Orchestrate task execution via beads and sub-agents. Gets ready work from beads, spawns appropriate agents based on labels, monitors completion, and updates status...
Execute implementation tasks through coordinated sub-agents with optional TDD workflow:
agent:* labelsKey guarantee: The stop hook ensures ALL tasks complete before exit. Claude queries beads state each cycle rather than tracking in context, enabling token-efficient persistence.
Required after each agent completes:
{"s":"s","t":1200,"m":[...],"c":[...]}This enables retrospective analysis via /retro. Telemetry MUST be captured after EACH agent completes, not just at the end of the batch.
/approve-spec has created tasks/run-tasks [epic-id] # Run tasks for specific epic
/run-tasks # Run all ready tasks
Determine the location of discovery.db to support both new .parade/ structure and legacy project root:
# Path detection for .parade/ structure
if [ -f ".parade/discovery.db" ]; then
DISCOVERY_DB=".parade/discovery.db"
else
DISCOVERY_DB="./discovery.db"
fi
All subsequent database operations in this skill use $DISCOVERY_DB instead of hardcoded discovery.db.
Before starting task execution, check if TDD is enabled:
cat project.yaml | grep -A 1 "workflow:"
If tdd_enabled: true, enforce test-first gating workflow (see TDD Protocol).
If tdd_enabled: false, use standard workflow without gating.
Create an epic integration branch to isolate all work for this epic:
# Ensure main is up to date
git checkout main
git pull origin main
# Create epic branch
git checkout -b epic/<epic-id>
git push -u origin epic/<epic-id>
All task branches will be created from this epic branch, enabling:
See Git Strategy for complete branching and commit workflow.
bd ready --json
This returns tasks that:
openIf epic-id is provided, filter:
bd list --parent <epic-id> --status open --json
For each ready task, check metadata and labels:
bd show <task-id> --json
TDD Gating Rules:
skip_tests label โ ALLOW immediately (no TDD gating)test_task_id metadata and test task is NOT closed โ EXCLUDE from ready batchSee TDD Protocol for complete gating details.
Tasks can run in parallel if they don't depend on each other.
CRITICAL: Apply batch size limit to prevent context overflow.
# Check project config for max parallel tasks (default: 3)
MAX_PARALLEL=$(grep -A1 "workflow:" project.yaml | grep "max_parallel_tasks:" | awk '{print $2}')
MAX_PARALLEL=${MAX_PARALLEL:-3}
From the ready work, group tasks with size limit:
Why this matters: Each agent returns ~2-3K tokens. Running 8+ agents in parallel returns 16-24K tokens simultaneously, overwhelming context and preventing compaction.
Example with MAX_PARALLEL=3:
Ready now (8 tasks):
- bd-x7y8.1 [agent:sql]
- bd-x7y8.2 [agent:swift]
- bd-x7y8.3 [agent:typescript]
- bd-x7y8.4 [agent:typescript]
- bd-x7y8.5 [agent:sql]
- bd-x7y8.6 [agent:swift]
- bd-x7y8.7 [agent:typescript]
- bd-x7y8.8 [agent:test]
Split into sub-batches:
- Sub-batch 1: [.1, .2, .3] โ execute, wait, collect telemetry
- Sub-batch 2: [.4, .5, .6] โ execute, wait, collect telemetry
- Sub-batch 3: [.7, .8] โ execute, wait, collect telemetry
Execution pattern:
For each task in the current batch:
bd show <task-id> --json
Identify agent from labels:
Look for agent:* label (e.g., agent:swift, agent:sql, agent:test)
Create output directory:
# Ensure the epic folder exists
mkdir -p docs/features/<epic-id>
The output path pattern is: docs/features/<epic-id>/<task-id>.md
# Create isolated worktree from epic branch
bd worktree create agent-<task-id> --branch agent/<task-id> --base epic/<epic-id>
bd update <epic-id> --status in_progress
bd update <task-id> --status in_progress
See Agent Spawning Reference for:
run_in_background: trueWait for all agents in batch to complete.
For each agent result:
CRITICAL: Telemetry MUST be captured immediately after EACH agent completes, not just at batch end.
This is essential for:
/retroFailure Impact: If telemetry is not captured:
/retro cannot analyze execution patterns{"s":"s","t":1200,"m":["src/file.ts"],"c":["src/new.ts"]}
INSERT INTO agent_telemetry (
id, task_id, epic_id, agent_type, status, token_count,
duration_ms, files_modified, files_created, error_type,
error_summary, debug_attempts, started_at, completed_at
) VALUES (
'tel-' || hex(randomblob(4)), -- Generate unique ID
'<task-id>',
'<epic-id>',
'<agent-type>', -- e.g., 'typescript', 'swift', 'sql'
CASE '<status>' WHEN 's' THEN 'PASS' WHEN 'f' THEN 'FAIL' ELSE 'UNKNOWN' END,
<token_count>, -- From 't' field in JSON
<duration_ms>, -- Calculate from start/end time
'<files_modified_json>', -- From 'm' field
'<files_created_json>', -- From 'c' field
'<error_type>', -- From 'e' field if present
'<error_summary>', -- From 'x' field if present
0, -- debug_attempts (increment on retries)
'<started_at>',
datetime('now')
);
Error Handling - If telemetry insert fails:
Compact Output Key Reference:
| Key | Meaning | Values |
|---|---|---|
s |
status | "s" (success), "f" (fail), "b" (blocked) |
t |
tokens | estimated token count used |
m |
modified | array of modified file paths |
c |
created | array of created file paths |
e |
error | "t" (test), "b" (build), "o" (timeout) |
x |
error msg | truncated error message (max 200 chars) |
If agent output lacks JSON: Record with status='UNKNOWN', token_count=NULL. This indicates agents need prompt updates.
Checklist for Step 4a:
When agent reports completion, verify acceptance criteria are met:
When test-writer-agent reports completion:
# On successful RED phase
bd close <test-task-id>
When implementation agent reports completion:
See TDD Protocol for complete RED/GREEN/DEBUG phase details.
When implementation tests fail, enter debug loop:
debug_attempts metadataHybrid approach (token-optimized):
def smart_debug(task, test_output):
# Try sub-agent first (cheaper)
for attempt in range(2):
result = spawn_debug_agent(task, test_output)
if result.success:
return result
# Fall back to Ralph for persistent issues
if config.ralph.use_for_debug:
return debug_with_ralph(task, max_iterations=10)
else:
bd_update(task.id, status='blocked')
See TDD Protocol and Ralph Integration for details.
# Standard success
bd close <task-id>
# Test task success (RED phase)
bd close <test-task-id> # Unblocks implementation task
# Implementation task success (GREEN phase)
bd close <impl-task-id>
# Test task: tests pass without implementation (bad)
bd update <test-task-id> --status blocked --notes "Tests pass without implementation"
# Implementation task: debug attempts exhausted
bd update <impl-task-id> --status blocked --notes "Test failures persist after 3 attempts"
# Mark epic as blocked when any task fails
bd update <epic-id> --status blocked
When a blocker is resolved and work continues:
bd update <epic-id> --status in_progress
## Batch 1 Complete
โ
bd-x7y8.1: Database schema - PASS (closed)
โ
bd-x7y8.3: Experience picker UI - PASS (closed)
Newly unblocked:
- bd-x7y8.2: Assessment edge function [agent:typescript]
Proceeding to Batch 2...
## Batch 1 Complete (Test Phase)
โ
bd-x7y8.1: Write database tests - RED PHASE PASS (closed)
โ
bd-x7y8.3: Write picker UI tests - RED PHASE PASS (closed)
Newly unblocked (Implementation Phase):
- bd-x7y8.2: Implement database schema [agent:sql]
- bd-x7y8.4: Implement picker UI [agent:swift]
Proceeding to Batch 2 (Implementation)...
See TDD Protocol - Progress Logging for complete examples.
Check for new ready work:
bd ready --json
If tasks remain, return to Step 2.
When no more ready work:
## Execution Complete
Epic: bd-x7y8 - Feature Name
Completed:
โ
bd-x7y8.1: Task 1
โ
bd-x7y8.2: Task 2
โ
bd-x7y8.3: Task 3
All tasks closed. Feature ready for review.
## Execution Complete (TDD Mode)
Epic: bd-x7y8 - Feature Name
Test Phase (RED):
โ
bd-x7y8.1: Write tests - RED PASS
โ
bd-x7y8.3: Write tests - RED PASS
Implementation Phase (GREEN):
โ
bd-x7y8.2: Implementation - GREEN PASS
โ
bd-x7y8.4: Implementation - GREEN PASS (1 debug attempt)
Debug Summary:
- Total debug sessions: 1
- Successful fixes: 1
- Patterns documented: 1
All tasks closed. Feature ready for review.
When no more ready work AND all child tasks are closed:
Step 10a: Check for evolutions
Before presenting options, run evolution detection:
# Analyze git diff for new additions
git diff main...HEAD --name-only | wc -l
# Quick check for new exports (components, types, patterns)
git diff main...HEAD -- "src/renderer/**/*.tsx" | grep -c "^+export" || echo 0
git diff main...HEAD -- "src/shared/types/**/*.ts" | grep -c "^+export" || echo 0
Step 10b: Present options to user:
All tasks for "<epic-title>" are complete.
Completed: X tasks
Blocked: Y tasks (if any)
Debug loops: Z
New additions detected: N (components, fields, patterns)
Options:
1. Merge and close epic
2. Capture evolutions and close (recommended if new additions > 0)
3. Run retrospective + evolutions (recommended if debug loops > 0)
4. Keep open for manual review
Option 1: Merge and close:
git checkout main
git pull origin main
git merge epic/<epic-id> --no-ff -m "Merge epic/<epic-id>: <epic-title>
Completed tasks:
- <task-id>: <title>
- <task-id>: <title>
Closes: <epic-id>"
git push origin main
git branch -d epic/<epic-id>
git push origin --delete epic/<epic-id>
bd close <epic-id>
sqlite3 "$DISCOVERY_DB" "UPDATE briefs SET status = 'completed', updated_at = datetime('now') WHERE exported_epic_id = '<epic-id>';"
Option 2: Capture evolutions and close:
Before merge, invoke the evolution skill:
/evolve <epic-id> skill - detects new components, fields, and patternsSee Evolve Skill for evolution capture process.
Option 3: Retrospective + evolutions:
For epics with both debug loops AND new additions:
/retro <epic-id> skill - handles failure analysis, recommendations, and archiving/evolve <epic-id> skill - captures positive evolutionsThis captures both lessons learned (from failures) and knowledge gained (from new patterns).
See Retro Skill and Evolve Skill for details.
Option 4: Keep open:
Leave epic as in_progress on its branch for further review or manual testing.
See Git Strategy for rollback procedures if issues are discovered after merge.
After the epic is successfully merged and closed (Option 1, 2, or 3 completed), present a "What's next?" prompt to guide the user to their next workflow step.
Context-aware recommendations:
Analyze the just-completed epic to provide intelligent recommendations:
# Check if debug loops occurred (suggests retrospective)
DEBUG_LOOPS=$(sqlite3 "$DISCOVERY_DB" "SELECT COUNT(*) FROM agent_telemetry WHERE epic_id='<epic-id>' AND debug_attempts > 0;" 2>/dev/null || echo 0)
# Check if retrospective was already run
RETRO_RAN=$(sqlite3 "$DISCOVERY_DB" "SELECT COUNT(*) FROM workflow_events WHERE brief_id=(SELECT brief_id FROM specs WHERE exported_epic_id='<epic-id>') AND event_type='retro_complete';" 2>/dev/null || echo 0)
Present the prompt:
## What's next?
Epic "<epic-title>" has been merged and closed successfully.
Choose your next action:
| Option | Command | When Recommended |
|---|---|---|
| 1. Run retrospective | /retro <epic-id> |
Debug loops > 0 AND retro not yet run |
| 2. Start new feature | /discover |
Default next step for new work |
| 3. View project status | /workflow-status |
Check overall project health |
| 4. Done for now | (exit) | User wants to stop |
Recommendation logic:
def get_recommendation(epic_id):
debug_loops = get_debug_loop_count(epic_id)
retro_ran = check_retro_completed(epic_id)
if debug_loops > 0 and not retro_ran:
return "1. Run retrospective (recommended - debug loops detected)"
else:
return "2. Start new feature (recommended)"
Example output:
## What's next?
Epic "Add Post-Epic Completion Workflow Prompt" has been merged and closed successfully.
Choose your next action:
1. Run retrospective (/retro customTaskTracker-n24)
2. Start new feature (/discover) โ recommended
3. View project status (/workflow-status)
4. Done for now
What would you like to do?
If debug loops occurred:
## What's next?
Epic "Complex Feature Implementation" has been merged and closed successfully.
โ ๏ธ 3 debug loops occurred during this epic. Running a retrospective
can help identify patterns and improve future executions.
Choose your next action:
1. Run retrospective (/retro customTaskTracker-xyz) โ recommended
2. Start new feature (/discover)
3. View project status (/workflow-status)
4. Done for now
What would you like to do?
User selection handling:
/retro <epic-id> skill, then return to this prompt/discover skill to capture next feature idea/workflow-status skill, then return to this promptThis step improves workflow continuity by reducing friction between completed work and starting new work.
def get_ready_work(epic_id=None, tdd_enabled=False):
# Get base ready work from beads
if epic_id:
tasks = bd_list(parent=epic_id, status='open')
else:
tasks = bd_ready()
if not tdd_enabled:
return tasks
# Apply TDD gating
ready = []
for task in tasks:
# Skip tests label bypasses gating
if 'skip_tests' in task.labels:
ready.append(task)
continue
# Test tasks can run immediately
if 'test_task_id' not in task.metadata:
ready.append(task)
continue
# Implementation tasks wait for test task to close
test_task_id = task.metadata['test_task_id']
test_task = bd_show(test_task_id)
if test_task.status == 'closed':
ready.append(task)
return ready
def execute_batch(tasks, epic_id, tdd_enabled=False):
results = []
worktrees = {}
# Create output directories for all tasks
run(f"mkdir -p docs/features/{epic_id}")
# Create worktrees from epic branch (multi-task batches)
if len(tasks) > 1:
for task in tasks:
worktree_name = f"agent-{task.id}"
run(f"bd worktree create {worktree_name} --branch agent/{task.id} --base epic/{epic_id}")
worktrees[task.id] = worktree_name
# Spawn all agents in parallel
for task in tasks:
agent = select_agent(task) # See agent-spawning.md
bd_update(task.id, status='in_progress')
# Spawn with background=true, include worktree path and output path
working_dir = f"../{worktrees[task.id]}" if task.id in worktrees else None
output_path = f"docs/features/{epic_id}/{task.id}.md"
result = spawn_agent(agent, task, working_dir=working_dir,
output_path=output_path, background=True)
results.append((task, result))
# Wait for all to complete
for task, result in results:
if result.status == 'PASS':
verify_and_close(task, tdd_enabled)
# Squash merge to epic branch and cleanup
if task.id in worktrees:
run(f"git checkout epic/{epic_id}")
run(f"git merge agent/{task.id} --squash")
run(f"git commit -m '{task.id}: {task.title}'")
run(f"bd worktree remove {worktrees[task.id]}")
run(f"git branch -D agent/{task.id}")
else:
handle_failure(task, result, tdd_enabled)
# Keep worktree for debugging if failure
# Push checkpoint after batch completes
run(f"git push origin epic/{epic_id}")
def verify_and_close(task, tdd_enabled):
if not tdd_enabled:
# Standard mode: just close
bd_close(task.id)
return
# TDD mode: verify phase
if 'agent:test' in task.labels:
# RED phase: verify tests fail
if verify_tests_fail(task):
bd_close(task.id) # Unblocks impl task
else:
bd_update(task.id, status='blocked',
notes='Tests pass without implementation')
else:
# GREEN phase: verify tests pass
if verify_tests_pass(task):
bd_close(task.id)
else:
enter_debug_loop(task) # See tdd-protocol.md
See docs/tdd-protocol.md for:
See docs/agent-spawning.md for:
See docs/git-strategy.md for:
See docs/stop-hook-enforcement.md for:
See docs/ralph-integration.md for:
See docs/retrospective.md for:
/run-tasksAfter successful execution: