State Management
Workflow state is stored as plain instance properties on the workflow class. Properties are automatically checkpointed and restored across transitions.
Defining State
No decorator needed — just declare properties on your workflow class:
export class MyWorkflow extends BaseWorkflow {
counter: number = 0;
llmResult?: ClaudeGenerateTextResult;
items: string[] = [];
confirmedConcept?: string | null;
}Writing State
Assign values directly in transition methods:
@Transition({ from: 'ready', to: 'processed' })
async process() {
const result = await this.claudeGenerateText.call({ ... });
this.llmResult = result.data;
this.counter++;
this.items.push('new item');
}Reading State
Access properties directly in any transition or guard method:
@Transition({ from: 'processed', to: 'done' })
async display() {
await this.createChatMessage.call({
role: 'assistant',
content: `Processed ${this.counter} items. Result: ${this.llmResult?.content}`,
});
}
hasToolCalls() {
return this.llmResult?.stop_reason === 'tool_use';
}Persistence Across Pauses
State survives when a workflow pauses at a wait: true transition and resumes later:
@Initial({ to: 'waiting' })
async setup() {
this.counter = 42; // Set before pause
}
@Transition({ from: 'waiting', to: 'done', wait: true })
async onResume() {
// this.counter is still 42
}Accessing Workflow Args
Input arguments are available via this.ctx.args:
@Workflow({
schema: z.object({ value: z.number().default(150) }),
})
export class MyWorkflow extends BaseWorkflow {
@Initial({ to: 'ready' })
async setup() {
const args = this.ctx.args as { value: number };
console.log(args.value); // 150
}
}Or receive them directly as a parameter in the @Initial method:
@Initial({ to: 'ready' })
async setup(args: { value: number }) {
console.log(args.value); // 150
}Tool State
Tool properties are also automatically persisted across invocations:
@Tool({ uiConfig: { description: 'Counter tool.' } })
export class CounterTool extends BaseTool {
count: number = 0;
async call(): Promise<ToolResult<number>> {
this.count++;
return { data: this.count };
}
}The counter persists even if the workflow pauses and resumes between calls:
// Before pause: count = 1, 2, 3
// After resume: count = 4, 5, 6Helper Methods
Use regular private methods for reusable logic — no special decorator needed:
export class MyWorkflow extends BaseWorkflow {
message?: string;
@Final({ from: 'data_created' })
async showResults() {
await this.createChatMessage.call({
role: 'assistant',
content: this.formatMessage(this.message!),
});
}
private formatMessage(text: string): string {
return text.toUpperCase();
}
}Registry References
- workflow-state-example-workflow — Stores state in instance properties, accesses in final transition, uses helper methods
- custom-tool-example-module — Stateful CounterTool that persists state across workflow pause/resume
- accessing-tool-results-example-workflow — Storing and accessing tool results via workflow state