feat(skills): add team-roadmap-dev skill with phased execution pipeline

Roadmap-driven development team skill with coordinator/planner/executor/verifier
roles. Features action-planning-agent integration (IMPL-*.json task format),
convergence criteria verification, pause/resume support, and wave-based execution.
This commit is contained in:
catlog22
2026-02-24 23:32:32 +08:00
parent dadcc1af5e
commit 6c16c121d2
15 changed files with 3740 additions and 0 deletions

View File

@@ -0,0 +1,309 @@
# Command: implement
Wave-based task execution using code-developer subagent. Reads IMPL-*.json task files, computes execution waves from dependency graph, and executes sequentially by wave with parallel tasks within each wave.
## Purpose
Read IMPL-*.json task files for the current phase, compute wave groups from depends_on graph, and execute each task by delegating to a code-developer subagent. Produce summary-NN.md per task with structured YAML frontmatter for verifier and cross-task context.
## When to Use
- Phase 3 of executor execution (after loading tasks, before self-validation)
- Called once per EXEC-* task
## Strategy
Compute waves from dependency graph (topological sort). Sequential waves, parallel tasks within each wave. Each task is delegated to a code-developer subagent with the full task JSON plus prior summary context. After each task completes, a summary is written. After each wave completes, wave progress is reported.
## Parameters
| Parameter | Source | Description |
|-----------|--------|-------------|
| `sessionFolder` | From EXEC-* task description | Session artifact directory |
| `phaseNumber` | From EXEC-* task description | Phase number (1-based) |
| `tasks` | From executor Phase 2 | Parsed task JSON objects |
| `waves` | From executor Phase 2 | Wave-grouped task map |
| `waveNumbers` | From executor Phase 2 | Sorted wave number array |
| `priorSummaries` | From executor Phase 2 | Summaries from earlier phases |
## Execution Steps
### Step 1: Compute Waves from Dependency Graph
```javascript
// Tasks loaded in executor Phase 2 from .task/IMPL-*.json
// Compute wave assignment from depends_on graph
function computeWaves(tasks) {
const waveMap = {} // taskId → waveNumber
const assigned = new Set()
let currentWave = 1
while (assigned.size < tasks.length) {
const ready = tasks.filter(t =>
!assigned.has(t.id) &&
(t.depends_on || []).every(d => assigned.has(d))
)
if (ready.length === 0 && assigned.size < tasks.length) {
// Cycle detected — force lowest unassigned
const unassigned = tasks.find(t => !assigned.has(t.id))
ready.push(unassigned)
}
for (const task of ready) {
waveMap[task.id] = currentWave
assigned.add(task.id)
}
currentWave++
}
// Group by wave
const waves = {}
for (const task of tasks) {
const w = waveMap[task.id]
if (!waves[w]) waves[w] = []
waves[w].push(task)
}
return {
waves,
waveNumbers: Object.keys(waves).map(Number).sort((a, b) => a - b),
totalWaves: currentWave - 1
}
}
const { waves, waveNumbers, totalWaves } = computeWaves(tasks)
const totalTasks = tasks.length
let completedTasks = 0
```
### Step 2: Sequential Wave Execution
```javascript
for (const waveNum of waveNumbers) {
const waveTasks = waves[waveNum]
for (const task of waveTasks) {
const startTime = Date.now()
// 2a. Build context from prior summaries
const contextSummaries = []
// From earlier phases
for (const ps of priorSummaries) {
contextSummaries.push(ps.content)
}
// From earlier waves in this phase
for (const earlierWave of waveNumbers.filter(w => w < waveNum)) {
for (const earlierTask of waves[earlierWave]) {
try {
const summaryFile = `${sessionFolder}/phase-${phaseNumber}/summary-${earlierTask.id}.md`
contextSummaries.push(Read(summaryFile))
} catch {}
}
}
const contextSection = contextSummaries.length > 0
? `## Prior Context\n\n${contextSummaries.join('\n\n---\n\n')}`
: "## Prior Context\n\nNone (first task in first wave)."
// 2b. Build implementation prompt from task JSON
const filesSection = (task.files || [])
.map(f => `- \`${f.path}\` (${f.action}): ${f.change}`)
.join('\n')
const stepsSection = (task.implementation || [])
.map((step, i) => typeof step === 'string' ? `${i + 1}. ${step}` : `${i + 1}. ${step.step}: ${step.description}`)
.join('\n')
const convergenceSection = task.convergence
? `## Success Criteria\n${(task.convergence.criteria || []).map(c => `- ${c}`).join('\n')}\n\n**Verification**: ${task.convergence.verification || 'N/A'}`
: ''
// 2c. Delegate to code-developer subagent
const implResult = Task({
subagent_type: "code-developer",
run_in_background: false,
prompt: `Implement the following task. Write production-quality code following existing patterns.
## Task: ${task.id} - ${task.title}
${task.description}
## Files
${filesSection}
## Implementation Steps
${stepsSection}
${convergenceSection}
${contextSection}
## Implementation Rules
- Follow existing code patterns and conventions in the project
- Write clean, minimal code that satisfies the task requirements
- Create all files listed with action "create"
- Modify files listed with action "modify" as described
- Handle errors appropriately
- Do NOT add unnecessary features beyond what the task specifies
- Do NOT modify files outside the task scope unless absolutely necessary
## Output
After implementation, report:
1. Files created or modified (with brief description of changes)
2. Key decisions made during implementation
3. Any deviations from the task (and why)
4. Capabilities provided (exports, APIs, components)
5. Technologies/patterns used`
})
const duration = Math.round((Date.now() - startTime) / 60000)
// 2d. Write summary
const summaryPath = `${sessionFolder}/phase-${phaseNumber}/summary-${task.id}.md`
const affectedPaths = (task.files || []).map(f => f.path)
Write(summaryPath, `---
phase: ${phaseNumber}
task: "${task.id}"
title: "${task.title}"
requires: [${(task.depends_on || []).map(d => `"${d}"`).join(', ')}]
provides: ["${task.id}"]
affects:
${affectedPaths.map(p => ` - "${p}"`).join('\n')}
tech-stack: []
key-files:
${affectedPaths.map(p => ` - "${p}"`).join('\n')}
key-decisions: []
patterns-established: []
convergence-met: pending
duration: ${duration}m
completed: ${new Date().toISOString().slice(0, 19)}
---
# Summary: ${task.id} - ${task.title}
## Implementation Result
${implResult || "Implementation delegated to code-developer subagent."}
## Files Affected
${affectedPaths.map(p => `- \`${p}\``).join('\n')}
## Convergence Criteria
${(task.convergence?.criteria || []).map(c => `- [ ] ${c}`).join('\n')}
`)
completedTasks++
}
// 2e. Report wave progress
mcp__ccw-tools__team_msg({
operation: "log", team: "roadmap-dev",
from: "executor", to: "coordinator",
type: "exec_progress",
summary: `[executor] Wave ${waveNum}/${totalWaves} complete (${completedTasks}/${totalTasks} tasks done)`,
ref: `${sessionFolder}/phase-${phaseNumber}/`
})
}
```
### Step 3: Report Execution Complete
```javascript
mcp__ccw-tools__team_msg({
operation: "log", team: "roadmap-dev",
from: "executor", to: "coordinator",
type: "exec_complete",
summary: `[executor] All ${totalTasks} tasks executed across ${totalWaves} waves for phase ${phaseNumber}`,
ref: `${sessionFolder}/phase-${phaseNumber}/`
})
```
## Summary File Format
Each summary-{IMPL-ID}.md uses YAML frontmatter:
```yaml
---
phase: N
task: "IMPL-N"
title: "Task title"
requires: ["IMPL-N"]
provides: ["IMPL-N"]
affects: [paths]
tech-stack: [technologies]
key-files: [paths]
key-decisions: [decisions]
patterns-established: [patterns]
convergence-met: pending|pass|fail
duration: Xm
completed: timestamp
---
```
### Frontmatter Fields
| Field | Type | Description |
|-------|------|-------------|
| `phase` | number | Phase this summary belongs to |
| `task` | string | Task ID that was executed |
| `title` | string | Task title |
| `requires` | string[] | Dependency task IDs consumed |
| `provides` | string[] | Task ID provided to downstream |
| `affects` | string[] | File paths created or modified |
| `tech-stack` | string[] | Technologies/frameworks used |
| `key-files` | string[] | Primary files (subset of affects) |
| `key-decisions` | string[] | Decisions made during implementation |
| `patterns-established` | string[] | Patterns introduced |
| `convergence-met` | string | Whether convergence criteria passed |
| `duration` | string | Execution time |
| `completed` | string | ISO timestamp |
## Deviation Rules
| Deviation | Action | Report |
|-----------|--------|--------|
| **Bug found** in existing code | Auto-fix, continue | Log in summary key-decisions |
| **Missing critical** dependency | Add to scope, implement | Log in summary key-decisions |
| **Blocking dependency** (unresolvable) | Stop task execution | Report error to coordinator |
| **Architectural concern** | Do NOT auto-fix | Report error to coordinator, await guidance |
## Wave Execution Example
```
Phase 2, 4 tasks, 3 waves (computed from depends_on):
Wave 1: [IMPL-201 (types)] — no dependencies
-> delegate IMPL-201 to code-developer
-> write summary-IMPL-201.md
-> report: Wave 1/3 complete (1/4 tasks)
Wave 2: [IMPL-202 (API), IMPL-203 (UI)] — depend on IMPL-201
-> delegate IMPL-202 (loads summary-IMPL-201 as context)
-> write summary-IMPL-202.md
-> delegate IMPL-203 (loads summary-IMPL-201 as context)
-> write summary-IMPL-203.md
-> report: Wave 2/3 complete (3/4 tasks)
Wave 3: [IMPL-204 (tests)] — depends on IMPL-202, IMPL-203
-> delegate IMPL-204 (loads summaries 201-203 as context)
-> write summary-IMPL-204.md
-> report: Wave 3/3 complete (4/4 tasks)
-> report: exec_complete
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| code-developer subagent fails | Retry once. If still fails, write error summary, continue with next task |
| File write conflict | Last write wins. Log in summary. Verifier will validate |
| Task references non-existent file | Check if dependency task creates it. If yes, load summary. If no, log error |
| All tasks in a wave fail | Report wave failure to coordinator, attempt next wave |
| Summary write fails | Retry with Bash fallback. Critical — verifier needs summaries |

View File

@@ -0,0 +1,272 @@
# Role: executor
Code implementation per phase. Reads IMPL-*.json task files from the phase's .task/ directory, computes execution waves from the dependency graph, and executes sequentially by wave with parallel tasks within each wave. Each task is delegated to a code-developer subagent. Produces summary-{IMPL-ID}.md files for verifier consumption.
## Role Identity
- **Name**: `executor`
- **Task Prefix**: `EXEC-*`
- **Responsibility**: Code generation
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[executor]`
## Role Boundaries
### MUST
- All outputs must carry `[executor]` prefix
- Only process `EXEC-*` prefixed tasks
- Only communicate with coordinator (SendMessage)
- Delegate implementation to commands/implement.md
- Execute tasks in dependency order (sequential waves, parallel within wave)
- Write summary-{IMPL-ID}.md per task after execution
- Report wave progress to coordinator
### MUST NOT
- Create plans or modify IMPL-*.json task files
- Verify implementation against must_haves (that is verifier's job)
- Create tasks for other roles (TaskCreate)
- Interact with user (AskUserQuestion)
- Process PLAN-* or VERIFY-* tasks
- Skip loading prior summaries for cross-plan context
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `exec_complete` | executor -> coordinator | All plans executed | Implementation done, summaries written |
| `exec_progress` | executor -> coordinator | Wave completed | Wave N of M done |
| `error` | executor -> coordinator | Failure | Implementation failed |
## Message Bus
```javascript
mcp__ccw-tools__team_msg({
operation: "log", team: "roadmap-dev",
from: "executor", to: "coordinator",
type: messageType,
summary: `[executor] ${messageSummary}`,
ref: artifactPath
})
```
### CLI Fallback
```javascript
Bash(`ccw team log --team "roadmap-dev" --from "executor" --to "coordinator" --type "${type}" --summary "[executor] ${summary}" --json`)
```
## Toolbox
### Available Commands
| Command | File | Phase | Description |
|---------|------|-------|-------------|
| `implement` | [commands/implement.md](commands/implement.md) | Phase 3 | Wave-based plan execution via code-developer subagent |
### Available Subagents
| Subagent | Purpose | When |
|----------|---------|------|
| `code-developer` | Code implementation per plan | Phase 3: delegate each plan |
### CLI Tools
None. Executor delegates all implementation work to code-developer subagent.
## Execution
### Phase 1: Task Discovery
```javascript
// Find assigned EXEC-* task
const tasks = TaskList()
const execTask = tasks.find(t =>
t.subject.startsWith('EXEC-') &&
t.status === 'pending' &&
(!t.blockedBy || t.blockedBy.length === 0)
)
if (!execTask) {
mcp__ccw-tools__team_msg({
operation: "log", team: "roadmap-dev",
from: "executor", to: "coordinator",
type: "error",
summary: "[executor] No available EXEC-* task found"
})
return
}
TaskUpdate({ taskId: execTask.id, status: "in_progress" })
// Parse task description for session context
const taskDetails = TaskGet({ taskId: execTask.id })
const sessionFolder = parseSessionFolder(taskDetails.description)
const phaseNumber = parsePhaseNumber(taskDetails.description)
```
### Phase 2: Load Tasks
```javascript
// Read all task JSON files for this phase
const taskFiles = Glob(`${sessionFolder}/phase-${phaseNumber}/.task/IMPL-*.json`)
if (!taskFiles || taskFiles.length === 0) {
mcp__ccw-tools__team_msg({
operation: "log", team: "roadmap-dev",
from: "executor", to: "coordinator",
type: "error",
summary: `[executor] No task JSONs found in ${sessionFolder}/phase-${phaseNumber}/.task/`
})
return
}
// Parse all task JSONs
const tasks = []
for (const taskFile of taskFiles) {
const taskJson = JSON.parse(Read(taskFile))
tasks.push({
...taskJson,
file: taskFile
})
}
// Compute waves from dependency graph
function computeWaves(tasks) {
const waveMap = {}
const assigned = new Set()
let currentWave = 1
while (assigned.size < tasks.length) {
const ready = tasks.filter(t =>
!assigned.has(t.id) &&
(t.depends_on || []).every(d => assigned.has(d))
)
if (ready.length === 0 && assigned.size < tasks.length) {
const unassigned = tasks.find(t => !assigned.has(t.id))
ready.push(unassigned)
}
for (const task of ready) { waveMap[task.id] = currentWave; assigned.add(task.id) }
currentWave++
}
const waves = {}
for (const task of tasks) {
const w = waveMap[task.id]
if (!waves[w]) waves[w] = []
waves[w].push(task)
}
return { waves, waveNumbers: Object.keys(waves).map(Number).sort((a, b) => a - b) }
}
const { waves, waveNumbers } = computeWaves(tasks)
// Load prior summaries for cross-task context
const priorSummaries = []
for (let p = 1; p < phaseNumber; p++) {
try {
const summaryFiles = Glob(`${sessionFolder}/phase-${p}/summary-*.md`)
for (const sf of summaryFiles) {
priorSummaries.push({ phase: p, content: Read(sf) })
}
} catch {}
}
```
### Phase 3: Implement (via command)
```javascript
// Delegate to implement command
Read("commands/implement.md")
// Execute wave-based implementation:
// 1. Compute waves from depends_on graph
// 2. For each wave (sequential): execute all tasks in the wave
// 3. For each task in wave: delegate to code-developer subagent
// 4. Write summary-{IMPL-ID}.md per task
// 5. Report wave progress
//
// Produces: {sessionFolder}/phase-{N}/summary-IMPL-*.md
```
**Command**: [commands/implement.md](commands/implement.md)
### Phase 4: Self-Validation
```javascript
// Basic validation after implementation — NOT full verification (that is verifier's job)
const summaryFiles = Glob(`${sessionFolder}/phase-${phaseNumber}/summary-*.md`)
for (const summaryFile of summaryFiles) {
const summary = Read(summaryFile)
const frontmatter = parseYamlFrontmatter(summary)
const affectedFiles = frontmatter.affects || frontmatter['key-files'] || []
for (const filePath of affectedFiles) {
// 4a. Check file exists
const exists = Bash(`test -f "${filePath}" && echo "EXISTS" || echo "NOT_FOUND"`).trim()
if (exists === "NOT_FOUND") {
mcp__ccw-tools__team_msg({
operation: "log", team: "roadmap-dev",
from: "executor", to: "coordinator",
type: "error",
summary: `[executor] Expected file not found after implementation: ${filePath}`,
ref: summaryFile
})
}
// 4b. Syntax check (basic — language-aware)
if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
const syntaxCheck = Bash(`npx tsc --noEmit "${filePath}" 2>&1 || true`)
if (syntaxCheck.includes('error TS')) {
mcp__ccw-tools__team_msg({
operation: "log", team: "roadmap-dev",
from: "executor", to: "coordinator",
type: "error",
summary: `[executor] TypeScript syntax errors in ${filePath}`,
ref: summaryFile
})
}
}
}
}
// 4c. Run lint once for all changes (best-effort)
Bash(`npm run lint 2>&1 || yarn lint 2>&1 || true`)
```
### Phase 5: Report to Coordinator
```javascript
const taskCount = tasks.length
const waveCount = waveNumbers.length
const writtenSummaries = Glob(`${sessionFolder}/phase-${phaseNumber}/summary-*.md`)
mcp__ccw-tools__team_msg({
operation: "log", team: "roadmap-dev",
from: "executor", to: "coordinator",
type: "exec_complete",
summary: `[executor] Phase ${phaseNumber} executed: ${taskCount} tasks across ${waveCount} waves. ${writtenSummaries.length} summaries written.`,
ref: `${sessionFolder}/phase-${phaseNumber}/`
})
SendMessage({
to: "coordinator",
message: `[executor] Phase ${phaseNumber} execution complete.
- Tasks executed: ${taskCount}
- Waves: ${waveCount}
- Summaries: ${writtenSummaries.map(f => f).join(', ')}
Ready for verification.`
})
TaskUpdate({ taskId: execTask.id, status: "completed" })
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No task JSON files found | Error to coordinator -- planner may have failed |
| code-developer subagent fails | Retry once. If still fails, log error in summary, continue with next plan |
| Syntax errors after implementation | Log in summary, continue -- verifier will catch remaining issues |
| Missing dependency from earlier wave | Error to coordinator -- dependency graph may be incorrect |
| File conflict between parallel plans | Log warning, last write wins -- verifier will validate correctness |