Ax
Stop writing prompt glue.
A one-line signature declares what goes in and what comes out. Ax turns it into the prompt, the parser, the validators, and the retry loop — and hands back typed data your code can trust. The same programming model in TypeScript, Python, Java, C++, Go, and Rust.
npm install @ax-llm/axon npm
import { ai, ax } from "@ax-llm/ax";
const llm = ai({ name: "openai" });
const classify = ax(
"review:string -> sentiment:class \"positive, negative, neutral\""
);
const result = await classify.forward(llm, {
review: "This product is amazing!",
});
{
"sentiment": "positive"
}
Using Claude Code or Cursor? Point your coding agent at Ax — every language ships installable, versioned skills your agent can follow.
npx skills add https://ax-llm.github.io/ax/typescript/ --skill '*'
Why signatures?
Describe the input and output. Ax handles the model call.
The hero demo is the whole philosophy. A signature says what data the model receives and what typed data your app expects back. Ax uses that one contract to render prompts, call providers, parse output, validate constraints, retry with feedback, stream partial results, record traces, seed examples, and optimize behavior later.
The contract becomes the system boundary.
Instead of spreading prompt text, JSON parsing, retry logic, tool schemas, tracing, and eval metadata across your app, Ax hangs them from the signature.
Signature pipeline
One line becomes a running pipeline.
The signature you write is lowered into prompt rendering, streaming parsers, validators, retry feedback, and trace metadata — the same pipeline that produced the typed output above.
AxIR compiler
We didn't port Ax six times. We compiled it.
Ax is built around a portable intermediate representation. TypeScript is the reference runtime; the AxIR compiler lowers signatures, schemas, providers, generators, agents, flows, MCP, and optimizers into one shared semantic core — then emits native package surfaces for Python, Java, C++, Go, and Rust. Native names, native errors, native builders. Same behavior.
Signature syntax
const extract = ax(
"doc:string -> names:string[], dates:date[], amounts:number[]"
);
String signatures become AxIR contracts that the compiler can lower into prompts, schemas, validators, examples, traces, and typed outputs.
Field schema IR
const sig = f()
.input("document", f.string().min(10))
.output("summary", f.string().max(500))
.output("tags", f.string().array())
.build();
Fluent fields, media types, arrays, enums, constraints, and validators preserve field semantics across native packages.
Structured schema output
const sig = f()
.output(z.object({
summary: z.string(),
score: z.number().min(1).max(10),
}))
.build();
Schema-backed output keeps generated code aligned with the same parse, retry, docs, telemetry, and optimization contract.
Compiler pipeline
TypeScript reference runtime -> AxIR -> native APIs.
The package compiler emits language-shaped APIs instead of transpiling TypeScript. Each backend keeps native names, errors, builders, callbacks, transports, and runtime profiles while sharing the same Ax semantics.
Conformance gate
Capability manifests keep every backend honest.
Generated package examples, API metadata, capability manifests, and conformance fixtures are checked by axir verify. That is why the language switcher in the hero is a demo, not a promise — every backend earns its place in the matrix.
The ideas behind it
Built on DSPy, GEPA, RLM, and PEEK.
Ax is more than another LLM framework — it is where a serious research lineage ships. The typed signatures, validation with retry feedback, reflective optimization, runtime-backed agents, and context maps you just saw all come from these papers.
Declarative modules, signatures, examples, and self-improving LLM pipelines shape Ax's programming model.
Constraints, validation, and self-refinement inform Ax signatures, schemas, retry feedback, and output reliability.
Reflective prompt evolution and Pareto tradeoffs map directly to Ax optimization for generators, flows, and agents.
External runtime loops and recursive model calls inform AxAgent's runtime state, execution boundary, and small-context turns.
Persistent context maps and orientation caches are the product instinct behind Ax memory, skills, and context management.
Agents
Agents built for context, tools, memory, and code.
AxAgent is designed around DSPy, RLM, and PEEK ideas: typed signatures define the job, generated code and host runtimes hold durable state, context maps drive context management, and discovery-based tools load only the schemas needed for the next action. That keeps agents useful with small models and big ones, while built-in memory, skills, child agents, telemetry, and agent.optimize(...) make them practical to operate.
import { agent, ai, fn } from "@ax-llm/ax";
const llm = ai({ name: "openai" });
const research = agent({
name: "researcher",
signature: "question:string -> answer:string, sources:string[]",
functions: [
fn({
name: "search",
description: "Search internal docs",
parameters: "query:string -> results:string[]",
handler: searchDocs,
}),
],
contextFields: ["largeDocument"],
});
const result = await research.forward(llm, {
question: "What changed in the release?",
});
Discovery
Large tool catalogs stay out of the base prompt. The agent discovers groups and loads concrete schemas only when they matter.
Context maps
Runtime state, context maps, summaries, and checkpoints preserve orientation without replaying every token.
Memory + skills
Built-in memory, skills, MCP tools, and child agents become typed capabilities behind the same signature contract.
Optimization
agent.optimize(...) tunes instructions, examples, and agent behavior against evals, judges, and saved artifacts.
Function discovery
Agents navigate large tool catalogs without stuffing every schema into the prompt.
Function groups, child agents, MCP tools, memory, and runtime state are discovered and loaded as needed, which keeps even small models focused on the next useful action.
Context policy
State grows in the runtime instead of the prompt.
Context maps, summaries, checkpoint state, and runtime references keep long-running work usable without turning every turn into a full transcript replay.
Audio
Build text, voice, and realtime AI apps.
Ax treats audio as part of the same typed programming model: direct speech-to-text, direct text-to-speech, signature audio artifacts, conversational audio turns, realtime/native audio, and agent audio inputs.
Use the smallest audio surface that matches the job.
ai.transcribe(...)for batch speech-to-text.ai.speak(...)for batch text-to-speech.speech:audiofor typed programs that return synthesized audio artifacts..chat()audio config for conversational or realtime audio turns.- Agents transcribe audio inputs before planner, executor, and responder stages.
import { ai, ax } from "@ax-llm/ax";
const llm = ai({ name: "openai" });
const narrator = ax("article:string -> speech:audio, summary:string");
const result = await narrator.forward(
llm,
{ article },
{ speech: { speak: { voice: "alloy", format: "mp3" } } }
);
Transcribe and speak
Use direct batch APIs when the app needs speech-to-text, text-to-speech, transcripts, or reusable audio artifacts.
Conversational audio
Use provider audio chat and realtime configurations when voice belongs inside the model conversation.
Agent audio
Let agents accept recordings and return spoken outputs while their internal tool loops operate on stable text.
Optimization
Improve quality after it works.
GEPA, the Genetic-Pareto optimizer, tunes prompts, demos, flows, and agents against evals. Pareto frontiers make quality, latency, cost, and brevity tradeoffs explicit instead of hiding them behind one metric.
Pick the artifact that matches production reality.
Use optimized programs when quality matters, cheaper frontier points when cost dominates, and saved artifacts when the same tuned behavior needs to be deployed repeatedly.
The full surface
Everything you need to build useful LLM systems.
Every capability above hangs off the same signature contract. Start with a single typed generation call, then grow into tools, agents, voice, workflows, telemetry, optimization, and native packages without switching mental models.
Structured generation ax()
Declare typed inputs and outputs, then get parsed host values with streaming, validation, retries, and traces.
Signatures s() + f()
Use concise string signatures, fluent fields, media types, enums, arrays, constraints, and Standard Schema output.
Tools and MCP fn()
Expose typed host functions, MCP servers, runtimes, flows, and child agents as callable capabilities.
Agents agent()
Build agents with tool discovery, memory, skills, child agents, context policy, and persistent runtime state.
Audio speech:audio
Transcribe speech, synthesize speech, return typed audio artifacts, and use conversational or realtime audio turns.
Workflows flow()
Compose typed steps, branches, and parallel work into explicit LLM application flows.
Optimization optimize()
Improve prompts, demos, programs, flows, and agents against evals, judges, and production tradeoffs.
Providers ai()
Use OpenAI, Responses, Claude, Gemini, OpenAI-compatible gateways, local routers, embeddings, and model catalogs.
Telemetry traces
Inspect model calls, tool calls, usage, cost, latency, errors, optimizer metrics, and agent turns.
Native packages AxIR
Use the same Ax concepts from TypeScript, Python, Java, C++, Go, and Rust package surfaces.
Production-ready from day one
The operational pieces are built in, not bolted on.
Extensive test coverage, OpenTelemetry integration, cost tracking, provider routing, and enterprise-grade error handling all belong to one program story.
OpenTelemetry
Distributed traces span LLM calls, function invocations, MCP calls, and agent turns.
Detailed metrics
Track latency, tokens, errors, context windows, thinking budgets, and custom labels.
Streaming and validation
Structured outputs stream through parsers, assertions, retries, and correction feedback.
Cost tracking
Estimate provider costs per request and make optimization tradeoffs concrete.
Multi-language
One semantic core spans TypeScript, Python, Java, C++, Go, and Rust package shapes.
Enterprise controls
Rate limits, sampling, redaction, provider routing, and error handling fit production workflows.
Operate Ax systems
Observe the run from model call to optimized artifact.
Use the telemetry guide for the concrete spans, counters, histograms, and labels emitted by Ax programs.
Patterns
Declare capabilities, not prompts.
Signatures make common LLM tasks readable, testable, and portable. The contract is the unit Ax can validate, trace, optimize, and document.
Classification
Categorize text into predefined classes.
ax("text:string -> category:class \"spam, ham, promo\"")Extraction
Pull structured data from unstructured text.
ax("document:string -> names:string[], dates:date[]")Question answering
Answer questions with provided context.
ax("context:string, question:string -> answer:string")Multimodal
Process images and audio alongside text.
ax("photo:image, question:string -> answer:string")Validation
Auto-validate outputs with constraints.
ax("email:string, score:number -> valid:boolean")Streaming
Receive structured results as they generate.
ax("topic:string -> chunk:string")Translation
Translate between languages with typed IO.
ax("text:string, targetLanguage:string -> translation:string")Workflows
Return multiple typed outputs from one call.
ax("doc:string -> summary:string, keyPoints:string[]")MCP and tools
External servers become typed Ax functions.
Use MCP servers through AxMCPClient.toFunction() in ax() generation or pass MCP clients into agents for discovery-aware tool use.
LLM providers
Use any model.
Pick OpenAI, Claude, Gemini, a gateway, or a local OpenAI-compatible endpoint in ai(). Your signatures, tools, traces, and outputs stay the same.
const openai = ai({ name: "openai" });
const claude = ai({ name: "anthropic" });
const local = ai({
name: "openai",
config: { baseURL: "http://localhost:11434/v1" },
});
Need routing, embeddings, audio, or context caching? Read the LLM guide.
Also checkout
Connect AI agents to your database.
GraphJin compiles GraphQL to efficient SQL and doubles as an MCP server, giving Ax agents direct, governed access to application data.
import { AxMCPClient, AxMCPHTTPSSETransport, agent } from "@ax-llm/ax";
const transport = new AxMCPHTTPSSETransport(
"http://localhost:8080/api/v1/mcp"
);
const mcp = new AxMCPClient(transport);
await mcp.init();
const dataAnalyst = agent({
name: "data-analyst",
signature: "question:string -> answer:string",
functions: mcp.toFunction(),
});
Use GraphJin as an MCP tool inside Ax agents.
PostgreSQL, MySQL, SQLite, MongoDB, Oracle, MSSQL, and Snowflake can sit behind one data access layer for AI workflows.
Start now
Write your first signature today.
One line in, typed data out — on npm now, and in five more languages straight from this repo.
Building with an AI coding agent? Install the Ax skills and let it write Ax for you.