Your First AXON Program
Let’s build a complete AXON program that analyzes documents. You’ll learn the core concepts while creating something functional.
This guide assumes you’ve completed the installation and have at least one API key configured.
Step 1: Create Your First .axon File
Create a file called analyzer.axon:
persona Analyst {
domain: ["analysis", "research"]
tone: professional
confidence_threshold: 0.8
}
flow AnalyzeText(input: Document) -> Summary {
step Extract {
given: input
ask: "What are the key points in this text?"
output: KeyPoints
}
step Summarize {
given: Extract.output
ask: "Create a concise summary"
output: Summary
}
}
Understand the persona block
The persona defines the cognitive identity of your AI: persona Analyst {
domain: ["analysis", "research"]
tone: professional
confidence_threshold: 0.8
}
domain: Areas of expertise
tone: Communication style
confidence_threshold: Minimum confidence level (0-1)
Understand the flow block
The flow defines a pipeline of cognitive steps: flow AnalyzeText(input: Document) -> Summary {
step Extract { ... }
step Summarize { ... }
}
Flows:
Take typed inputs (input: Document)
Return typed outputs (-> Summary)
Execute steps sequentially
Pass data between steps
Step 2: Validate Your Syntax
Before running, check that your syntax is correct:
✓ Lexer: 23 tokens
✓ Parser: AST built
✓ Type Checker: No errors
analyzer.axon is valid.
Always use axon check during development to catch errors early. It runs the lexer, parser, and type checker without executing anything.
Step 3: Compile to IR
Compile your AXON program to Intermediate Representation (IR):
axon compile analyzer.axon
This creates analyzer.ir.json - a JSON representation of your program that any backend can execute.
The IR is a JSON structure that captures the semantic meaning of your program: {
"type" : "program" ,
"personas" : [
{
"name" : "Analyst" ,
"domain" : [ "analysis" , "research" ],
"tone" : "professional" ,
"confidence_threshold" : 0.8
}
],
"flows" : [
{
"name" : "AnalyzeText" ,
"parameters" : [{ "name" : "input" , "type" : "Document" }],
"return_type" : "Summary" ,
"steps" : [ ... ]
}
]
}
Step 4: Execute Your Program
Run your AXON program with a specific backend:
axon run analyzer.axon --backend anthropic
Anthropic (Claude)
OpenAI (GPT)
Gemini
Ollama (Local)
axon run analyzer.axon --backend anthropic
Requires ANTHROPIC_API_KEY environment variable. axon run analyzer.axon --backend openai
Requires OPENAI_API_KEY environment variable. axon run analyzer.axon --backend gemini
Requires API_KEY_GEMINI environment variable. axon run analyzer.axon --backend ollama
Requires Ollama running locally with a model pulled.
Step 5: Add Constraints with Anchors
Now let’s add hard constraints that can never be violated:
persona Analyst {
domain: ["analysis", "research"]
tone: professional
confidence_threshold: 0.8
}
anchor NoSpeculation {
require: factual_claims
confidence_floor: 0.75
unknown_response: "Insufficient information to answer"
on_violation: raise AnchorBreachError
}
flow AnalyzeText(input: Document) -> Summary {
step Extract {
given: input
ask: "What are the key points in this text?"
output: KeyPoints
}
step Summarize {
given: Extract.output
ask: "Create a concise summary"
validate: NoSpeculation
output: Summary
}
}
Anchors are hard constraints . If violated, AXON’s self-healing runtime will retry with failure context. If max attempts are exceeded, it raises AnchorBreachError.
Step 6: Add Self-Healing with Refine
Make your program automatically retry and self-correct:
flow AnalyzeText(input: Document) -> Summary {
step Extract {
given: input
ask: "What are the key points in this text?"
output: KeyPoints
}
step Summarize {
given: Extract.output
ask: "Create a concise summary"
validate: NoSpeculation
if confidence < 0.8 -> refine(max_attempts: 2)
output: Summary
}
}
The refine directive:
Automatically retries when confidence is too low
Injects failure context back to the LLM
Respects max attempts to prevent infinite loops
Creates a closed feedback loop for self-healing
Step 7: Enable Execution Tracing
Get detailed insights into what happened during execution:
axon run analyzer.axon --backend anthropic --trace
This saves a trace to analyzer.trace.json. View it with:
axon trace analyzer.trace.json
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
AXON Execution Trace
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[FLOW_START] AnalyzeText
timestamp: 2026-03-06T14:23:01.234Z
input: {"text": "Sample document..."}
[STEP_START] Extract
timestamp: 2026-03-06T14:23:01.235Z
[MODEL_CALL] anthropic/claude-3-5-sonnet
timestamp: 2026-03-06T14:23:01.240Z
duration: 1.23s
[STEP_COMPLETE] Extract
output: {"key_points": [...]}
confidence: 0.92
[STEP_START] Summarize
timestamp: 2026-03-06T14:23:02.470Z
[VALIDATION_SUCCESS] NoSpeculation
timestamp: 2026-03-06T14:23:03.120Z
[STEP_COMPLETE] Summarize
output: {"summary": "..."}
confidence: 0.89
[FLOW_COMPLETE] AnalyzeText
timestamp: 2026-03-06T14:23:03.125Z
duration: 1.89s
status: success
Advanced Example: Contract Analyzer
Here’s a production-ready example from the AXON repository:
persona LegalExpert {
domain: ["contract law", "IP", "corporate"]
tone: precise
confidence_threshold: 0.85
cite_sources: true
}
context LegalReview {
memory: session
language: "en"
depth: exhaustive
max_tokens: 4096
temperature: 0.3
}
anchor NoHallucination {
require: source_citation
confidence_floor: 0.75
unknown_response: "I don't have sufficient information."
on_violation: raise AnchorBreachError
}
type RiskScore(0.0..1.0)
type Party {
name: FactualClaim,
role: FactualClaim
}
type Risk {
score: RiskScore,
mitigation: Opinion?
}
tool WebSearch {
provider: brave
max_results: 5
timeout: 10s
}
flow AnalyzeContract(doc: Document) -> ContractAnalysis {
step Extract {
given: doc
ask: "Extract all parties, obligations, dates, and penalties"
output: EntityMap
}
step Assess {
given: Extract.output
ask: "Identify ambiguous or risky clauses"
output: RiskAnalysis
}
}
run AnalyzeContract(myContract)
as LegalExpert
within LegalReview
constrained_by [NoHallucination]
on_failure: retry(backoff: exponential)
output_to: "report.json"
effort: high
This example demonstrates:
Personas Specialized domain expertise with citation requirements
Context Session configuration for consistent behavior
Anchors Hard constraints preventing hallucination
Types Custom semantic types with ranges and optional fields
Tools External capabilities with timeout configuration
Flows Multi-step pipelines with data passing
Using the Python API
You can also use AXON programmatically:
from axon import Lexer, Parser, TypeChecker, IRGenerator, get_backend
# Read source
source = open ( "analyzer.axon" ).read()
# Compile
tokens = Lexer(source).tokenize()
ast = Parser(tokens).parse()
errors = TypeChecker(ast).check()
if errors:
for error in errors:
print ( f "Error: { error } " )
exit ( 1 )
# Generate IR and execute
ir = IRGenerator().generate(ast)
backend = get_backend( "anthropic" )
result = backend.compile(ir)
print ( f "Result: { result } " )
Common CLI Commands
Here’s a quick reference of useful commands:
# Validate syntax
axon check program.axon
# Compile to IR
axon compile program.axon -b openai
# Execute with tracing
axon run program.axon --backend anthropic --trace
# View trace
axon trace program.trace.json
# Check version
axon version
Error Hierarchy
AXON has a six-level error hierarchy:
Level Error When it occurs 1 ValidationErrorOutput type mismatch 2 ConfidenceErrorConfidence below floor 3 AnchorBreachErrorAnchor constraint violated 4 RefineExhaustedMax retry attempts exceeded 5 RuntimeErrorModel call failed 6 TimeoutErrorExecution time limit exceeded
Levels 1-3 trigger automatic self-healing via the RetryEngine. Level 4 means healing failed after max attempts.
Next Steps
Language Reference Deep dive into AXON’s syntax and semantics
Type System Learn about epistemic types and subsumption
Examples Real-world AXON programs
CLI Reference Complete CLI documentation