CRUMB a card from devarno-cloud

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

FieldTypeConstraints
idUUIDServer-generated
namestringHuman-readable chain name
stepsChainStep[]minItems: 1. Ordered execution sequence
gatesGate[]Veto-capable checkpoints
timeoutDurationPattern: ^([1-9]\d*)(ms|s|m|h)$. Examples: 30s, 5m, 1h

ChainStep Structure

FieldTypeDescription
orderintegerZero-based execution order (0, 1, 2…)
sprite_idUUIDWhich sprite executes this step
actionstringCapability name to invoke (must match a capability declared by the sprite)
input_mapobjectMaps parameters to source expressions using JSONPath-like notation (e.g., $steps[0].output.code, $input.user_prompt)
output_mapobjectExtraction expressions defining what to capture from the step’s raw response

Gate Structure

FieldTypeDescription
positionenumbefore (before first step), after (after last step), on_error (triggered by step failure)
sprite_idUUIDThe gate authority sprite that evaluates this gate
conditionstringExpression up to 2,048 chars (e.g., output.confidence >= 0.85)
veto_messagestringHuman-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 : contains

Execution 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
end

Data 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