Chain & ChainStep Schema
iris intermediate 5 min read
ELI5
A chain is like a recipe in a cookbook. Each step tells a specific sprite (chef) what to do (action) using ingredients from previous steps (input_map). After each step, you write down what was produced (output_map). Gate checkpoints are like food safety inspectors who can stop the entire kitchen if something looks wrong.
Technical Deep Dive
Chain JSON Schema
Chain is the third top-level type in iris.schema.json (identified by steps).
Required Fields
| Field | Type | Constraints |
|---|---|---|
id | UUID | Server-generated |
name | string | Human-readable chain name |
steps | ChainStep[] | minItems: 1. Ordered execution sequence |
gates | Gate[] | Veto-capable checkpoints |
timeout | Duration | Pattern: ^([1-9]\d*)(ms|s|m|h)$. Examples: 30s, 5m, 1h |
ChainStep Structure
| Field | Type | Description |
|---|---|---|
order | integer | Zero-based execution order (0, 1, 2…) |
sprite_id | UUID | Which sprite executes this step |
action | string | Capability name to invoke (must match a capability declared by the sprite) |
input_map | object | Maps parameters to source expressions using JSONPath-like notation (e.g., $steps[0].output.code, $input.user_prompt) |
output_map | object | Extraction expressions defining what to capture from the step’s raw response |
Gate Structure
| Field | Type | Description |
|---|---|---|
position | enum | before (before first step), after (after last step), on_error (triggered by step failure) |
sprite_id | UUID | The gate authority sprite that evaluates this gate |
condition | string | Expression up to 2,048 chars (e.g., output.confidence >= 0.85) |
veto_message | string | Human-readable message logged when gate vetoes (up to 1,024 chars) |
Class Diagram
classDiagram class Chain { +UUID id +string name +ChainStep[] steps +Gate[] gates +Duration timeout +validate_structure() boolean } class ChainStep { +integer order +UUID sprite_id +string action +object input_map +object output_map } class Gate { +GatePosition position +UUID sprite_id +string condition +string veto_message } class ChainExecutionResult { +UUID execution_id +ChainStatus status +datetime started_at +datetime completed_at +integer duration_ms +StepExecution[] steps +GateEvaluation[] gates } Chain --> ChainStep : contains Chain --> Gate : contains ChainExecutionResult --> StepExecution : contains ChainExecutionResult --> GateEvaluation : containsExecution Sequence Diagram
sequenceDiagram autonumber participant Client participant API as iris-service participant Executor as ChainExecutor participant Gate as GateEngine participant Sprite as Sprite (placeholder)
Client->>API: POST /v1/chains/execute API->>Executor: execute_chain(council_id, chain, input) Executor->>Gate: evaluate before-gates alt Any before-gate vetoes Gate-->>Executor: decision: veto Executor-->>API: status: vetoed API-->>Client: 409 GATE_VETO else All before-gates allow Gate-->>Executor: decision: allow loop For each step in order Executor->>Sprite: invoke sprite action Sprite-->>Executor: output Executor->>Gate: evaluate after-gate (if any) alt After-gate vetoes Gate-->>Executor: decision: veto Executor-->>API: status: vetoed API-->>Client: 409 GATE_VETO end end Executor-->>API: status: completed API-->>Client: 200 ChainExecutionResult endData Flow Between Steps
flowchart LR A["$input.user_prompt"] -->|input_map| B["Step 0: SOL-FORGE\ngenerate_code"] B -->|output_map| C["$steps[0].output.code"] C -->|input_map| D["Step 1: BECK-02\nreview_pull_request"] D -->|output_map| E["$steps[1].output.approved"] E -->|input_map| F["Step 2: MARTINEZ-04\ndeploy"] F -->|output_map| G["$steps[2].output.url"]Gate Position Lifecycle
stateDiagram-v2 [*] --> BeforeGates: Chain starts BeforeGates --> StepExecution: All gates allow BeforeGates --> Vetoed: Gate vetoes StepExecution --> AfterGates: Step succeeds StepExecution --> OnErrorGates: Step fails AfterGates --> NextStep: Gate allows AfterGates --> Vetoed: Gate vetoes OnErrorGates --> Vetoed: Gate vetoes OnErrorGates --> Continue: Gate allows NextStep --> StepExecution: More steps NextStep --> Completed: All steps done Continue --> StepExecution: Resume Vetoed --> [*] Completed --> [*]Key Terms
- ChainStep → A single ordered action invoking a sprite’s capability with mapped inputs/outputs
- input_map → JSONPath-like expressions routing data from previous steps or initial input into the current step
- output_map → Extraction expressions defining what to capture from a step’s response for downstream use
- Gate position → When a gate is evaluated:
before(pre-execution),after(post-step),on_error(failure handler) - Veto message → Human-readable explanation logged when a gate halts execution
- Duration → ISO 8601-like shorthand:
30s,5m,1h. Parsed by_parse_timeout()in the executor.
Q&A
Q: Can a chain have zero steps?
A: No. steps requires minItems: 1. A chain with no steps would have nothing to execute.
Q: What happens if a step’s sprite doesn’t have the requested capability?
A: The step fails with status="failed" and the chain either continues (if no on_error gate vetoes) or returns status="failed".
Q: How does $steps[0].output.code work?
A: input_map and output_map use a JSONPath-like expression language. $steps[n].output.field references the output of step n. $input.field references the original chain execution input.
Q: Can gates be evaluated between every step, or only at the chain level?
A: Gates defined at the chain level can be before (before all steps), after (after all steps), or on_error (on any failure). Per-step gates (gates_before/gates_after) are supported in the SDK’s ChainStep model but the service-level gates are chain-scoped.
Q: What happens on timeout?
A: The _parse_timeout() method converts the duration string to seconds, but timeout enforcement is currently a placeholder in the executor. Full timeout enforcement will abort long-running chains and return status="failed" with a timeout error.
Examples
A chain is like an assembly line building a custom bicycle:
- Step 0 (Frame builder) = “Take the customer’s measurements (
$input.measurements) and weld a frame” - Step 1 (Painter) = “Take the frame (
$steps[0].output.frame) and apply the chosen colour” - Step 2 (Wheel builder) = “Build wheels to match the frame size”
- Step 3 (Assembler) = “Assemble everything into a complete bike”
- Gate (before) = “Quality inspector checks raw materials are certified”
- Gate (after) = “Safety inspector test-rides the bike before delivery”
- Gate (on_error) = “If welding fails, scrap specialist decides whether to retry or refund”
neighbors on the map
- Council Orchestration Model creating a new council
- Gate Engine & Veto Mechanics designing gate conditions