Step<I, O>
The atomic unit of a workflow.NodeType.AGENT cost tracking:
Built-in Step Types
| Type | Factory | What it wraps |
|---|---|---|
| Lambda | Step.named("n", (ctx, in) -> ...) | Any function |
| Chat | ChatClientStep.of(chat, "template {input}") | Single Spring AI call |
| Claude | ClaudeStep.of("template").workingDirectory(path) | Full Claude CLI session |
| A2A | A2AStep.of(url) | Remote agent via Agent-to-Agent protocol |
| Function | Steps.of(fn) | Pure deterministic function |
| Retry | Steps.retrying(3, step) | Retry wrapper |
| Output ref | Steps.outputOf("step-name") | Read prior step result from context |
| Terminate | Steps.terminate(status, msg) | Early workflow exit |
ClaudeStep options
Workflow Builder
Gate
GateDecision: PASS, FAIL, ESCALATE, TIMEOUT
Implementations
| Gate | Description |
|---|---|
JudgeGate(jury, threshold) | Automated — passes when agent-judge score >= threshold |
TieredGate(jury, high, low) | >= high → PASS, >= low → ESCALATE, < low → FAIL |
HumanGate | HITL — waits for external signal with durable timeout |
Gate builder
Verdict written to AgentContext.JUDGE_VERDICT. Reflector transforms verdict into constructive feedback for the retry step.
AgentContext
Immutable, threaded through every step. Copy-on-write viamutate().
Well-known Keys
| Key | Type | Description |
|---|---|---|
WORKFLOW_RUN_ID | String | Unique execution ID |
WORKFLOW_NAME | String | Workflow name |
CURRENT_STEP | String | Active step name |
ITERATION_COUNT | Integer | Loop counter |
ACCUMULATED_COST | Double | USD spend so far |
ACCUMULATED_TOKENS | Long | Total tokens |
JUDGE_VERDICT | Verdict | Gate failure verdict |
JUDGE_REFLECTION | String | Reflector feedback text |
ContextKey<T> implements Bloch’s Typesafe Heterogeneous Container (Effective Java Item 33).
RunOptions
WorkflowGraph (IR)
Pure data structure — no execution logic, no Spring AI imports.Node Types (sealed)
| Node | Description |
|---|---|
StepNode | Regular step execution (AGENT or DETERMINISTIC) |
GatewayNode | Predicate branch |
DecisionNode | LLM routing |
GateNode | Quality gate with reflector and retry |
LoopEntryNode | While-do entry |
LoopCheckNode | Do-while condition |
LoopExitNode | Loop resume point |
ForkNode | Parallel split |
JoinNode | Convergence |
Edge Conditions (sealed)
| Condition | From |
|---|---|
Unconditional | Sequential |
BooleanGuard(true/false) | GatewayNode |
OptionMatch("name") | DecisionNode |
GateMatch(PASS/FAIL/ESCALATE) | GateNode |
BranchIndex(i) | ForkNode |
ErrorMatch(ExType) | Error edges |
LoopContinue / LoopExit | Loop nodes |
BackEdge(condition) | backTo() cyclic edges |
Type Checking
WorkflowGraphAssert.assertTypeCompatible(graph) walks a compiled graph and checks that each step’s declared output type is assignable to the next step’s declared input type. Catches ClassCastException-style bugs at test time.
Opt-in: Steps that override inputType() / outputType() participate. Lambda steps and Step.named() return Object.class by default and are silently skipped — no false positives.
StepRunner
The substrate swap seam. Same workflow code, different durability:| Runner | What it adds | Status |
|---|---|---|
LocalStepRunner | Direct in-process execution, zero overhead | Available |
CheckpointingStepRunner | JDBC crash recovery via workflow-batch | Available |
TemporalStepRunner | Distributed durable execution via workflow-temporal | Available |
@Bean, not the workflow. See Durability for setup and crash-recovery examples.
TraceRecorder
Records every step transition:TraceRecorder.noop() is the default — zero overhead unless opted in. Trace data feeds Markov analysis, run diagnosis, and replay.