| name | workflow-execute |
| description | Autonomous workflow execution pipeline with CSV wave engine.
Session discovery → plan validation → IMPL-*.json → CSV conversion →
wave execution via spawn_agents_on_csv → results sync.
Task JSONs remain the rich data source; CSV is brief + execution state.
|
| argument-hint | [-y|--yes] [-c|--concurrency N] [--resume-session=ID] [--with-commit] |
| allowed-tools | spawn_agents_on_csv, request_user_input, Read, Write, Edit, Bash, Glob, Grep |
Auto Mode
When --yes or -y: Auto-select first session, auto-complete session after all tasks, skip all confirmations.
Workflow Execute
Usage
$workflow-execute
$workflow-execute --yes
$workflow-execute --resume-session=WFS-auth
$workflow-execute -y --with-commit
$workflow-execute -y -c 4 --with-commit
$workflow-execute -y --with-commit --resume-session=WFS-auth
Flags:
-y, --yes: Skip all confirmations (auto mode)
-c, --concurrency N: Max concurrent agents per wave (default: 4)
--resume-session=ID: Resume specific session (skip Phase 1-2)
--with-commit: Auto-commit after each task completion
Overview
Autonomous execution pipeline using spawn_agents_on_csv wave engine. Converts planning artifacts (IMPL-*.json + plan.json) into CSV for wave-based parallel execution, with full task JSON available via task_json_path column.
┌──────────────────────────────────────────────────────────────────┐
│ WORKFLOW EXECUTE PIPELINE │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Phase 1: Session Discovery │
│ ├─ Find active sessions │
│ ├─ Auto-select (1 session) or prompt (multiple) │
│ └─ Load session metadata │
│ │
│ Phase 2: Planning Document Validation │
│ ├─ Verify IMPL_PLAN.md exists │
│ ├─ Verify TODO_LIST.md exists │
│ └─ Verify .task/ contains IMPL-*.json │
│ │
│ Phase 3: JSON → CSV Conversion │
│ ├─ Read all IMPL-*.json + plan.json │
│ ├─ Skip already-completed tasks (resume support) │
│ ├─ Compute waves via Kahn's BFS (deps + plan hints) │
│ ├─ Generate tasks.csv (21 cols) + context.csv │
│ └─ Initialize discoveries.ndjson │
│ │
│ Phase 4: Wave Execute (spawn_agents_on_csv) │
│ ├─ Per wave: build prev_context → wave-{N}.csv │
│ ├─ spawn_agents_on_csv with execute instruction │
│ ├─ Merge results → tasks.csv + task JSON status │
│ ├─ Auto-commit per task (if --with-commit) │
│ └─ Cleanup temp wave CSVs │
│ │
│ Phase 5: Results Sync │
│ ├─ Export results.csv │
│ ├─ Reconcile TODO_LIST.md with tasks.csv status │
│ └─ User choice: Review | Complete Session │
│ │
│ Phase 6: Post-Implementation Review (Optional) │
│ ├─ Select review type (quality/security/architecture) │
│ ├─ CLI-assisted analysis │
│ └─ Generate REVIEW-{type}.md │
│ │
│ Resume Mode (--resume-session): │
│ └─ Skip Phase 1-2 → enter Phase 3 (skip completed tasks) │
│ │
└──────────────────────────────────────────────────────────────────┘
CSV Schemas
tasks.csv (21 columns)
id,title,description,agent,scope,deps,execution_group,context_from,wave,task_json_path,hints,execution_directives,acceptance_criteria,prev_context,status,findings,files_modified,tests_passed,acceptance_met,summary_path,error
| Column | Phase | Source | Description |
|---|
id | Input | task.id | IMPL-001 etc |
title | Input | task.title | Short title |
description | Input | task.description | Full description |
agent | Input | meta.agent or inferred | @code-developer etc |
scope | Input | task.scope / focus_paths | File scope glob |
deps | Input | depends_on.join(';') | Dependency IDs (semicolon-separated) |
execution_group | Input | meta.execution_group | Parallel group identifier |
context_from | Computed | deps + completed predecessors | Context source IDs |
wave | Computed | Kahn's BFS | Wave number (1-based) |
task_json_path | Input | relative path | .task/IMPL-001.json (agent reads full JSON) |
hints | Input | artifacts + pre_analysis refs | tips || file1;file2 |
execution_directives | Input | convergence.verification | Verification commands |
acceptance_criteria | Input | convergence.criteria.join | Acceptance conditions |
prev_context | Computed(per-wave) | context_from findings lookup | Predecessor task findings |
status | Output | agent result | pending→completed/failed/skipped |
findings | Output | agent result | Key findings (max 500 chars) |
Key design: task_json_path lets agents read the full task JSON (with pre_analysis, flow_control, convergence etc). CSV is "brief + execution state".
context.csv (4 columns)
key,type,value,source
"tech_stack","array","TypeScript;React 18;Zustand","plan.json"
"conventions","array","Use useIntl;Barrel exports","plan.json"
"context_package_path","path",".process/context-package.json","session"
"discoveries_path","path","discoveries.ndjson","session"
Injected into instruction template as static context — avoids each agent rediscovering project basics.
Session Structure
.workflow/active/WFS-{session}/
├── workflow-session.json # Session state
├── plan.json # Structured plan (machine-readable)
├── IMPL_PLAN.md # Implementation plan (human-readable)
├── TODO_LIST.md # Progress tracking (Phase 5 sync)
├── tasks.csv # Phase 3 generated, Phase 4 updated
├── context.csv # Phase 3 generated
├── results.csv # Phase 5 exported
├── discoveries.ndjson # Phase 3 initialized, Phase 4 agents append
├── .task/ # Task definitions (unchanged)
│ ├── IMPL-1.json
│ └── IMPL-N.json
├── .summaries/ # Agent-generated summaries
│ ├── IMPL-1-summary.md
│ └── IMPL-N-summary.md
├── .process/context-package.json# Unchanged
└── wave-{N}.csv # Phase 4 temporary (cleaned after each wave)
Implementation
Session Initialization
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
const AUTO_YES = $ARGUMENTS.includes('--yes') || $ARGUMENTS.includes('-y')
const withCommit = $ARGUMENTS.includes('--with-commit')
const resumeMatch = $ARGUMENTS.match(/--resume-session[=\s]+(\S+)/)
const resumeSessionId = resumeMatch ? resumeMatch[1] : null
const isResumeMode = !!resumeSessionId
const concurrencyMatch = $ARGUMENTS.match(/(?:--concurrency|-c)\s+(\d+)/)
const maxConcurrency = concurrencyMatch ? parseInt(concurrencyMatch[1]) : 4
Phase 1: Session Discovery
Applies to: Normal mode only (skipped if --resume-session).
let sessionId, sessionFolder
if (isResumeMode) {
sessionId = resumeSessionId
sessionFolder = `.workflow/active/${sessionId}`
} else {
const sessions = Bash(`ls -d .workflow/active/WFS-* 2>/dev/null`).trim().split('\n').filter(Boolean)
if (sessions.length === 0) {
console.log('ERROR: No active workflow sessions found.')
console.log('Run $workflow-plan "task description" to create a session.')
return
}
if (sessions.length === 1) {
sessionFolder = sessions[0]
sessionId = sessionFolder.split('/').pop()
console.log(`Auto-selected session: ${sessionId}`)
} else {
if (AUTO_YES) {
sessionFolder = sessions[0]
sessionId = sessionFolder.split('/').pop()
console.log(`[--yes] Auto-selected: ${sessionId}`)
} else {
sessionInfos = sessions.(, ).( {
id = s.().()
total = (().()) ||
done = (().()) ||
{ id, : s, : }
})
answer = functions.({
: [{
: ,
: ,
: ,
: sessionInfos.( ({
: s.,
: s.
}))
}]
})
sessionId = answer...[]
sessionFolder =
}
}
}
Phase 2: Planning Document Validation
Applies to: Normal mode only.
if (!isResumeMode) {
const checks = {
'IMPL_PLAN.md': Bash(`test -f "${sessionFolder}/IMPL_PLAN.md" && echo yes`).trim() === 'yes',
'TODO_LIST.md': Bash(`test -f "${sessionFolder}/TODO_LIST.md" && echo yes`).trim() === 'yes',
'.task/ has files': parseInt(Bash(`ls ${sessionFolder}/.task/IMPL-*.json 2>/dev/null | wc -l`).trim()) > 0
}
const missing = Object.entries(checks).filter(([_, ok]) => !ok).map(([name]) => name)
if (missing.length > 0) {
console.log(`ERROR: Missing planning documents: ${missing.join(', ')}`)
console.log(`Run $workflow-plan --session ${sessionId} to generate plan.`)
return
}
console.log(`Planning documents validated.`)
}
Phase 3: JSON → CSV Conversion
Applies to: Both normal and resume modes (resume entry point).
Objective: Convert IMPL-*.json + plan.json into tasks.csv + context.csv with computed waves.
console.log(`\n## Phase 3: JSON → CSV Conversion\n`)
Bash(`cd "${sessionFolder}" && jq '.status = "active" | .execution_started_at = (.execution_started_at // "'"$(date -Iseconds)"'")' workflow-session.json > tmp.json && mv tmp.json workflow-session.json 2>/dev/null || true`)
Bash(`mkdir -p "${sessionFolder}/.summaries"`)
const taskFiles = Bash(`ls ${sessionFolder}/.task/IMPL-*.json 2>/dev/null`).trim().split('\n').filter(Boolean)
if (taskFiles.length === 0) {
console.log('ERROR: No task JSONs found in .task/')
return
}
const taskJsons = taskFiles.map(f => {
const content = Read(f)
const json = JSON.parse(content)
json._filePath = f
if (!json.id) {
json.id = f.split('/').pop().replace('.json', )
}
json
})
todoContent = ()
completedIds = ()
todoLines = todoContent.() || []
todoLines.( {
match = line.()
(match) completedIds.(match[])
})
taskJsons.( {
(tj. === ) completedIds.(tj.)
})
pendingJsons = taskJsons.( !completedIds.(tj.))
.()
.()
.()
(pendingJsons. === ) {
.()
}
planJsonPath =
planJsonExists = ().() ===
planJson = planJsonExists ? .((planJsonPath) || ) : {}
() {
(tj.?.) tj..
typeMap = {
: ,
: ,
: ,
: ,
:
}
typeMap[tj.?.] ||
}
() {
tj. || tj.?. || []
}
() {
tips = []
files = []
(tj.) {
tj..( { (a.) files.(a.) })
}
(tj.) {
tj..( {
(step. === && step.) files.(step.)
})
}
(tj.?.) tips.(tj..)
(tj.?.) tips.(tj..)
tipsStr = tips.()
filesStr = files.()
(tipsStr && filesStr)
(tipsStr) tipsStr
(filesStr)
}
() {
(tj.?.) {
.(tj..)
? tj...()
: tj..
}
(tj.?.) tj..
}
() {
(tj.?.) {
.(tj..)
? tj...()
: tj..
}
(tj.?.) {
.(tj..)
? tj...()
: tj..
}
}
() {
(tj.) tj.
(tj.) {
.(tj.) ? tj..() : tj.
}
}
taskRows = taskJsons.( ({
: tj.,
: tj. || ,
: tj. || ,
: (tj),
: (tj),
: (tj).(),
: tj.?. || ,
: ,
: ,
: (tj),
: (tj),
: (tj),
: ,
: completedIds.(tj.) ? : ,
: ,
: ,
: ,
: ,
: ,
:
}))
() {
taskMap = (rows.( [r., r]))
inDegree = (rows.( [r., ]))
adjList = (rows.( [r., []]))
( row rows) {
deps = row..().()
( dep deps) {
(taskMap.(dep)) {
adjList.(dep).(row.)
inDegree.(row., inDegree.(row.) + )
}
}
}
queue = []
waveMap = ()
( [id, deg] inDegree) {
(deg === ) {
queue.([id, ])
waveMap.(id, )
}
}
maxWave =
idx =
(idx < queue.) {
[current, depth] = queue[idx++]
( next adjList.(current)) {
newDeg = inDegree.(next) -
inDegree.(next, newDeg)
nextDepth = .(waveMap.(next) || , depth + )
waveMap.(next, nextDepth)
(newDeg === ) {
queue.([next, nextDepth])
maxWave = .(maxWave, nextDepth)
}
}
}
( row rows) {
(!waveMap.(row.)) {
.()
waveMap.(row., maxWave + )
maxWave = maxWave +
}
}
(planJson.?.) {
planJson...( {
phaseWave = idx +
taskIds = phase. || phase. || []
taskIds.( {
(waveMap.(id)) {
(phaseWave > waveMap.(id)) {
waveMap.(id, phaseWave)
}
}
})
})
maxWave = .(maxWave, ...waveMap.())
}
{ waveMap, maxWave }
}
{ waveMap, maxWave } = (taskRows, planJson)
taskRows.( {
row. = waveMap.(row.) ||
depIds = row..().()
contextIds = [... ([...depIds, ...[...completedIds].( id !== row.)])]
row. = contextIds.()
})
() {
Phase 4: Wave Execute (spawn_agents_on_csv)
Objective: Execute tasks wave-by-wave via spawn_agents_on_csv. Each wave builds prev_context from completed predecessors.
console.log(`\n## Phase 4: Wave Execute\n`)
let effectiveConcurrency = maxConcurrency
if (planJson.recommended_execution === 'Sequential') {
effectiveConcurrency = 1
console.log(` Sequential mode (from plan.json), concurrency: 1`)
} else {
console.log(` Parallel mode, concurrency: ${effectiveConcurrency}`)
}
const contextCsvContent = Read(`${sessionFolder}/context.csv`)
const contextEntries = parseCsv(contextCsvContent)
const contextBlock = contextEntries.map(e => `- **${e.key}** (${e.type}): ${e.value}`).join('\n')
const failedIds = new Set()
const skippedIds = new Set()
for (let wave = 1; wave <= maxWave; wave++) {
console.log(`\n### Wave ${wave}/${maxWave}\n`)
masterCsv = (())
waveTasks = masterCsv.(
(row.) === wave && row. ===
)
(waveTasks. === ) {
.()
}
executableTasks = []
( task waveTasks) {
deps = (task. || ).().()
(deps.( failedIds.(d) || skippedIds.(d))) {
skippedIds.(task.)
(, task., {
: ,
:
})
.()
}
executableTasks.(task)
}
(executableTasks. === ) {
.()
}
( task executableTasks) {
task. = (task., masterCsv)
}
waveHeader =
waveRows = executableTasks.(
[t., t., t., t., t., t., t.,
t., t., t., t., t.,
t., t.]
.(
prev_context Builder
function buildPrevContext(contextFrom, masterCsv) {
if (!contextFrom) return 'No previous context available'
const ids = contextFrom.split(';').filter(Boolean)
const entries = []
ids.forEach(id => {
const row = masterCsv.find(r => r.id === id)
if (row && row.status === 'completed' && row.findings) {
entries.push(`[${row.id}: ${row.title}] ${row.findings}`)
if (row.files_modified) entries.push(` Modified: ${row.files_modified}`)
}
})
return entries.length > 0 ? entries.join('\n') : 'No previous context available'
}
Execute Instruction Template
function buildExecuteInstruction(sessionFolder, contextBlock) {
return `
## TASK ASSIGNMENT
### MANDATORY FIRST STEPS
1. Read your FULL task JSON: ${sessionFolder}/{task_json_path}
- CSV row is a brief — task JSON has pre_analysis, flow_control, convergence, and full context
2. Read shared discoveries: ${sessionFolder}/discoveries.ndjson (if exists)
3. Read project context: .workflow/project-tech.json (if exists)
---
## Your Task
**Task ID**: {id}
**Title**: {title}
**Description**: {description}
**Agent Type**: {agent}
**Scope**: {scope}
### Task JSON (full details)
Read: ${sessionFolder}/{task_json_path}
### Implementation Hints & Reference Files
{hints}
> Format: \`tips text || file1;file2\`. Read ALL reference files (after ||) before starting. Apply tips (before ||) as guidance.
### Execution Directives
{execution_directives}
> Commands to run for verification, tool restrictions, or environment requirements.
### Acceptance Criteria
{acceptance_criteria}
### Previous Context (from predecessor tasks)
{prev_context}
### Project Context
${contextBlock}
---
## Execution Protocol
1. **Read task JSON**: Load ${sessionFolder}/{task_json_path} for full task details including pre_analysis steps and flow_control
2. **Check execution method**: If task JSON has \`execution_config.method\`, follow it (agent vs cli mode)
3. **Execute pre_analysis**: If task JSON has \`pre_analysis\` steps, run them first to gather context
4. **Read references**: Parse {hints} — read all files listed after \`||\` to understand existing patterns
5. **Read discoveries**: Load ${sessionFolder}/discoveries.ndjson for shared findings
6. **Use context**: Apply predecessor tasks' findings from prev_context above
7. **Stay in scope**: ONLY create/modify files within {scope} — do NOT touch files outside this boundary
8. **Apply hints**: Follow implementation tips from {hints} (before \`||\`)
9. **Execute**: Implement the task as described in the task JSON
10. **Generate summary**: Write execution summary to ${sessionFolder}/.summaries/{id}-summary.md with sections:
## Summary, ## Files Modified (as \`- \\\`path\\\`\` list), ## Key Decisions, ## Tests
11. **Run directives**: Execute commands from {execution_directives} to verify your work
12. **Update TODO**: In ${sessionFolder}/TODO_LIST.md, change \`- [ ] {id}\` to \`- [x] {id}\`
13. **Share discoveries**: Append findings to shared board:
\`\`\`bash
echo '{"ts":"<ISO8601>","worker":"{id}","type":"<type>","data":{...}}' >> ${sessionFolder}/discoveries.ndjson
\`\`\`
14. **Report result**: Return JSON via report_agent_job_result
### Discovery Types to Share
- \`code_pattern\`: {name, file, description} — reusable patterns found
- \`integration_point\`: {file, description, exports[]} — module connection points
- \`convention\`: {naming, imports, formatting} — code style conventions
- \`blocker\`: {issue, severity, impact} — blocking issues encountered
---
## Output (report_agent_job_result)
Return JSON:
{
"id": "{id}",
"status": "completed" | "failed",
"findings": "Key discoveries and implementation notes (max 500 chars)",
"files_modified": ["path1", "path2"],
"tests_passed": true | false,
"acceptance_met": "Summary of which acceptance criteria were met/unmet",
"error": ""
}
**IMPORTANT**: Set status to "completed" ONLY if:
- All acceptance criteria are met
- Verification directives pass (if any)
Otherwise set status to "failed" with details in error field.
`
}
Phase 5: Results Sync
Objective: Export results, reconcile TODO_LIST.md, update session status.
console.log(`\n## Phase 5: Results Sync\n`)
const finalCsvContent = Read(`${sessionFolder}/tasks.csv`)
Write(`${sessionFolder}/results.csv`, finalCsvContent)
const finalTasks = parseCsv(finalCsvContent)
let todoMd = Read(`${sessionFolder}/TODO_LIST.md`)
for (const task of finalTasks) {
if (task.status === 'completed') {
const uncheckedPattern = new RegExp(`^(- \\[ \\] ${task.id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(:.*)?)$`, 'm')
todoMd = todoMd.replace(uncheckedPattern, (match, line) => line.replace('- [ ]', '- [x]'))
}
}
Write(`${sessionFolder}/TODO_LIST.md`, todoMd)
const completed = finalTasks.filter(t => t.status === 'completed')
failed = finalTasks.( t. === )
skipped = finalTasks.( t. === )
pending = finalTasks.( t. === )
.()
.()
.()
.()
.()
allDone = failed. === && skipped. === && pending. ===
sessionStatus = allDone ? :
()
() {
.()
} {
nextStep = functions.({
: [{
: ,
: ,
: ,
: [
{ : , : },
{ : , : }
]
}]
})
(nextStep...[] === ) {
} {
.()
}
}
Phase 6: Post-Implementation Review (Optional)
Objective: CLI-assisted specialized review of implemented code.
console.log(`\n## Phase 6: Post-Implementation Review\n`)
const reviewType = AUTO_YES ? 'quality' : (() => {
const answer = functions.request_user_input({
questions: [{
header: "Review Type",
id: "review_type",
question: "Select review type.",
options: [
{ label: "Quality (Recommended)", description: "Code quality, best practices, maintainability" },
{ label: "Security", description: "Security vulnerabilities, OWASP Top 10" },
{ label: "Architecture", description: "Architecture decisions, scalability, patterns" }
]
}]
})
return answer.answers.review_type.answers[0].toLowerCase()
})()
const reviewTasks = parseCsv(Read(`${sessionFolder}/tasks.csv`))
const allModifiedFiles = new Set()
reviewTasks.forEach( => {
(t. || ).().().( allModifiedFiles.(f))
})
fileList = [...allModifiedFiles].()
({
: ,
:
})
(, reviewReport)
.()
(!) {
postReview = functions.({
: [{
: ,
: ,
: ,
: [
{ : , : },
{ : , : }
]
}]
})
(postReview...[] === ) {
}
}
.()
CSV Helpers
function parseCsv(content) {
const lines = content.trim().split('\n')
if (lines.length < 2) return []
const header = parseCsvLine(lines[0])
return lines.slice(1).map(line => {
const cells = parseCsvLine(line)
const obj = {}
header.forEach((col, i) => { obj[col] = cells[i] || '' })
return obj
})
}
function parseCsvLine(line) {
const cells = []
let current = ''
let inQuotes = false
for (let i = 0; i < line.length; i++) {
const ch = line[i]
if (inQuotes) {
if (ch === '"' && line[i + 1] === '"') {
current += '"'
i++
} else if (ch === '"') {
inQuotes = false
} {
current += ch
}
} {
(ch === ) {
inQuotes =
} (ch === ) {
cells.(current)
current =
} {
current += ch
}
}
}
cells.(current)
cells
}
() {
content = (csvPath)
lines = content.()
header = (lines[])
( i = ; i < lines.; i++) {
cells = (lines[i])
(cells[] === taskId) {
( [col, val] .(updates)) {
colIdx = header.(col)
(colIdx >= ) {
cells[colIdx] = (val).(, )
}
}
lines[i] = cells.( ).()
}
}
(csvPath, lines.())
}
() {
Agent Assignment Rules
meta.agent specified → Use specified agent file
meta.agent missing → Infer from meta.type:
feature → code-developer
test-gen → code-developer
test-fix → test-fix-agent
review → universal-executor
docs → doc-generator
default → code-developer
Error Handling
| Error | Recovery |
|---|
| No active sessions | Guide: run $workflow-plan "description" first |
| Missing planning docs | Guide: run $workflow-plan --session ID |
| Agent failure | Mark failed in tasks.csv, skip dependents, continue wave |
| Dependency cascade | Skip dependent tasks, report at Phase 5 |
| CSV parse error | Validate CSV format, report line number |
| Task JSON corruption | Skip task, mark failed in CSV |
| Commit failure | Log error, continue execution (non-blocking) |
| Circular dependency | Warn and assign to last wave |
| All wave tasks skipped | Log and continue to next wave |
Core Rules
- Wave Order is Sacred: Never execute wave N before wave N-1 completes and results merge
- CSV is Execution State: tasks.csv holds all execution state — always re-read before each wave
- Task JSON is Rich Data: agents read full task JSON via
task_json_path — CSV is brief
- Skip on Failure: If a dependency failed, skip the dependent task (cascade)
- Cleanup Temp Files: Remove wave CSVs after results are merged
- TODO_LIST.md Sync: Phase 5 reconciles TODO_LIST.md with tasks.csv final state
- Discovery Board is Append-Only: Never clear, modify, or recreate discoveries.ndjson
- DO NOT STOP: Continuous execution until all waves complete or all remaining tasks are skipped
- Planning Artifacts Unchanged: IMPL-*.json, plan.json, IMPL_PLAN.md formats are preserved
Compact Protection
COMPACT DIRECTIVE: If context compression occurs during execution:
- Re-read
tasks.csv for current execution state (source of truth)
- Re-read
TODO_LIST.md for progress display
- Re-read
plan.json for execution hints (concurrency, phases)
- Task JSONs are read per-wave via
task_json_path, compression has minimal impact
- Wave loop state (
failedIds, skippedIds, wave) can be reconstructed from tasks.csv status column