Workflow Capability Contract
Status: Active contract for the current workflow subsystem.
Scope: Defines additive workflow subsystem boundaries, canonical IR/runtime capabilities, deterministic invariants, validation guarantees, replay/checkpoint behavior, YAML execution, and binding exposure expectations.
1) Non-Breaking Scope
- The workflow subsystem is additive and does not replace existing
SimpleAgentsClientcompletion/streaming APIs. - Existing crates and bindings continue to function without workflow adoption.
- Workflow features are introduced via new crate boundaries and typed interfaces.
2) Workspace Crate Boundaries
- New crate:
crates/simple-agents-workflow - In-scope modules:
ir- canonical workflow IR typesvalidation- normalization and structural diagnosticsruntime- deterministic execution enginescheduler- bounded concurrency primitivesstate- hierarchical scoped state + capability checkstrace- stable trace event schemarecorder- in-memory trace recorderreplay- structural replay validation + replay cache policycheckpoint- checkpoint store abstractions and filesystem backenddebug- timeline/retry/replay inspection helpersobservability- tracing + metrics adaptersvisualize- Mermaid workflow rendering
yaml_runner- YAML workflow execution with step timing metrics- Integration boundary:
- LLM execution is delegated through
LlmExecutor; production adapter isimpl LlmExecutor for SimpleAgentsClient. - Tool execution is host-injected via
ToolExecutor.
- LLM execution is delegated through
3) Canonical IR Contract
Canonical node taxonomy currently supported:
startllmtoolconditionloopparallelmergemapreducesubgraphbatchfilterdebouncethrottleretry_compensatehuman_in_the_loopcache_readcache_writeevent_triggerroutertransformend
IR guarantees:
- Version is
v0(WORKFLOW_IR_V0) for canonical IR fixtures and validation. - Workflows normalize deterministically (trimmed strings, node sorting by id).
- Nodes have stable
idand typed node payload (NodeKind).
Reference: crates/simple-agents-workflow/src/ir.rs.
4) Validation and Diagnostic Contract
Validation entrypoint:
validate_and_normalize(&WorkflowDefinition) -> Result<WorkflowDefinition, ValidationErrors>
Guaranteed structural checks:
- unsupported IR version
- empty workflow name or empty workflow
- empty/duplicate node ids
- missing start / multiple start
- missing end
- unknown edge targets
- unreachable nodes
- no path from start to any end
- required field emptiness per node type
Diagnostics are typed with stable codes (DiagnosticCode) and severity (Severity::Error).
Reference: crates/simple-agents-workflow/src/validation.rs.
5) Deterministic Execution Invariants
Runtime invariants:
- deterministic normalized workflow is used for execution
- single active node cursor, step-indexed event stream
- bounded execution via
max_steps - cooperative cancellation checks before step and between retry attempts
- runtime-owned node policies for retries/timeouts (
NodeExecutionPolicy) - trace sequence is monotonic and deterministic within one run
- per-step execution records are stable (
NodeExecution+NodeExecutionData)
Reference: crates/simple-agents-workflow/src/runtime.rs.
6) Trace and Replay Contract
Trace schema types:
WorkflowTraceWorkflowTraceMetadataTraceEventwith monotonicseqTraceEventKind:node_enter,node_exit,node_error,terminalTraceTerminalStatus:completed | failed
Replay contract:
replay_trace(&WorkflowTrace) -> Result<ReplayReport, ReplayError>validates:- monotonic sequence
- node lifecycle consistency (enter/exit/error pairing)
- terminal event presence
- no unclosed node lifecycle at end
Replay cache policy surface:
ReplayCachePolicy::AlwaysReplayCachePolicy::RefreshReplayCachePolicy::Mixed
Checkpoint and resume surface:
WorkflowRuntime::execute_resume_from_failureFilesystemCheckpointStoreandCheckpointStoretrait
Workflow YAML streaming/healing surface:
llm_call.streamenables node-level LLM delta streamingllm_call.healenables healing mode for structured node output- when
stream=trueandheal=true, streaming is disabled for that node with explanatory event text node_llm_input_resolvedemits per-node resolved LLM input telemetry, including:- resolved prompt text and original template
- model/schema and effective stream/heal flags
- template binding provenance (
expression,source_path,resolved,missing)
Workflow YAML memory interpolation surface:
- Prompt interpolation supports:
{{ input.email_text }}{{ nodes.<node_id>.output.<field> }}{{ globals.<key> }}
- Node config supports global memory writes:
set_globalsfor direct key assignment from context pathsupdate_globalswith mutable ops:setappendincrementmerge
References:
crates/simple-agents-workflow/src/trace.rscrates/simple-agents-workflow/src/recorder.rscrates/simple-agents-workflow/src/replay.rs
7) Capability Contract (Existing vs New)
| Capability | Existing core/runtime | New workflow subsystem |
|---|---|---|
| Provider execution | SimpleAgentsClient::complete and routing stack | delegated via LlmExecutor adapter to core |
| Tool execution | app/tool-specific handling outside workflow engine | host-injected ToolExecutor |
| Validation diagnostics | request validation in existing types | workflow graph validation + diagnostic codes |
| Deterministic run model | not workflow-graph aware | step-based deterministic workflow runtime |
| Trace/replay | provider metrics/logging only | typed trace schema + recorder + replay validator |
| Scope boundaries | request-level | runtime scoped state with capability checks |
| YAML workflow execution | not available | run_workflow_yaml_file_with_client / run_workflow_yaml_with_client (email wrappers remain) |
| Workflow live events | not available | run_email_workflow_yaml_with_client_and_custom_worker_and_events + YamlWorkflowEventSink |
| YAML workflow verifier | not available | verify_yaml_workflow diagnostics before execution |
| YAML prompt memory | not available | set_globals + update_globals + {{ globals.* }} interpolation |
| Visualization | not available | workflow_to_mermaid |
8) Cross-Language Exposure Contract
Rust remains source of truth. Language bindings should wrap Rust behavior, not re-implement core logic.
- FFI:
sa_run_workflow_yamlreturns JSON output from Rust runner (sa_run_email_workflow_yamlremains as wrapper). - Go:
Client.RunWorkflowYAML(...)delegates through FFI (RunEmailWorkflowYAML(...)remains as wrapper). - Node:
Client.runWorkflowYaml(...)delegates through Rust binding (runEmailWorkflowYaml(...)remains as wrapper). - Python:
Client.run_workflow_yaml(...)delegates through Rust binding (run_email_workflow_yaml(...)remains as wrapper). - Python streaming:
Client.run_workflow_yaml_stream(...)delegates through Rust event stream + callback sink.
All binding outputs include terminal output, trace, per-step timing, and total runtime.
9) Acceptance Mapping
- Crate boundaries: complete
- Canonical IR + advanced nodes: complete
- Validation/lint pass: complete
- Deterministic invariants + trace schema: complete
- Replay/checkpoint controls: complete
- YAML runner + timing outputs: complete
- Cross-language YAML execution exposure: complete
- Published capability contract: complete (this document)