Why an Annotation Model?
Steps and workflows are the plumbing. Agents are the product β the thing you expose to HTTP endpoints, MCP servers, message listeners, and other agents. The annotation model gives you a programming model for declaring agents, naming them, describing them, handling their errors, and looking them up by name at runtime. If youβve used@Controller + @ControllerAdvice in Spring MVC, you already know how this works. @Agent is to AgentHandler what @Controller is to your handler methods.
AgentHandler<I, O>
The entry-point contract for agents. A@FunctionalInterface that takes context and input, returns output:
Workflow internally:
AgentHandler is pure Java β no Spring dependency. It lives in workflow-api so itβs portable across any runtime.
@Agent
Marks a class as a named agent and registers it as a Spring bean:@Agent is a Spring @Component stereotype β classes annotated with it are picked up by component scanning. The value() is the unique agent name used for registry lookup and protocol addressing.
@StepName and @Description
Two metadata annotations for steps and agents:Step.name() (which defaults to the class simple name) is used.
@Description provides a human-readable description for traces, visualization, and protocol tool listings. Can be placed on types or methods.
Both are pure Java annotations β no Spring dependency, no runtime cost.
StepNames utility
StepNames.resolve(step) reads the @StepName annotation; falls back to step.name() if absent:
AgentRegistry
An immutable map of name β handler. Manual construction β you decide what goes in:Map.copyOf()). Subsequent changes to the source map donβt affect it.
Auto-configuration that scans
@Agent beans and populates AgentRegistry automatically is planned but not yet implemented. For now, construct the registry manually or in a @Configuration class.Exception Handling
Exception handling mirrors Spring MVCβs@ExceptionHandler + @ControllerAdvice pattern exactly. Two scopes:
- Per-agent β
@ExceptionHandlermethods inside an@Agentclass handle that agentβs exceptions - Cross-cutting β
@ExceptionHandlermethods inside an@AgentAdviceclass handle exceptions from any agent
Per-agent handling
ReturnType method(ExceptionType ex)β just the exceptionReturnType method(ExceptionType ex, AgentContext ctx)β exception plus context
@ExceptionHandler(SomeException.class) or inferred from the methodβs first parameter.
Cross-cutting handling
@AgentAdvice is a Spring @Component β picked up by component scanning, applies to all agents.
Using the resolver
AgentExceptionHandlerResolver ties it together. Pass it the @AgentAdvice instances at construction, then call resolve() on exception:
Spring Boot Wiring
In a Spring Boot application, wire the registry and resolver as beans in a@Configuration class:
@Agent and @AgentAdvice beans by type. The registry and resolver become injectable anywhere you need them β HTTP controllers, message listeners, MCP tool handlers.
Disambiguating steps with @Qualifier
When two steps share the sameStep<I, O> signature, Spring canβt tell them apart by type alone. Use @Qualifier on both the bean definition and the injection point:
@StepName gives you a stable checkpoint key, @Qualifier gives you injection disambiguation.
Injecting Durability with withExecutor()
By default,Workflow.run() creates a WorkflowExecutor with LocalStepRunner (in-process, no persistence). Use withExecutor() to inject a configured executor with a durable StepRunner:
WorkflowBuilder and SupervisorBuilder. See Durability for the full graduation path from LocalStepRunner β CheckpointingStepRunner β TemporalStepRunner.
Full Example
A complete PR review agent using all 5 annotations:Annotation Summary
| Annotation | Target | Module | Purpose |
|---|---|---|---|
@StepName | Type | workflow-api | Stable checkpoint/Temporal key |
@Description | Type, Method | workflow-api | Human-readable description |
@ExceptionHandler | Method | workflow-api | Marks exception handler methods |
@Agent | Type | workflow-flows | Spring stereotype for AgentHandler beans |
@AgentAdvice | Type | workflow-flows | Spring stereotype for cross-cutting error handlers |
Whatβs Next
Durability
Crash recovery with CheckpointingStepRunner and Temporal integration
DSL Primitives
Branch, loop, parallel, decision, gate, supervisor β 10+ composable patterns
API Reference
Step, AgentContext, Gate, WorkflowGraph, StepRunner
Getting Started
Steps, context, your first workflow