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): AgentExecution
Execute 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 latestRunResult
and returnstrue
to 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
maxIterations
even 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