WorkflowContext
The WorkflowContext interface is injected into vibeWorkflow functions. It provides methods for multi-stage automation pipelines with cumulative state tracking across stages.
Interface
Section titled “Interface”interface WorkflowContext { stage(name: string, opts: RunAgentOptions): AgentExecution; files: WorkflowFileAccessor; tools: WorkflowToolAccessor; timeline: WorkflowTimelineAccessor; until( predicate: (latest: RunResult) => boolean | Promise<boolean>, body: () => Promise<RunResult>, opts?: { maxIterations?: number } ): Promise<RunResult[]>; defaults: { workspace?: string; model?: string; };}Properties
Section titled “Properties”stage(name: string, opts: RunAgentOptions): AgentExecutionExecute one stage of the workflow. Returns AgentExecution for this stage and accumulates state into the workflow.
Parameters:
name- Stage name (appears in logs and reports)opts- Agent execution configuration
Returns:
AgentExecution- Thenable execution handle
Behavior:
- State accumulates across all stages in the workflow
- Each stage has a unique name for tracking
- Stages execute sequentially (not parallel)
Example:
vibeWorkflow('deployment', async (wf) => { // Stage 1 await wf.stage('build', { prompt: '/build' });
// Stage 2 (runs after stage 1) await wf.stage('deploy', { prompt: '/deploy' });});See Also:
files: { allChanged(): FileChange[]; byStage(stageName?: string): FileChange[];}Access cumulative file changes across all stages.
Methods:
allChanged()
Section titled “allChanged()”Get all files changed across all stages in the workflow.
vibeWorkflow('example', async (wf) => { await wf.stage('stage1', { prompt: '/task1' }); await wf.stage('stage2', { prompt: '/task2' });
const allFiles = wf.files.allChanged(); console.log(`Total files changed: ${allFiles.length}`);});byStage(stageName?)
Section titled “byStage(stageName?)”Get files changed in a specific stage (or current stage if omitted).
vibeWorkflow('example', async (wf) => { await wf.stage('build', { prompt: '/build' }); await wf.stage('test', { prompt: '/test' });
// Get files from specific stage const buildFiles = wf.files.byStage('build'); console.log('Build changed:', buildFiles.map(f => f.path));
// Get files from current stage const testFiles = wf.files.byStage(); console.log('Test changed:', testFiles.map(f => f.path));});See Also:
tools: { all(): Array<{ stage: string; call: ToolCall }>;}Access cumulative tool calls across all stages with stage context.
Methods:
Get all tool calls from all stages, with stage names included.
vibeWorkflow('example', async (wf) => { await wf.stage('implement', { prompt: '/implement' }); await wf.stage('test', { prompt: '/test' });
const allTools = wf.tools.all();
allTools.forEach(({ stage, call }) => { console.log(`[${stage}] ${call.name}: ${call.input}`); });});Returns: Array of objects with:
stage- Stage name where tool was calledcall- Tool call details
See Also:
timeline
Section titled “timeline”timeline: { events(): AsyncIterable<{ stage: string; evt: TimelineEvent }>;}Access unified timeline of events across all stages.
Methods:
events()
Section titled “events()”Returns async iterable over timeline events with stage context.
vibeWorkflow('example', async (wf) => { await wf.stage('stage1', { prompt: '/task1' }); await wf.stage('stage2', { prompt: '/task2' });
for await (const { stage, evt } of wf.timeline.events()) { console.log(`[${stage}] ${evt.type} at ${evt.timestamp}`); }});Returns: Async iterable of objects with:
stage- Stage name where event occurredevt- Timeline event details
until( predicate: (latest: RunResult) => boolean | Promise<boolean>, body: () => Promise<RunResult>, opts?: { maxIterations?: number }): Promise<RunResult[]>Loop helper for iterative workflows. Executes body until predicate returns true or max iterations reached.
Parameters:
predicate- Function that receives latestRunResultand returnstrueto stopbody- Function to execute each iteration (returnsRunResult)opts.maxIterations- Maximum iterations before stopping (default: 10)
Returns:
Promise<RunResult[]>- Array of results from all iterations
Behavior:
- Always executes body at least once (like do-while)
- Stops when predicate returns
true - Stops after
maxIterationseven if predicate never returnstrue
Example:
vibeWorkflow('retry deployment', async (wf) => { const results = await wf.until( // Stop when deployment succeeds (latest) => !latest.logs.some(log => log.includes('ERROR')),
// Try deployment async () => { return await wf.stage('deploy attempt', { prompt: '/deploy' }); },
{ maxIterations: 3 } );
console.log(`Succeeded after ${results.length} attempts`);});See Also:
defaults
Section titled “defaults”defaults: { workspace?: string; model?: string;}Default configuration for all stages in this workflow. Individual stages can override these values.
Properties:
workspace- Default workspace directory for all stagesmodel- Default model for all stages
Example:
vibeWorkflow('example', async (wf) => { // All stages inherit defaults await wf.stage('stage1', { prompt: '/task1' });
// Override workspace for specific stage await wf.stage('stage2', { prompt: '/task2', workspace: '/different/path' // Override });}, { defaults: { workspace: '/default/path', model: 'claude-sonnet-4-5-20250929' }});Precedence:
- Stage-level override (highest priority)
- Workflow defaults
- Global defaults (lowest priority)
Differences from VibeTestContext
Section titled “Differences from VibeTestContext”| Feature | VibeTestContext | WorkflowContext |
|---|---|---|
| Execution Method | runAgent() | stage() |
| Purpose | Testing & evaluation | Automation pipelines |
| Assertions | Has expect, judge | No assertions (workflows don’t fail) |
| State Tracking | Cumulative across runs | Cumulative across stages with stage names |
| Loop Helper | None | until() method |
| Defaults | No defaults | defaults property |
Access WorkflowContext through destructuring in vibeWorkflow functions:
import { vibeWorkflow } from '@dao/vibe-check';
vibeWorkflow('example', async (wf) => { // Access via destructured wf parameter await wf.stage('build', { prompt: '/build' });
const allFiles = wf.files.allChanged(); const allTools = wf.tools.all();
// Or destructure specific properties const { stage, files, until } = wf;});Complete Example
Section titled “Complete Example”import { vibeWorkflow } from '@dao/vibe-check';
vibeWorkflow('deployment pipeline', async (wf) => { // Stage 1: Build const build = await wf.stage('build', { prompt: '/build' });
console.log('Build files:', build.files.stats());
// Stage 2: Test const test = await wf.stage('test', { prompt: '/test' });
// Check if tests passed const testsPassed = !test.logs.some(log => log.includes('FAIL'));
if (testsPassed) { // Stage 3: Deploy await wf.stage('deploy', { prompt: '/deploy' }); } else { console.log('Tests failed, skipping deployment'); }
// Report cumulative stats console.log('Total files changed:', wf.files.allChanged().length); console.log('Tools used per stage:');
wf.tools.all().forEach(({ stage, call }) => { console.log(` ${stage}: ${call.name}`); });}, { defaults: { workspace: process.cwd(), model: 'claude-sonnet-4-5-20250929' }});See Also
Section titled “See Also”- vibeWorkflow() → - Workflow function using this context
- VibeTestContext → - Test equivalent
- RunResult → - Result type returned by stage()
- Building Workflows → - Workflow guide
- Loop Patterns → - Using until() helper