-
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: result
name: 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_c
Circular 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-6
Retry 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 minutes
Cache 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 characters
condition: '{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