Executions
Routine execution context, step results, data flow, and real-time monitoring via events.
When a routine runs, the executor creates a RoutineContext that flows through every step. Each step produces a StepResult, and events are broadcast in real time for monitoring.
RoutineContext
The execution context is created at the start of a routine run and passed to every step. Steps can read from it (e.g., to access task metadata or gate feedback) and the executor writes to it after each step completes.
Core fields
| Field | Type | Description |
|---|---|---|
routine_id | UUID | The routine being executed |
project_id | UUID | The project this execution belongs to |
initial_input | string | The input text that started the routine |
max_retries | integer | Maximum retry attempts (from routine config) |
step_results | map | Results keyed by step ID, accumulated during execution |
execution_run_id | UUID? | The execution run record ID (null for chat routines) |
task_id | UUID? | The task being processed (null for chat/cron routines) |
is_cron_trigger | boolean | When true, agent steps use the role's cron_task template |
Task metadata
These fields are populated from the task being executed and are available in prompt templates via {{ task.* }}.
| Field | Template variable | Description |
|---|---|---|
task_title | {{ task.title }} | Task title |
task_description | {{ task.description }} | Task description |
task_acceptance_criteria | {{ task.acceptance_criteria }} | Acceptance criteria |
task_tags | {{ task.tags }} | List of tags |
task_source | {{ task.source }} | Who created/triggered: "user" or a role name |
task_status | {{ task.status }} | Status: open, ready, in_progress, done |
task_priority | {{ task.priority }} | Priority: low, medium, high, critical |
task_type | {{ task.type }} | Type: bug, feature, task |
task_slug | {{ task.slug }} | URL-safe identifier |
task_complexity | {{ task.complexity }} | Estimated complexity score |
Git context
| Field | Template variable | Description |
|---|---|---|
git_branch | {{ git.branch }} | Current working branch (e.g., agent/<run>/<slug>) |
git_target_branch | {{ git.target_branch }} | Target branch for merges/PRs (defaults to main) |
git_work_dir | {{ git.work_dir }} | Absolute path to the worktree directory |
git_repo_url | {{ git.repo_url }} | Remote clone URL |
Routine and step context
| Field | Template variable | Description |
|---|---|---|
routine_name | {{ routine.name }} | Name of the routine |
current_step_name | {{ step.name }} | Name of the currently executing step |
step_metadata | {{ step.metadata }} | JSON from step.config.metadata |
gate_feedback | {{ gate_feedback }} | Output from the most recent failed gate/cron/lambda step |
Project context
| Field | Template variable | Description |
|---|---|---|
project_name | {{ project.name }} | Project name |
project_description | {{ project.description }} | Project description |
StepResult
Every step produces a StepResult that is stored in the context and used for edge condition evaluation.
| Field | Type | Description |
|---|---|---|
passed | boolean | Whether the step succeeded |
output | string | The step's output text |
data | JSON | Structured data (optional) |
step_id | UUID | ID of the step that produced this result |
step_name | string | Name of the step |
input_tokens | u64 | Total input tokens consumed (LLM steps) |
output_tokens | u64 | Total output tokens consumed (LLM steps) |
Data flow between steps
Data flows through the routine context:
- Initial input -- The
initial_inputstring (task description or user message) is available to all steps. - Step results -- Each step's
StepResultis stored instep_resultskeyed by step ID. The most recent result is used as input for gate steps. - Gate feedback -- When a gate, cron, or lambda step fails, its output is stored as
gate_feedback. The next agent step (reached via anon_failedge) can use this to understand what went wrong. - Source tracking -- When a step fails,
task_sourceis updated to the failing step's role name, so downstream steps know where feedback originated. - Metrics -- Token usage and execution counts are accumulated per step in
RoutineMetrics.
Routine events
Routine events are broadcast via tokio::sync::broadcast for real-time monitoring. The event channel has a capacity of 512 buffered events.
RoutineEvent structure
{
"task_id": "uuid",
"execution_run_id": "uuid",
"event_type": "phase_started",
"phase": "implementation",
"data": {},
"timestamp": "2024-01-01T00:00:00Z"
}Event types
| Event type | Description |
|---|---|
phase_started | A phase has started executing |
phase_completed | A phase completed successfully |
phase_failed | A phase failed (may retry) |
status_changed | The task's status changed |
retry_scheduled | A retry has been scheduled after a failure |
routine_completed | The entire routine completed successfully |
routine_failed | The routine failed permanently (max retries exceeded) |
Routine phases
| Phase | Description |
|---|---|
implementation | Code generation, branch creation, commit |
review | LLM code review of the diff |
testing | Test execution and acceptance verification |
WebSocket step events
In addition to routine events, the executor emits richer step-level events via WebSocket for frontend execution tracking.
Step started
Emitted when a step begins execution. Includes role info (ID, color, name) for frontend identicon rendering.
Step completed
Emitted when a step finishes. Includes:
- Event type:
step_completed(pass),step_warning(fail withon_failedge available), orstep_failed(fail with no recovery path) - Metrics:
execution_count,input_tokens,output_tokens,total_tokens - Duration: Execution time in milliseconds
The distinction between step_warning and step_failed is important: a gate failure with an on_fail edge is expected (the routine has a recovery path), while a failure with no matching edge is terminal.
Monitoring
Subscribe to routine events by connecting to the WebSocket endpoint. Events are fire-and-forget -- if no receivers are connected, events are silently dropped.
// Subscribe to execution events
const ws = new WebSocket('wss://your-instance.com/ws');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.event_type === 'step_started') {
console.log(`Step started: ${data.step_name}`);
}
};