-
Notifications
You must be signed in to change notification settings - Fork 2
Chain Format
Chains are YAML files stored in the chains/ directory. This page covers every field available.
name: my-chain
steps:
- id: step1
prompt: "Do something"
output_var: result
output: resultname: my-chain # Required. kebab-case identifier.
description: "What this does" # Optional. Shown in list_chains.
version: "1.0" # Optional. Semantic version.
inputs: # Optional. Chain-level parameters.
- name: topic # Input variable name.
description: "The topic" # Optional. Shown to users.
optional: false # Default: false. If true, can be omitted.
steps: # Required. At least 1 step.
- id: step_one # Required. Unique ID (kebab-case).
type: agent # Optional. Default: "agent".
label: "Human-readable name" # Optional. Shown in SSE events.
model: claude-sonnet-4-6 # Optional. Override default model.
prompt: "..." # Required. Supports {variables}.
output_var: result # Required. Variable name for output.
depends_on: [other_step] # Optional. Steps that must complete first.
tools: [Read, Write, Bash] # Optional. Claude tools this step can use.
cwd: "/path/to/dir" # Optional. Working directory for Claude.
condition: '{var} == "value"' # Optional. Skip step if condition is false.
timeout_ms: 300000 # Optional. Per-step timeout (default: 5min).
pre_tools: [...] # Optional. Data injection before execution.
# Each pre-tool supports on_error: "inject" | "skip" | "fail"
retry: { ... } # Optional. Retry configuration.
fallback_models: [...] # Optional. Models to try if primary fails.
cache: { ... } # Optional. Result caching.
guardrails: [...] # Optional. Output validation rules.
context_strategy: { ... } # Optional. How to compress dependencies.
early_exit_if: '...' # Optional. Stop chain if condition is true.
output: result # Required. output_var to return as final result.Variables are referenced with {name} syntax in prompts and pre-tool configs:
| Variable | Source | Example |
|---|---|---|
{input.topic} |
Chain input | User-provided value |
{step_output} |
Step output_var | Output from a previous step |
{search_results} |
Pre-tool inject_as | Data injected before the step |
{item} |
Loop iteration | Current item in a loop step |
Variables resolve at execution time. Undefined variables remain as literal {name} in the prompt.
Steps without depends_on run in parallel (same wave). Steps with depends_on wait for their dependencies.
steps:
# Wave 1 (parallel)
- id: a
prompt: "..."
output_var: out_a
- id: b
prompt: "..."
output_var: out_b
# Wave 2 (waits for a and b)
- id: c
depends_on: [a, b]
prompt: "Combine {out_a} and {out_b}"
output_var: out_cCircular dependencies are detected at load time and rejected with a clear error message.
retry:
max: 3 # Max attempts (default: 1 = no retry)
delay_ms: 2000 # Initial delay between retries
backoff: 2 # Multiply delay by this factor each retry
fallback_models: # Try these models if the primary fails
- claude-opus-4-6
- claude-sonnet-4-6Retry order: attempt with primary model → retry with primary → fallback model 1 → fallback model 2.
guardrails:
- type: min_length
value: 500
- type: max_length
value: 5000
- type: must_contain
value: "## Summary"
- type: must_not_contain
value: "I don't know"
- type: regex_match
value: "^#{1,3} "
- type: json_valid
# Legacy fields (still supported)
output_must_contain: ["## Summary"]
output_must_not_contain: ["TODO"]
output_max_length: 5000
output_schema: json # "json", "markdown", or "text"If guardrails fail and retry is configured, the step re-runs automatically.
cache:
enabled: true
ttl_minutes: 60 # Cache expires after 60 minutesCache key = hash of (step ID + resolved prompt + model). Identical inputs skip the LLM entirely.
Control how dependency outputs are compressed before injection:
context_strategy:
research: "full" # Pass full output (default)
raw_data: "summarize" # LLM-summarize before injection
big_output: "truncate:2000" # Truncate to 2000 characterscondition: '{codebase_type} == "frontend"'Supported operators: ==, !=, contains, >, <.
If condition is false, the step is skipped and its output_var is set to empty string.
early_exit_if: '{answer_found} == "true"'If the condition evaluates to true after this step completes, remaining waves are skipped.
- Step Types — Detailed reference for each step type
- Pre-Tools — Data injection before steps
- Token Optimization — Best practices for minimizing cost