- 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
```bash
$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)
```csv
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) |
| `files_modified` | Output | agent result | Modified files (semicolon-separated) |
| `tests_passed` | Output | agent result | true/false |
| `acceptance_met` | Output | agent result | Acceptance status |
| `summary_path` | Output | generated | .summaries/IMPL-X-summary.md |
| `error` | Output | agent result | Error message |
**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)
```csv
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
```javascript
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
// Parse flags
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`).
```javascript
let sessionId, sessionFolder
if (isResumeMode) {
sessionId = resumeSessionId
sessionFolder = `.workflow/active/${sessionId}`
// Skip to Phase 3
} 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 {
const sessionInfos = sessions.slice(0, 4).map(s => {
const id = s.split('/').pop()
const total = parseInt(Bash(`grep -c '^- \\[' "${s}/TODO_LIST.md" 2>/dev/null || echo 0`).trim()) || 0
const done = parseInt(Bash(`grep -c '^- \\[x\\]' "${s}/TODO_LIST.md" 2>/dev/null || echo 0`).trim()) || 0
return { id, path: s, progress: `${done}/${total} tasks` }
})
const answer = functions.request_user_input({
questions: [{
header: "Session",
id: "session",
question: "Select session to execute.",
options: sessionInfos.map(s => ({
label: s.id,
description: s.progress
}))
}]
})
sessionId = answer.answers.session.answers[0]
sessionFolder = `.workflow/active/${sessionId}`
}
}
}
```
---
### Phase 2: Planning Document Validation
**Applies to**: Normal mode only.
```javascript
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.
```javascript
console.log(`\n## Phase 3: JSON → CSV Conversion\n`)
// Update session status to active
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"`)
// 3.1: Read all IMPL-*.json
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
// Fallback: derive id from filename if missing
if (!json.id) {
json.id = f.split('/').pop().replace('.json', '')
}
return json
})
// 3.2: Skip completed tasks (resume support)
const todoContent = Read(`${sessionFolder}/TODO_LIST.md`)
const completedIds = new Set()
const todoLines = todoContent.match(/^- \[x\] (IMPL-\d+(?:\.\d+)?)/gm) || []
todoLines.forEach(line => {
const match = line.match(/IMPL-\d+(?:\.\d+)?/)
if (match) completedIds.add(match[0])
})
// Also check task JSON status field
taskJsons.forEach(tj => {
if (tj.status === 'completed') completedIds.add(tj.id)
})
const pendingJsons = taskJsons.filter(tj => !completedIds.has(tj.id))
console.log(` Total tasks: ${taskJsons.length}`)
console.log(` Already completed: ${completedIds.size}`)
console.log(` Pending: ${pendingJsons.length}`)
if (pendingJsons.length === 0) {
GitHub에서 보기