mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-27 09:13:07 +08:00
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:
288
.claude/skills/team-roadmap-dev/SKILL.md
Normal file
288
.claude/skills/team-roadmap-dev/SKILL.md
Normal file
@@ -0,0 +1,288 @@
|
||||
---
|
||||
name: team-roadmap-dev
|
||||
description: Unified team skill for roadmap-driven development workflow. Coordinator discusses roadmap with user, then dispatches phased execution pipeline (plan → execute → verify). All roles invoke this skill with --role arg. Triggers on "team roadmap-dev".
|
||||
allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), TaskUpdate(*), TaskList(*), TaskGet(*), Task(*), AskUserQuestion(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
|
||||
---
|
||||
|
||||
# Team Roadmap Dev
|
||||
|
||||
Phased project execution team. Coordinator discusses roadmap with the user and manages phase transitions. Workers handle planning, execution, and verification per phase. Follows filesystem-based state machine pattern with fixed and dynamic artifacts.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────┐
|
||||
│ Skill(skill="team-roadmap-dev") │
|
||||
│ args="任务描述" 或 args="--role=xxx" │
|
||||
└───────────────────┬───────────────────────────┘
|
||||
│ Role Router
|
||||
│
|
||||
┌──── --role present? ────┐
|
||||
│ NO │ YES
|
||||
↓ ↓
|
||||
Orchestration Mode Role Dispatch
|
||||
(auto → coordinator) (route to role.md)
|
||||
│
|
||||
┌────┴────┬───────────┬───────────┐
|
||||
↓ ↓ ↓ ↓
|
||||
┌──────────┐┌─────────┐┌──────────┐┌──────────┐
|
||||
│coordinator││ planner ││ executor ││ verifier │
|
||||
│ (human ││ PLAN-* ││ EXEC-* ││ VERIFY-* │
|
||||
│ 交互) ││ ││ ││ │
|
||||
└──────────┘└─────────┘└──────────┘└──────────┘
|
||||
```
|
||||
|
||||
## Command Architecture
|
||||
|
||||
```
|
||||
roles/
|
||||
├── coordinator/
|
||||
│ ├── role.md # Orchestrator: roadmap discussion + phase management
|
||||
│ └── commands/
|
||||
│ ├── roadmap-discuss.md # Discuss roadmap with user, generate phase plan
|
||||
│ ├── dispatch.md # Create task chain per phase
|
||||
│ ├── monitor.md # Stop-Wait phase execution loop
|
||||
│ ├── pause.md # Save state and exit cleanly
|
||||
│ └── resume.md # Resume from paused session
|
||||
├── planner/
|
||||
│ ├── role.md # Research + task JSON generation per phase
|
||||
│ └── commands/
|
||||
│ ├── research.md # Context gathering + codebase exploration
|
||||
│ └── create-plans.md # action-planning-agent delegation → IMPL-*.json
|
||||
├── executor/
|
||||
│ ├── role.md # Task execution with wave parallelism
|
||||
│ └── commands/
|
||||
│ └── implement.md # Code implementation via code-developer
|
||||
└── verifier/
|
||||
├── role.md # Goal-backward verification
|
||||
└── commands/
|
||||
└── verify.md # Convergence criteria checking + gap detection
|
||||
```
|
||||
|
||||
## Role Router
|
||||
|
||||
### Input Parsing
|
||||
|
||||
```javascript
|
||||
const args = "$ARGUMENTS"
|
||||
const roleMatch = args.match(/--role[=\s]+(\w+)/)
|
||||
const resumeMatch = args.match(/--resume[=\s]+(.+?)(?:\s|$)/)
|
||||
const teamName = "roadmap-dev"
|
||||
|
||||
if (!roleMatch) {
|
||||
// No --role: Orchestration Mode → auto route to coordinator
|
||||
// If --resume present: coordinator handles resume via commands/resume.md
|
||||
}
|
||||
|
||||
const role = roleMatch ? roleMatch[1] : "coordinator"
|
||||
const agentName = args.match(/--agent-name[=\s]+([\w-]+)/)?.[1] || role
|
||||
```
|
||||
|
||||
### Role Dispatch
|
||||
|
||||
```javascript
|
||||
const VALID_ROLES = {
|
||||
"coordinator": { file: "roles/coordinator/role.md", prefix: null },
|
||||
"planner": { file: "roles/planner/role.md", prefix: "PLAN" },
|
||||
"executor": { file: "roles/executor/role.md", prefix: "EXEC" },
|
||||
"verifier": { file: "roles/verifier/role.md", prefix: "VERIFY" }
|
||||
}
|
||||
|
||||
if (!VALID_ROLES[role]) {
|
||||
throw new Error(`Unknown role: ${role}. Available: ${Object.keys(VALID_ROLES).join(', ')}`)
|
||||
}
|
||||
|
||||
Read(VALID_ROLES[role].file)
|
||||
```
|
||||
|
||||
### Orchestration Mode
|
||||
|
||||
```javascript
|
||||
if (!roleMatch) {
|
||||
const role = "coordinator"
|
||||
Read(VALID_ROLES[role].file)
|
||||
}
|
||||
```
|
||||
|
||||
### Available Roles
|
||||
|
||||
| Role | Task Prefix | Responsibility | Role File |
|
||||
|------|-------------|----------------|-----------|
|
||||
| `coordinator` | N/A | Human interaction, roadmap discussion, phase transitions, state management | [roles/coordinator/role.md](roles/coordinator/role.md) |
|
||||
| `planner` | PLAN-* | Research, context gathering, task JSON generation via action-planning-agent | [roles/planner/role.md](roles/planner/role.md) |
|
||||
| `executor` | EXEC-* | Code implementation following plans, wave-based parallel execution | [roles/executor/role.md](roles/executor/role.md) |
|
||||
| `verifier` | VERIFY-* | Convergence criteria verification, gap detection, fix loop trigger | [roles/verifier/role.md](roles/verifier/role.md) |
|
||||
|
||||
## Shared Infrastructure
|
||||
|
||||
### Artifact System
|
||||
|
||||
**Fixed Artifacts** (session-level, persist throughout session):
|
||||
|
||||
| Artifact | Path | Created By | Purpose |
|
||||
|----------|------|------------|---------|
|
||||
| roadmap.md | `{session}/roadmap.md` | coordinator (roadmap-discuss) | Phase plan with requirements and success criteria |
|
||||
| state.md | `{session}/state.md` | coordinator | Living memory (<100 lines), updated every significant action |
|
||||
| config.json | `{session}/config.json` | coordinator | Session settings: mode, depth, gates |
|
||||
|
||||
**Dynamic Artifacts** (per-phase, form execution history):
|
||||
|
||||
| Artifact | Path | Created By | Purpose |
|
||||
|----------|------|------------|---------|
|
||||
| context.md | `{session}/phase-N/context.md` | planner (research) | Phase context and requirements |
|
||||
| IMPL_PLAN.md | `{session}/phase-N/IMPL_PLAN.md` | planner (create-plans) | Implementation overview with task dependency graph |
|
||||
| IMPL-*.json | `{session}/phase-N/.task/IMPL-*.json` | planner (create-plans) | Task JSON files (unified flat schema with convergence criteria) |
|
||||
| TODO_LIST.md | `{session}/phase-N/TODO_LIST.md` | planner (create-plans) | Checklist tracking for all tasks |
|
||||
| summary-{ID}.md | `{session}/phase-N/summary-{IMPL-ID}.md` | executor (implement) | Execution record with requires/provides/convergence-met |
|
||||
| verification.md | `{session}/phase-N/verification.md` | verifier (verify) | Convergence criteria check results + gap list |
|
||||
|
||||
### Init Prerequisite
|
||||
|
||||
Coordinator **must** ensure `.workflow/project-tech.json` exists before starting. If not found, invoke `/workflow:init`.
|
||||
|
||||
### Team Configuration
|
||||
|
||||
```javascript
|
||||
const TEAM_CONFIG = {
|
||||
name: "roadmap-dev",
|
||||
sessionDir: ".workflow/.team/RD-{slug}-{date}/",
|
||||
msgDir: ".workflow/.team-msg/roadmap-dev/"
|
||||
}
|
||||
```
|
||||
|
||||
### Role Isolation Rules
|
||||
|
||||
#### Output Tagging
|
||||
|
||||
All outputs must carry `[role_name]` prefix.
|
||||
|
||||
#### Coordinator Isolation
|
||||
|
||||
| Allowed | Forbidden |
|
||||
|---------|-----------|
|
||||
| Discuss roadmap with user (AskUserQuestion) | Direct code writing/modification |
|
||||
| Create task chain (TaskCreate) | Calling implementation subagents |
|
||||
| Dispatch tasks to workers | Direct analysis/testing/verification |
|
||||
| Monitor progress (message bus) | Bypassing workers |
|
||||
| Report results to user | Modifying source code |
|
||||
|
||||
#### Worker Isolation
|
||||
|
||||
| Allowed | Forbidden |
|
||||
|---------|-----------|
|
||||
| Process own-prefix tasks only | Process other roles' tasks |
|
||||
| SendMessage to coordinator only | Direct worker-to-worker communication |
|
||||
| Use Toolbox-declared tools | TaskCreate for other roles |
|
||||
| Delegate to commands/*.md | Modify resources outside scope |
|
||||
|
||||
### Message Bus & Task Lifecycle
|
||||
|
||||
Each role's role.md contains self-contained Message Bus and Task Lifecycle. See `roles/{role}/role.md`.
|
||||
|
||||
## Pipeline
|
||||
|
||||
```
|
||||
Phase N lifecycle:
|
||||
Coordinator (roadmap-discuss → dispatch phase N)
|
||||
→ PLAN-N01: Planner (research → action-planning-agent → IMPL-*.json)
|
||||
→ EXEC-N01: Executor (load IMPL-*.json → wave-based code-developer)
|
||||
→ VERIFY-N01: Verifier (convergence criteria check)
|
||||
→ Coordinator (transition: gap closure or next phase)
|
||||
|
||||
Cross-phase flow:
|
||||
Init → Roadmap Discussion → Phase 1 → Phase 2 → ... → Phase N → Complete
|
||||
↑ |
|
||||
└── gap closure loop ──────┘
|
||||
|
||||
Session lifecycle:
|
||||
Running → Pause (save coordinates) → Resume (re-enter monitor at coordinates)
|
||||
```
|
||||
|
||||
## Coordinator Spawn Template
|
||||
|
||||
```javascript
|
||||
TeamCreate({ team_name: "roadmap-dev" })
|
||||
|
||||
// Planner
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
team_name: "roadmap-dev",
|
||||
name: "planner",
|
||||
prompt: `你是 team "roadmap-dev" 的 PLANNER。
|
||||
|
||||
## 首要指令(MUST)
|
||||
Skill(skill="team-roadmap-dev", args="--role=planner")
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
Session: ${sessionFolder}
|
||||
|
||||
## 角色准则
|
||||
- 只处理 PLAN-* 前缀任务
|
||||
- 所有输出带 [planner] 标识
|
||||
- 仅与 coordinator 通信
|
||||
|
||||
## 工作流程
|
||||
1. Skill(skill="team-roadmap-dev", args="--role=planner")
|
||||
2. TaskList → PLAN-* 任务 → 执行 → 汇报
|
||||
3. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
|
||||
// Executor
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
team_name: "roadmap-dev",
|
||||
name: "executor",
|
||||
prompt: `你是 team "roadmap-dev" 的 EXECUTOR。
|
||||
|
||||
## 首要指令(MUST)
|
||||
Skill(skill="team-roadmap-dev", args="--role=executor")
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
Session: ${sessionFolder}
|
||||
|
||||
## 角色准则
|
||||
- 只处理 EXEC-* 前缀任务
|
||||
- 所有输出带 [executor] 标识
|
||||
- 仅与 coordinator 通信
|
||||
|
||||
## 工作流程
|
||||
1. Skill(skill="team-roadmap-dev", args="--role=executor")
|
||||
2. TaskList → EXEC-* 任务 → 执行 → 汇报
|
||||
3. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
|
||||
// Verifier
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
team_name: "roadmap-dev",
|
||||
name: "verifier",
|
||||
prompt: `你是 team "roadmap-dev" 的 VERIFIER。
|
||||
|
||||
## 首要指令(MUST)
|
||||
Skill(skill="team-roadmap-dev", args="--role=verifier")
|
||||
|
||||
当前需求: ${taskDescription}
|
||||
Session: ${sessionFolder}
|
||||
|
||||
## 角色准则
|
||||
- 只处理 VERIFY-* 前缀任务
|
||||
- 所有输出带 [verifier] 标识
|
||||
- 仅与 coordinator 通信
|
||||
|
||||
## 工作流程
|
||||
1. Skill(skill="team-roadmap-dev", args="--role=verifier")
|
||||
2. TaskList → VERIFY-* 任务 → 执行 → 汇报
|
||||
3. TaskUpdate completed → 检查下一个任务`
|
||||
})
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Unknown --role value | Error with available role list |
|
||||
| Missing --role arg | Orchestration Mode → auto route to coordinator |
|
||||
| Role file not found | Error with expected path |
|
||||
| project-tech.json missing | Coordinator invokes /workflow:init |
|
||||
| Phase verification fails with gaps | Coordinator triggers gap closure loop |
|
||||
| Max gap closure iterations (3) | Report to user, ask for guidance |
|
||||
@@ -0,0 +1,213 @@
|
||||
# Command: dispatch
|
||||
|
||||
Create task chain for a specific phase. Each phase gets a PLAN -> EXEC -> VERIFY pipeline with dependency ordering.
|
||||
|
||||
## Purpose
|
||||
|
||||
Read the roadmap and create a linked task chain (PLAN -> EXEC -> VERIFY) for a given phase number. Tasks are assigned to the appropriate worker roles and linked via blockedBy dependencies.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Source | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `phaseNumber` | From coordinator | Phase to dispatch (1-based) |
|
||||
| `sessionFolder` | From coordinator | Session artifact directory |
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Read Roadmap and Extract Phase Requirements
|
||||
|
||||
```javascript
|
||||
const roadmap = Read(`${sessionFolder}/roadmap.md`)
|
||||
const config = JSON.parse(Read(`${sessionFolder}/config.json`))
|
||||
|
||||
// Parse phase section from roadmap
|
||||
// Extract: goal, requirements (REQ-IDs), success criteria
|
||||
const phaseGoal = extractPhaseGoal(roadmap, phaseNumber)
|
||||
const phaseRequirements = extractPhaseRequirements(roadmap, phaseNumber)
|
||||
const phaseSuccessCriteria = extractPhaseSuccessCriteria(roadmap, phaseNumber)
|
||||
```
|
||||
|
||||
### Step 2: Create Phase Directory
|
||||
|
||||
```javascript
|
||||
Bash(`mkdir -p "${sessionFolder}/phase-${phaseNumber}"`)
|
||||
```
|
||||
|
||||
### Step 3: Create PLAN Task (Assigned to Planner)
|
||||
|
||||
```javascript
|
||||
const planTaskId = TaskCreate({
|
||||
subject: `PLAN-${phaseNumber}01: Plan phase ${phaseNumber} - ${phaseGoal}`,
|
||||
description: `[coordinator] Plan creation for phase ${phaseNumber}.
|
||||
|
||||
## Session
|
||||
- Folder: ${sessionFolder}
|
||||
- Phase: ${phaseNumber}
|
||||
- Depth: ${config.depth}
|
||||
|
||||
## Phase Goal
|
||||
${phaseGoal}
|
||||
|
||||
## Requirements
|
||||
${phaseRequirements.map(r => `- ${r}`).join('\n')}
|
||||
|
||||
## Success Criteria
|
||||
${phaseSuccessCriteria.map(c => `- ${c}`).join('\n')}
|
||||
|
||||
## Deliverables
|
||||
- ${sessionFolder}/phase-${phaseNumber}/context.md (research context)
|
||||
- ${sessionFolder}/phase-${phaseNumber}/plan-01.md (execution plan with waves and must_haves)
|
||||
|
||||
## Instructions
|
||||
1. Invoke Skill(skill="team-roadmap-dev", args="--role=planner")
|
||||
2. Follow planner role.md research + create-plans commands
|
||||
3. Use roadmap requirements as input for plan generation
|
||||
4. TaskUpdate this task to completed when plan is written`,
|
||||
activeForm: `Planning phase ${phaseNumber}`
|
||||
})
|
||||
```
|
||||
|
||||
### Step 4: Create EXEC Task (Assigned to Executor, Blocked by PLAN)
|
||||
|
||||
```javascript
|
||||
const execTaskId = TaskCreate({
|
||||
subject: `EXEC-${phaseNumber}01: Execute phase ${phaseNumber} - ${phaseGoal}`,
|
||||
description: `[coordinator] Execute plans for phase ${phaseNumber}.
|
||||
|
||||
## Session
|
||||
- Folder: ${sessionFolder}
|
||||
- Phase: ${phaseNumber}
|
||||
|
||||
## Phase Goal
|
||||
${phaseGoal}
|
||||
|
||||
## Plan Reference
|
||||
- ${sessionFolder}/phase-${phaseNumber}/plan-01.md (and any additional plans)
|
||||
|
||||
## Instructions
|
||||
1. Invoke Skill(skill="team-roadmap-dev", args="--role=executor")
|
||||
2. Follow executor role.md implement command
|
||||
3. Execute all plans in wave order
|
||||
4. Write summary to ${sessionFolder}/phase-${phaseNumber}/summary-01.md
|
||||
5. TaskUpdate this task to completed when all plans executed`,
|
||||
activeForm: `Executing phase ${phaseNumber}`
|
||||
})
|
||||
|
||||
// Set dependency: EXEC blocked by PLAN
|
||||
TaskUpdate({ taskId: execTaskId, addBlockedBy: [planTaskId] })
|
||||
```
|
||||
|
||||
### Step 5: Create VERIFY Task (Assigned to Verifier, Blocked by EXEC)
|
||||
|
||||
```javascript
|
||||
const verifyTaskId = TaskCreate({
|
||||
subject: `VERIFY-${phaseNumber}01: Verify phase ${phaseNumber} - ${phaseGoal}`,
|
||||
description: `[coordinator] Verify phase ${phaseNumber} against success criteria.
|
||||
|
||||
## Session
|
||||
- Folder: ${sessionFolder}
|
||||
- Phase: ${phaseNumber}
|
||||
|
||||
## Phase Goal
|
||||
${phaseGoal}
|
||||
|
||||
## Success Criteria (from roadmap)
|
||||
${phaseSuccessCriteria.map(c => `- ${c}`).join('\n')}
|
||||
|
||||
## References
|
||||
- Roadmap: ${sessionFolder}/roadmap.md
|
||||
- Plans: ${sessionFolder}/phase-${phaseNumber}/plan-*.md
|
||||
- Summaries: ${sessionFolder}/phase-${phaseNumber}/summary-*.md
|
||||
|
||||
## Instructions
|
||||
1. Invoke Skill(skill="team-roadmap-dev", args="--role=verifier")
|
||||
2. Follow verifier role.md verify command
|
||||
3. Check each success criterion against actual implementation
|
||||
4. Write verification to ${sessionFolder}/phase-${phaseNumber}/verification.md
|
||||
5. If gaps found: list them with gap IDs in verification.md
|
||||
6. TaskUpdate this task to completed with result (passed/gaps_found)`,
|
||||
activeForm: `Verifying phase ${phaseNumber}`
|
||||
})
|
||||
|
||||
// Set dependency: VERIFY blocked by EXEC
|
||||
TaskUpdate({ taskId: verifyTaskId, addBlockedBy: [execTaskId] })
|
||||
```
|
||||
|
||||
### Step 6: Update state.md
|
||||
|
||||
```javascript
|
||||
Edit(`${sessionFolder}/state.md`, {
|
||||
old_string: `- Phase: ${phaseNumber}\n- Status: ready_to_dispatch`,
|
||||
new_string: `- Phase: ${phaseNumber}\n- Status: in_progress\n- Tasks: PLAN-${phaseNumber}01 → EXEC-${phaseNumber}01 → VERIFY-${phaseNumber}01`
|
||||
})
|
||||
```
|
||||
|
||||
### Step 7: Log Dispatch Message
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "coordinator", to: "all",
|
||||
type: "phase_started",
|
||||
summary: `[coordinator] Phase ${phaseNumber} dispatched: PLAN-${phaseNumber}01 → EXEC-${phaseNumber}01 → VERIFY-${phaseNumber}01`,
|
||||
ref: `${sessionFolder}/roadmap.md`
|
||||
})
|
||||
```
|
||||
|
||||
## Task Description Format
|
||||
|
||||
All dispatched tasks follow this structure:
|
||||
|
||||
```
|
||||
[coordinator] {action} for phase {N}.
|
||||
|
||||
## Session
|
||||
- Folder: {sessionFolder}
|
||||
- Phase: {N}
|
||||
- Depth: {config.depth} (PLAN only)
|
||||
|
||||
## Phase Goal
|
||||
{goal from roadmap}
|
||||
|
||||
## Requirements / Success Criteria
|
||||
{from roadmap}
|
||||
|
||||
## Deliverables
|
||||
{expected output files}
|
||||
|
||||
## Instructions
|
||||
{step-by-step for the worker role}
|
||||
```
|
||||
|
||||
## Task Naming Convention
|
||||
|
||||
| Task | Name Pattern | Example |
|
||||
|------|-------------|---------|
|
||||
| Plan | `PLAN-{phase}01` | PLAN-101 |
|
||||
| Execute | `EXEC-{phase}01` | EXEC-101 |
|
||||
| Verify | `VERIFY-{phase}01` | VERIFY-101 |
|
||||
| Gap Plan | `PLAN-{phase}02` | PLAN-102 (gap closure iteration 1) |
|
||||
| Gap Execute | `EXEC-{phase}02` | EXEC-102 |
|
||||
| Gap Verify | `VERIFY-{phase}02` | VERIFY-102 |
|
||||
|
||||
## Dependency Chain
|
||||
|
||||
```
|
||||
PLAN-{N}01 ←── EXEC-{N}01 ←── VERIFY-{N}01
|
||||
(planner) (executor) (verifier)
|
||||
```
|
||||
|
||||
Each task is blocked by its predecessor. Workers pick up tasks only when their blockedBy list is empty.
|
||||
|
||||
## Output
|
||||
|
||||
Returns the three task IDs as a structured result:
|
||||
|
||||
```javascript
|
||||
{
|
||||
planTaskId: planTaskId,
|
||||
execTaskId: execTaskId,
|
||||
verifyTaskId: verifyTaskId
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,375 @@
|
||||
# Command: monitor
|
||||
|
||||
Stop-Wait phase execution loop. Spawns workers synchronously and manages phase transitions.
|
||||
|
||||
## Purpose
|
||||
|
||||
Execute all roadmap phases sequentially using the Stop-Wait pattern. The coordinator spawns each worker synchronously (run_in_background: false), waits for completion, then proceeds to the next step. Handles gap closure loops and phase transitions.
|
||||
|
||||
## Design Principle
|
||||
|
||||
Models have no concept of time. Polling, sleeping, and periodic checking are forbidden. All coordination uses synchronous Task() calls where worker return = step done.
|
||||
|
||||
## Strategy
|
||||
|
||||
Sequential spawning -- coordinator spawns one worker at a time via synchronous Task() calls. Each worker processes its task and returns. The coordinator inspects the result and decides the next action.
|
||||
|
||||
```
|
||||
Coordinator ──spawn──→ Planner (blocks until done)
|
||||
←─return──
|
||||
──spawn──→ Executor (blocks until done)
|
||||
←─return──
|
||||
──spawn──→ Verifier (blocks until done)
|
||||
←─return──
|
||||
──decide──→ next phase or gap closure
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Source | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `sessionFolder` | From coordinator | Session artifact directory |
|
||||
| `roadmap` | From roadmap.md | Parsed phase list |
|
||||
| `config` | From config.json | Execution mode and gates |
|
||||
| `resumePhase` | From resume command (optional) | Phase to resume from |
|
||||
| `resumeStep` | From resume command (optional) | Step within phase to resume from (plan/exec/verify/gap_closure) |
|
||||
| `resumeGapIteration` | From resume command (optional) | Gap iteration to resume from |
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Load Session State
|
||||
|
||||
```javascript
|
||||
const roadmap = Read(`${sessionFolder}/roadmap.md`)
|
||||
const config = JSON.parse(Read(`${sessionFolder}/config.json`))
|
||||
const state = Read(`${sessionFolder}/state.md`)
|
||||
|
||||
const totalPhases = countPhases(roadmap)
|
||||
|
||||
// Support resume: use resume coordinates if provided, else parse from state
|
||||
const currentPhase = resumePhase || parseCurrentPhase(state)
|
||||
const startStep = resumeStep || 'plan' // plan|exec|verify|gap_closure
|
||||
const startGapIteration = resumeGapIteration || 0
|
||||
```
|
||||
|
||||
### Step 2: Phase Loop
|
||||
|
||||
```javascript
|
||||
for (let phase = currentPhase; phase <= totalPhases; phase++) {
|
||||
|
||||
// --- Phase N execution ---
|
||||
|
||||
// 2a. Dispatch task chain (if not already dispatched)
|
||||
// Read("commands/dispatch.md") → creates PLAN/EXEC/VERIFY tasks
|
||||
dispatch(phase, sessionFolder)
|
||||
|
||||
let phaseComplete = false
|
||||
let gapIteration = 0
|
||||
const MAX_GAP_ITERATIONS = 3
|
||||
|
||||
while (!phaseComplete && gapIteration <= MAX_GAP_ITERATIONS) {
|
||||
|
||||
// 2b. Spawn Planner (Stop-Wait)
|
||||
const planResult = spawnPlanner(phase, gapIteration, sessionFolder)
|
||||
|
||||
// 2c. Gate: plan_check (if configured)
|
||||
if (config.gates.plan_check && gapIteration === 0) {
|
||||
const plans = Glob(`${sessionFolder}/phase-${phase}/plan-*.md`)
|
||||
// Present plan summary to user
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: `Phase ${phase} plan ready. Proceed with execution?`,
|
||||
header: "Plan Review",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "Proceed", description: "Execute the plan as-is" },
|
||||
{ label: "Revise", description: "Ask planner to revise" },
|
||||
{ label: "Skip phase", description: "Skip this phase entirely" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
// Handle "Revise" → re-spawn planner
|
||||
// Handle "Skip phase" → break to next phase
|
||||
}
|
||||
|
||||
// 2d. Spawn Executor (Stop-Wait)
|
||||
const execResult = spawnExecutor(phase, gapIteration, sessionFolder)
|
||||
|
||||
// 2e. Spawn Verifier (Stop-Wait)
|
||||
const verifyResult = spawnVerifier(phase, gapIteration, sessionFolder)
|
||||
|
||||
// 2f. Check verification result
|
||||
const verification = Read(`${sessionFolder}/phase-${phase}/verification.md`)
|
||||
const gapsFound = parseGapsFound(verification)
|
||||
|
||||
if (!gapsFound || gapsFound.length === 0) {
|
||||
// Phase passed
|
||||
phaseComplete = true
|
||||
} else if (gapIteration < MAX_GAP_ITERATIONS) {
|
||||
// Gap closure: create new task chain for gaps
|
||||
gapIteration++
|
||||
triggerGapClosure(phase, gapIteration, gapsFound, sessionFolder)
|
||||
} else {
|
||||
// Max iterations reached, report to user
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: `Phase ${phase} still has ${gapsFound.length} gaps after ${MAX_GAP_ITERATIONS} attempts. How to proceed?`,
|
||||
header: "Gap Closure Limit",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "Continue anyway", description: "Accept current state, move to next phase" },
|
||||
{ label: "Retry once more", description: "One more gap closure attempt" },
|
||||
{ label: "Stop", description: "Halt execution for manual intervention" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
// Handle user choice
|
||||
phaseComplete = true // or stop based on choice
|
||||
}
|
||||
}
|
||||
|
||||
// 2g. Phase transition
|
||||
updateStatePhaseComplete(phase, sessionFolder)
|
||||
|
||||
// 2h. Interactive gate at phase boundary
|
||||
if (config.mode === "interactive" && phase < totalPhases) {
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: `Phase ${phase} complete. Proceed to phase ${phase + 1}?`,
|
||||
header: "Phase Transition",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "Proceed", description: `Start phase ${phase + 1}` },
|
||||
{ label: "Review results", description: "Show phase summary before continuing" },
|
||||
{ label: "Stop", description: "Pause execution here" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
// Handle "Review results" → display summary, then re-ask
|
||||
// Handle "Stop" → invoke pause command
|
||||
if (userChoice === "Stop") {
|
||||
Read("commands/pause.md")
|
||||
// Execute pause: save state with currentPhase, currentStep, gapIteration
|
||||
pauseSession(phase, "transition", gapIteration, sessionFolder)
|
||||
return // Exit monitor loop
|
||||
}
|
||||
}
|
||||
// If mode === "yolo": auto-advance, no user interaction
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Spawn Functions (Stop-Wait Pattern)
|
||||
|
||||
#### Spawn Planner
|
||||
|
||||
```javascript
|
||||
function spawnPlanner(phase, gapIteration, sessionFolder) {
|
||||
const suffix = gapIteration === 0 ? "01" : `0${gapIteration + 1}`
|
||||
const gapContext = gapIteration > 0
|
||||
? `\nGap closure iteration ${gapIteration}. Fix gaps from: ${sessionFolder}/phase-${phase}/verification.md`
|
||||
: ""
|
||||
|
||||
// Synchronous call - blocks until planner returns
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
team_name: "roadmap-dev",
|
||||
name: "planner",
|
||||
prompt: `You are the PLANNER for team "roadmap-dev".
|
||||
|
||||
## Primary Directive
|
||||
Skill(skill="team-roadmap-dev", args="--role=planner")
|
||||
|
||||
## Assignment
|
||||
- Session: ${sessionFolder}
|
||||
- Phase: ${phase}
|
||||
- Task: PLAN-${phase}${suffix}${gapContext}
|
||||
|
||||
## Workflow
|
||||
1. Skill(skill="team-roadmap-dev", args="--role=planner")
|
||||
2. TaskList → find PLAN-${phase}${suffix} → execute
|
||||
3. TaskUpdate completed when done
|
||||
|
||||
All outputs carry [planner] tag.`,
|
||||
run_in_background: false // CRITICAL: Stop-Wait, blocks until done
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
#### Spawn Executor
|
||||
|
||||
```javascript
|
||||
function spawnExecutor(phase, gapIteration, sessionFolder) {
|
||||
const suffix = gapIteration === 0 ? "01" : `0${gapIteration + 1}`
|
||||
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
team_name: "roadmap-dev",
|
||||
name: "executor",
|
||||
prompt: `You are the EXECUTOR for team "roadmap-dev".
|
||||
|
||||
## Primary Directive
|
||||
Skill(skill="team-roadmap-dev", args="--role=executor")
|
||||
|
||||
## Assignment
|
||||
- Session: ${sessionFolder}
|
||||
- Phase: ${phase}
|
||||
- Task: EXEC-${phase}${suffix}
|
||||
|
||||
## Workflow
|
||||
1. Skill(skill="team-roadmap-dev", args="--role=executor")
|
||||
2. TaskList → find EXEC-${phase}${suffix} → execute plans
|
||||
3. TaskUpdate completed when done
|
||||
|
||||
All outputs carry [executor] tag.`,
|
||||
run_in_background: false // CRITICAL: Stop-Wait
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
#### Spawn Verifier
|
||||
|
||||
```javascript
|
||||
function spawnVerifier(phase, gapIteration, sessionFolder) {
|
||||
const suffix = gapIteration === 0 ? "01" : `0${gapIteration + 1}`
|
||||
|
||||
Task({
|
||||
subagent_type: "general-purpose",
|
||||
team_name: "roadmap-dev",
|
||||
name: "verifier",
|
||||
prompt: `You are the VERIFIER for team "roadmap-dev".
|
||||
|
||||
## Primary Directive
|
||||
Skill(skill="team-roadmap-dev", args="--role=verifier")
|
||||
|
||||
## Assignment
|
||||
- Session: ${sessionFolder}
|
||||
- Phase: ${phase}
|
||||
- Task: VERIFY-${phase}${suffix}
|
||||
|
||||
## Workflow
|
||||
1. Skill(skill="team-roadmap-dev", args="--role=verifier")
|
||||
2. TaskList → find VERIFY-${phase}${suffix} → verify against success criteria
|
||||
3. TaskUpdate completed when done
|
||||
|
||||
All outputs carry [verifier] tag.`,
|
||||
run_in_background: false // CRITICAL: Stop-Wait
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Gap Closure
|
||||
|
||||
```javascript
|
||||
function triggerGapClosure(phase, iteration, gaps, sessionFolder) {
|
||||
const suffix = `0${iteration + 1}`
|
||||
|
||||
// Log gap closure initiation
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "coordinator", to: "planner",
|
||||
type: "gap_closure",
|
||||
summary: `[coordinator] Gap closure iteration ${iteration} for phase ${phase}: ${gaps.length} gaps`,
|
||||
ref: `${sessionFolder}/phase-${phase}/verification.md`
|
||||
})
|
||||
|
||||
// Create new task chain for gap closure
|
||||
// PLAN-{phase}{suffix}: re-plan focusing on gaps only
|
||||
TaskCreate({
|
||||
subject: `PLAN-${phase}${suffix}: Gap closure for phase ${phase} (iteration ${iteration})`,
|
||||
description: `[coordinator] Gap closure re-planning for phase ${phase}.
|
||||
|
||||
## Session
|
||||
- Folder: ${sessionFolder}
|
||||
- Phase: ${phase}
|
||||
- Gap Iteration: ${iteration}
|
||||
|
||||
## Gaps to Address
|
||||
${gaps.map(g => `- ${g}`).join('\n')}
|
||||
|
||||
## Reference
|
||||
- Original verification: ${sessionFolder}/phase-${phase}/verification.md
|
||||
- Previous plans: ${sessionFolder}/phase-${phase}/plan-*.md
|
||||
|
||||
## Instructions
|
||||
1. Focus ONLY on the listed gaps -- do not re-plan completed work
|
||||
2. Create ${sessionFolder}/phase-${phase}/plan-${suffix}.md for gap fixes
|
||||
3. TaskUpdate completed when gap plan is written`,
|
||||
activeForm: `Re-planning phase ${phase} gaps (iteration ${iteration})`
|
||||
})
|
||||
|
||||
// EXEC and VERIFY tasks follow same pattern with blockedBy
|
||||
// (same as dispatch.md Step 4 and Step 5, with gap suffix)
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: State Updates
|
||||
|
||||
```javascript
|
||||
function updateStatePhaseComplete(phase, sessionFolder) {
|
||||
const state = Read(`${sessionFolder}/state.md`)
|
||||
|
||||
// Update current phase status
|
||||
Edit(`${sessionFolder}/state.md`, {
|
||||
old_string: `- Phase: ${phase}\n- Status: in_progress`,
|
||||
new_string: `- Phase: ${phase}\n- Status: completed\n- Completed: ${new Date().toISOString().slice(0, 19)}`
|
||||
})
|
||||
|
||||
// If more phases remain, set next phase as ready
|
||||
const nextPhase = phase + 1
|
||||
if (nextPhase <= totalPhases) {
|
||||
// Append next phase readiness
|
||||
Edit(`${sessionFolder}/state.md`, {
|
||||
old_string: `- Phase: ${phase}\n- Status: completed`,
|
||||
new_string: `- Phase: ${phase}\n- Status: completed\n\n- Phase: ${nextPhase}\n- Status: ready_to_dispatch`
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 6: Completion
|
||||
|
||||
```javascript
|
||||
// All phases done -- return control to coordinator Phase 5 (Report + Persist)
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "coordinator", to: "all",
|
||||
type: "project_complete",
|
||||
summary: `[coordinator] All ${totalPhases} phases complete.`,
|
||||
ref: `${sessionFolder}/roadmap.md`
|
||||
})
|
||||
```
|
||||
|
||||
## Gap Closure Loop Diagram
|
||||
|
||||
```
|
||||
VERIFY-{N}01 → gaps_found?
|
||||
│ NO → Phase complete → next phase
|
||||
│ YES ↓
|
||||
PLAN-{N}02 (gaps only) → EXEC-{N}02 → VERIFY-{N}02
|
||||
│ gaps_found?
|
||||
│ NO → Phase complete
|
||||
│ YES ↓
|
||||
PLAN-{N}03 → EXEC-{N}03 → VERIFY-{N}03
|
||||
│ gaps_found?
|
||||
│ NO → Phase complete
|
||||
│ YES → Max iterations (3) → ask user
|
||||
```
|
||||
|
||||
## Forbidden Patterns
|
||||
|
||||
| Pattern | Why Forbidden | Alternative |
|
||||
|---------|---------------|-------------|
|
||||
| `setTimeout` / `sleep` | Models have no time concept | Synchronous Task() return |
|
||||
| `setInterval` / polling loop | Wastes tokens, unreliable | Stop-Wait spawn pattern |
|
||||
| `TaskOutput` with sleep polling | Indirect, fragile | `run_in_background: false` |
|
||||
| `while (!done) { check() }` | Busy wait, no progress | Sequential synchronous calls |
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Worker Task() throws error | Log error, retry once. If still fails, report to user |
|
||||
| Verification file missing | Treat as gap -- verifier may have crashed, re-spawn |
|
||||
| Phase dispatch fails | Check roadmap integrity, report to user |
|
||||
| User chooses "Stop" at gate | Invoke pause command: save state.md with coordinates, exit cleanly |
|
||||
| Max gap iterations exceeded | Present to user with gap details, ask for guidance |
|
||||
@@ -0,0 +1,91 @@
|
||||
# Command: pause
|
||||
|
||||
Save session state and exit cleanly. Allows resumption later via resume command.
|
||||
|
||||
## Purpose
|
||||
|
||||
Persist the current execution state (phase, step, pending tasks) to state.md so the session can be resumed from exactly where it stopped. This is the coordinator's mechanism for handling user "Stop" requests at phase boundaries or gap closure gates.
|
||||
|
||||
## When to Use
|
||||
|
||||
- User selects "Stop" at any interactive gate in monitor.md
|
||||
- User requests pause during roadmap discussion
|
||||
- External interruption requires graceful shutdown
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Source | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `sessionFolder` | From coordinator | Session artifact directory |
|
||||
| `currentPhase` | From monitor loop | Phase number at pause time |
|
||||
| `currentStep` | From monitor loop | Step within phase (plan/exec/verify/gap_closure) |
|
||||
| `gapIteration` | From monitor loop | Current gap closure iteration (0 = none) |
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Capture Current State
|
||||
|
||||
```javascript
|
||||
const state = Read(`${sessionFolder}/state.md`)
|
||||
const timestamp = new Date().toISOString().slice(0, 19)
|
||||
|
||||
// Capture pending task states
|
||||
const allTasks = TaskList()
|
||||
const pendingTasks = allTasks.filter(t =>
|
||||
t.status === 'pending' || t.status === 'in_progress'
|
||||
)
|
||||
```
|
||||
|
||||
### Step 2: Update state.md with Pause Marker
|
||||
|
||||
```javascript
|
||||
// Find the current phase status line and update it
|
||||
Edit(`${sessionFolder}/state.md`, {
|
||||
old_string: `- Status: in_progress`,
|
||||
new_string: `- Status: paused
|
||||
- Paused At: ${timestamp}
|
||||
- Paused Phase: ${currentPhase}
|
||||
- Paused Step: ${currentStep}
|
||||
- Gap Iteration: ${gapIteration}
|
||||
- Pending Tasks: ${pendingTasks.map(t => t.subject).join(', ')}`
|
||||
})
|
||||
```
|
||||
|
||||
### Step 3: Log Pause Event
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "coordinator", to: "all",
|
||||
type: "phase_paused",
|
||||
summary: `[coordinator] Session paused at phase ${currentPhase}, step: ${currentStep}`,
|
||||
ref: `${sessionFolder}/state.md`
|
||||
})
|
||||
```
|
||||
|
||||
### Step 4: Report to User
|
||||
|
||||
```javascript
|
||||
// Output pause summary
|
||||
const summary = `[coordinator] Session paused.
|
||||
- Phase: ${currentPhase}
|
||||
- Step: ${currentStep}
|
||||
- Gap Iteration: ${gapIteration}
|
||||
- Pending Tasks: ${pendingTasks.length}
|
||||
|
||||
To resume: Skill(skill="team-roadmap-dev", args="--resume ${sessionFolder}")
|
||||
`
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
| Artifact | Path | Description |
|
||||
|----------|------|-------------|
|
||||
| state.md | `{sessionFolder}/state.md` | Updated with paused status and resume coordinates |
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| state.md edit fails | Write full state.md from scratch with pause info |
|
||||
| Task list unavailable | Record phase/step only, skip task listing |
|
||||
@@ -0,0 +1,138 @@
|
||||
# Command: resume
|
||||
|
||||
Resume a paused roadmap-dev session from its saved state. Reads pause coordinates from state.md and re-enters the monitor loop at the exact phase and step where execution was paused.
|
||||
|
||||
## Purpose
|
||||
|
||||
Restore execution context from a paused session and continue the monitor loop. This is the coordinator's mechanism for resuming long-running projects across sessions.
|
||||
|
||||
## When to Use
|
||||
|
||||
- User invokes `Skill(skill="team-roadmap-dev", args="--resume {sessionFolder}")`
|
||||
- Coordinator detects a paused session during init
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Source | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `sessionFolder` | From --resume argument | Session artifact directory to resume |
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Validate Session State
|
||||
|
||||
```javascript
|
||||
const stateContent = Read(`${sessionFolder}/state.md`)
|
||||
|
||||
// Check for paused status
|
||||
if (!stateContent.includes('Status: paused')) {
|
||||
// Session is not paused — check if it's in_progress or completed
|
||||
if (stateContent.includes('Status: completed')) {
|
||||
// Session already finished
|
||||
return { error: "Session already completed", sessionFolder }
|
||||
}
|
||||
// Not paused, not completed — treat as fresh continue
|
||||
}
|
||||
|
||||
// Parse resume coordinates
|
||||
const pausedPhase = parseInt(stateContent.match(/Paused Phase: (\d+)/)?.[1] || '1')
|
||||
const pausedStep = stateContent.match(/Paused Step: (\w+)/)?.[1] || 'plan'
|
||||
const gapIteration = parseInt(stateContent.match(/Gap Iteration: (\d+)/)?.[1] || '0')
|
||||
```
|
||||
|
||||
### Step 2: Load Session Context
|
||||
|
||||
```javascript
|
||||
const roadmap = Read(`${sessionFolder}/roadmap.md`)
|
||||
const config = JSON.parse(Read(`${sessionFolder}/config.json`))
|
||||
|
||||
// Load project context
|
||||
const projectTech = JSON.parse(Read('.workflow/project-tech.json'))
|
||||
```
|
||||
|
||||
### Step 3: Update State to In-Progress
|
||||
|
||||
```javascript
|
||||
const timestamp = new Date().toISOString().slice(0, 19)
|
||||
|
||||
Edit(`${sessionFolder}/state.md`, {
|
||||
old_string: `- Status: paused`,
|
||||
new_string: `- Status: in_progress
|
||||
- Resumed At: ${timestamp}
|
||||
- Resumed From Phase: ${pausedPhase}, Step: ${pausedStep}`
|
||||
})
|
||||
```
|
||||
|
||||
### Step 4: Log Resume Event
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "coordinator", to: "all",
|
||||
type: "phase_started",
|
||||
summary: `[coordinator] Session resumed at phase ${pausedPhase}, step: ${pausedStep}`,
|
||||
ref: `${sessionFolder}/state.md`
|
||||
})
|
||||
```
|
||||
|
||||
### Step 5: Re-enter Monitor Loop
|
||||
|
||||
```javascript
|
||||
// Delegate to monitor.md with resume context
|
||||
// monitor.md receives:
|
||||
// - startPhase: pausedPhase (instead of 1)
|
||||
// - startStep: pausedStep (plan/exec/verify/gap_closure)
|
||||
// - gapIteration: gapIteration (for gap closure continuity)
|
||||
|
||||
Read("commands/monitor.md")
|
||||
// Monitor will:
|
||||
// 1. Skip phases before pausedPhase
|
||||
// 2. Within pausedPhase, skip steps before pausedStep
|
||||
// 3. Continue normal execution from that point
|
||||
```
|
||||
|
||||
### Step 6: Determine Resume Entry Point
|
||||
|
||||
```javascript
|
||||
// Map pausedStep to monitor entry point
|
||||
switch (pausedStep) {
|
||||
case 'plan':
|
||||
// Re-dispatch planner for current phase
|
||||
// Check if PLAN task exists and is pending/incomplete
|
||||
break
|
||||
|
||||
case 'exec':
|
||||
// Re-dispatch executor for current phase
|
||||
// Check if EXEC task exists and is pending/incomplete
|
||||
break
|
||||
|
||||
case 'verify':
|
||||
// Re-dispatch verifier for current phase
|
||||
break
|
||||
|
||||
case 'gap_closure':
|
||||
// Re-enter gap closure loop at gapIteration
|
||||
break
|
||||
|
||||
case 'transition':
|
||||
// Phase was complete, proceed to next phase
|
||||
break
|
||||
}
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
| Artifact | Path | Description |
|
||||
|----------|------|-------------|
|
||||
| state.md | `{sessionFolder}/state.md` | Updated with resumed status |
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| Session folder not found | Error with available session list |
|
||||
| state.md missing | Error — session may be corrupted |
|
||||
| Session not paused | Check if in_progress or completed, handle accordingly |
|
||||
| Roadmap.md missing | Error — session artifacts may be incomplete |
|
||||
| config.json missing | Use defaults (mode=interactive, depth=standard) |
|
||||
| Tasks from prior run still pending | Re-use them, don't create duplicates |
|
||||
@@ -0,0 +1,287 @@
|
||||
# Command: roadmap-discuss
|
||||
|
||||
Interactive roadmap discussion with the user. This is the KEY coordinator command -- no work begins until the roadmap is agreed upon.
|
||||
|
||||
## Purpose
|
||||
|
||||
Discuss project roadmap with the user using project-tech.json + project-guidelines.json as context. Elicit phases, requirements, success criteria, and execution preferences. Produces `roadmap.md` and `config.json` as session artifacts.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 2 of coordinator lifecycle (after init prerequisites, before dispatch)
|
||||
- Called exactly once per session (re-entry updates existing roadmap)
|
||||
|
||||
## Strategy
|
||||
|
||||
Direct interaction via AskUserQuestion. No delegation to workers or subagents. Coordinator handles this entirely.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Source | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `sessionFolder` | From coordinator Phase 1 | Session artifact directory |
|
||||
| `taskDescription` | From coordinator Phase 1 | User's original task description |
|
||||
| `projectTech` | Loaded in Phase 1 | Parsed project-tech.json |
|
||||
| `projectGuidelines` | Loaded in Phase 1 | Parsed project-guidelines.json (nullable) |
|
||||
| `autoYes` | From -y/--yes flag | Skip interactive prompts, use defaults |
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Load Project Context
|
||||
|
||||
```javascript
|
||||
// Already loaded by coordinator Phase 1, but verify availability
|
||||
const projectTech = JSON.parse(Read('.workflow/project-tech.json'))
|
||||
let projectGuidelines = null
|
||||
try {
|
||||
projectGuidelines = JSON.parse(Read('.workflow/project-guidelines.json'))
|
||||
} catch {}
|
||||
```
|
||||
|
||||
### Step 2: Present Project Overview to User
|
||||
|
||||
```javascript
|
||||
// Summarize what we know about the project
|
||||
const overview = `[coordinator] Project context loaded.
|
||||
- Project: ${projectTech.project_name}
|
||||
- Tech Stack: ${projectTech.tech_stack?.join(', ')}
|
||||
- Task: ${taskDescription}
|
||||
${projectGuidelines ? `- Guidelines: ${projectGuidelines.conventions?.length || 0} conventions loaded` : '- Guidelines: not configured'}`
|
||||
|
||||
// Display overview (via direct output, not AskUserQuestion)
|
||||
```
|
||||
|
||||
### Step 3: Confirm Project Goal and Scope
|
||||
|
||||
```javascript
|
||||
// Skip if taskDescription is already detailed enough, or autoYes
|
||||
if (!autoYes && !taskDescription) {
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: "What is the project goal and scope for this session?",
|
||||
header: "Goal",
|
||||
multiSelect: false,
|
||||
options: [] // Free-form text input
|
||||
}]
|
||||
})
|
||||
}
|
||||
// Store response as `projectGoal`
|
||||
const projectGoal = taskDescription || userResponse
|
||||
```
|
||||
|
||||
### Step 4: Ask Execution Mode
|
||||
|
||||
```javascript
|
||||
if (!autoYes) {
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: "How should phase transitions be handled?",
|
||||
header: "Execution Mode",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "interactive", description: "Ask for confirmation at each phase transition" },
|
||||
{ label: "yolo", description: "Auto-execute all phases without stopping" },
|
||||
{ label: "custom", description: "Choose which gates require confirmation" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
} else {
|
||||
mode = "yolo"
|
||||
}
|
||||
|
||||
// If "custom" selected, follow up with gate selection:
|
||||
if (mode === "custom") {
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: "Which gates should require confirmation?",
|
||||
header: "Custom Gates",
|
||||
multiSelect: true,
|
||||
options: [
|
||||
{ label: "plan_check", description: "Review plan before execution" },
|
||||
{ label: "verifier", description: "Review verification results before next phase" },
|
||||
{ label: "gap_closure", description: "Confirm gap closure before re-execution" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Ask Analysis Depth
|
||||
|
||||
```javascript
|
||||
if (!autoYes) {
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: "How thorough should the analysis be?",
|
||||
header: "Analysis Depth",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "quick", description: "Fast scan, minimal context gathering (small tasks)" },
|
||||
{ label: "standard", description: "Balanced analysis with key context (default)" },
|
||||
{ label: "comprehensive", description: "Deep analysis, full codebase exploration (large refactors)" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
} else {
|
||||
depth = "standard"
|
||||
}
|
||||
```
|
||||
|
||||
### Step 6: Analyze Codebase and Generate Phased Roadmap
|
||||
|
||||
```javascript
|
||||
// Use Gemini CLI (or cli-explore-agent) to analyze the codebase
|
||||
// and generate a phased breakdown based on goal + project context
|
||||
Bash({
|
||||
command: `ccw cli -p "PURPOSE: Analyze codebase and generate phased execution roadmap for: ${projectGoal}
|
||||
TASK: \
|
||||
- Scan project structure and identify affected modules \
|
||||
- Break goal into sequential phases (max 5) \
|
||||
- Each phase: goal, requirements (REQ-IDs), success criteria (2-5 testable behaviors) \
|
||||
- Order phases by dependency (foundational first)
|
||||
MODE: analysis
|
||||
CONTEXT: @**/* | Memory: Tech stack: ${projectTech.tech_stack?.join(', ')}
|
||||
EXPECTED: Phased roadmap in markdown with REQ-IDs and testable success criteria
|
||||
CONSTRAINTS: Max 5 phases | Each phase independently verifiable | No implementation details" \
|
||||
--tool gemini --mode analysis --rule planning-breakdown-task-steps`,
|
||||
run_in_background: false,
|
||||
timeout: 300000
|
||||
})
|
||||
|
||||
// Parse the CLI output into structured phases
|
||||
```
|
||||
|
||||
### Step 7: Present Roadmap Draft for Confirmation
|
||||
|
||||
```javascript
|
||||
// Display the generated roadmap to user
|
||||
// Output the roadmap content directly, then ask for adjustments
|
||||
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: "Review the roadmap above. Any adjustments needed?",
|
||||
header: "Roadmap Review",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "Looks good, proceed", description: "Accept roadmap as-is" },
|
||||
{ label: "Adjust phases", description: "I want to modify the phase breakdown" },
|
||||
{ label: "Add requirements", description: "I want to add missing requirements" },
|
||||
{ label: "Change scope", description: "Narrow or expand the scope" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
|
||||
// If user requests adjustments, incorporate feedback and re-present
|
||||
// Loop until user confirms "Looks good, proceed"
|
||||
```
|
||||
|
||||
### Step 8: Generate Session Artifacts
|
||||
|
||||
#### roadmap.md
|
||||
|
||||
```javascript
|
||||
Write(`${sessionFolder}/roadmap.md`, roadmapContent)
|
||||
```
|
||||
|
||||
**roadmap.md format**:
|
||||
|
||||
```markdown
|
||||
# Roadmap: {projectGoal}
|
||||
|
||||
Generated: {date}
|
||||
Session: {sessionFolder}
|
||||
Depth: {depth}
|
||||
|
||||
## Phase 1: {phase title}
|
||||
|
||||
**Goal**: {one-line goal}
|
||||
|
||||
**Requirements**:
|
||||
- REQ-101: {requirement description}
|
||||
- REQ-102: {requirement description}
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] {testable behavior 1}
|
||||
- [ ] {testable behavior 2}
|
||||
- [ ] {testable behavior 3}
|
||||
|
||||
**Plan Count**: TBD
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: {phase title}
|
||||
|
||||
**Goal**: {one-line goal}
|
||||
|
||||
**Requirements**:
|
||||
- REQ-201: {requirement description}
|
||||
|
||||
**Success Criteria**:
|
||||
- [ ] {testable behavior 1}
|
||||
- [ ] {testable behavior 2}
|
||||
|
||||
**Plan Count**: TBD
|
||||
|
||||
---
|
||||
|
||||
(... additional phases ...)
|
||||
```
|
||||
|
||||
**REQ-ID Convention**: `REQ-{phase}{seq}` (e.g., REQ-101 = Phase 1, requirement 1)
|
||||
|
||||
#### config.json
|
||||
|
||||
```javascript
|
||||
Write(`${sessionFolder}/config.json`, JSON.stringify({
|
||||
mode: mode, // "interactive" | "yolo" | "custom"
|
||||
depth: depth, // "quick" | "standard" | "comprehensive"
|
||||
auto_advance: mode === "yolo",
|
||||
gates: {
|
||||
plan_check: mode === "interactive" || (mode === "custom" && customGates.includes("plan_check")),
|
||||
verifier: mode === "interactive" || (mode === "custom" && customGates.includes("verifier")),
|
||||
gap_closure: mode === "interactive" || (mode === "custom" && customGates.includes("gap_closure"))
|
||||
}
|
||||
}, null, 2))
|
||||
```
|
||||
|
||||
**config.json format**:
|
||||
|
||||
```json
|
||||
{
|
||||
"mode": "interactive",
|
||||
"depth": "standard",
|
||||
"auto_advance": false,
|
||||
"gates": {
|
||||
"plan_check": true,
|
||||
"verifier": true,
|
||||
"gap_closure": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 9: Update state.md
|
||||
|
||||
```javascript
|
||||
// Transition Phase 0 → Phase 1
|
||||
Edit(`${sessionFolder}/state.md`, {
|
||||
old_string: "- Phase: 0 (Roadmap Discussion)\n- Status: initializing",
|
||||
new_string: `- Phase: 1\n- Status: ready_to_dispatch\n- Roadmap: confirmed (${phaseCount} phases)\n- Mode: ${mode}\n- Depth: ${depth}`
|
||||
})
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
| Artifact | Path | Description |
|
||||
|----------|------|-------------|
|
||||
| roadmap.md | `{sessionFolder}/roadmap.md` | Phased plan with REQ-IDs and success criteria |
|
||||
| config.json | `{sessionFolder}/config.json` | Execution preferences |
|
||||
| state.md | `{sessionFolder}/state.md` | Updated with phase transition |
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| User provides no goal | Re-prompt with examples |
|
||||
| CLI analysis fails | Retry with simpler prompt, or ask user to describe phases manually |
|
||||
| User keeps adjusting roadmap | Max 5 adjustment rounds, then proceed with latest version |
|
||||
| autoYes flag set | Skip all AskUserQuestion calls, use defaults: mode=yolo, depth=standard |
|
||||
202
.claude/skills/team-roadmap-dev/roles/coordinator/role.md
Normal file
202
.claude/skills/team-roadmap-dev/roles/coordinator/role.md
Normal file
@@ -0,0 +1,202 @@
|
||||
# Role: coordinator
|
||||
|
||||
Team coordinator. Manages the full project lifecycle: init prerequisites → roadmap discussion with user → phase dispatch → monitoring → transitions → completion.
|
||||
|
||||
**Key innovation**: Roadmap is discussed with the user via `commands/roadmap-discuss.md` before any work begins. Coordinator is the ONLY role that interacts with humans.
|
||||
|
||||
## Role Identity
|
||||
|
||||
- **Name**: `coordinator`
|
||||
- **Task Prefix**: N/A (coordinator creates tasks, doesn't receive them)
|
||||
- **Responsibility**: Orchestration
|
||||
- **Communication**: SendMessage to all teammates + AskUserQuestion to user
|
||||
- **Output Tag**: `[coordinator]`
|
||||
|
||||
## Role Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- All outputs must carry `[coordinator]` prefix
|
||||
- Handle ALL human interaction (AskUserQuestion) — workers never interact with user
|
||||
- Ensure init prerequisites before starting (project-tech.json)
|
||||
- Discuss roadmap with user before dispatching work
|
||||
- Manage state.md updates at every phase transition
|
||||
- Route verifier gap results to planner for closure
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- ❌ Execute any business tasks (code, analysis, testing, verification)
|
||||
- ❌ Call code-developer, cli-explore-agent, or other implementation subagents
|
||||
- ❌ Modify source code or generate implementation artifacts
|
||||
- ❌ Bypass worker roles to do work directly
|
||||
- ❌ Skip roadmap discussion phase
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `phase_started` | coordinator → workers | Phase dispatch | New phase initiated |
|
||||
| `phase_complete` | coordinator → user | All phase tasks done | Phase results summary |
|
||||
| `gap_closure` | coordinator → planner | Verifier found gaps | Trigger re-plan for gaps |
|
||||
| `project_complete` | coordinator → user | All phases done | Final report |
|
||||
| `error` | coordinator → user | Critical failure | Error report |
|
||||
|
||||
## Message Bus
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "coordinator", to: targetRole,
|
||||
type: messageType,
|
||||
summary: `[coordinator] ${messageSummary}`,
|
||||
ref: artifactPath
|
||||
})
|
||||
```
|
||||
|
||||
### CLI Fallback
|
||||
|
||||
```javascript
|
||||
Bash(`ccw team log --team "roadmap-dev" --from "coordinator" --to "${targetRole}" --type "${type}" --summary "[coordinator] ${summary}" --json`)
|
||||
```
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `roadmap-discuss` | [commands/roadmap-discuss.md](commands/roadmap-discuss.md) | Phase 1-2 | Discuss roadmap with user, generate session artifacts |
|
||||
| `dispatch` | [commands/dispatch.md](commands/dispatch.md) | Phase 3 | Create task chain per phase |
|
||||
| `monitor` | [commands/monitor.md](commands/monitor.md) | Phase 4 | Stop-Wait phase execution loop |
|
||||
| `pause` | [commands/pause.md](commands/pause.md) | Any | Save state and exit cleanly |
|
||||
| `resume` | [commands/resume.md](commands/resume.md) | Any | Resume from paused session |
|
||||
|
||||
## Execution
|
||||
|
||||
### Phase 1: Init Prerequisites + Requirement Parsing
|
||||
|
||||
```javascript
|
||||
const args = "$ARGUMENTS"
|
||||
const taskDescription = args.replace(/--\w+[=\s]+\S+/g, '').trim()
|
||||
const autoYes = /\b(-y|--yes)\b/.test(args)
|
||||
const resumeMatch = args.match(/--resume[=\s]+(.+?)(?:\s|$)/)
|
||||
|
||||
// Resume mode: skip init, load existing session
|
||||
if (resumeMatch) {
|
||||
const sessionFolder = resumeMatch[1].trim()
|
||||
Read("commands/resume.md")
|
||||
// Resume handles: validate state → load context → re-enter monitor
|
||||
return
|
||||
}
|
||||
|
||||
// 1. Ensure project-tech.json exists
|
||||
const techExists = Bash(`test -f .workflow/project-tech.json && echo "EXISTS" || echo "NOT_FOUND"`).trim()
|
||||
if (techExists === "NOT_FOUND") {
|
||||
// Invoke workflow:init
|
||||
Skill(skill="workflow:init")
|
||||
}
|
||||
|
||||
// 2. Load project context
|
||||
const projectTech = JSON.parse(Read('.workflow/project-tech.json'))
|
||||
let projectGuidelines = null
|
||||
try {
|
||||
projectGuidelines = JSON.parse(Read('.workflow/project-guidelines.json'))
|
||||
} catch {}
|
||||
|
||||
// 3. Create session directory
|
||||
const slug = taskDescription.replace(/[^a-zA-Z0-9\u4e00-\u9fff]+/g, '-').slice(0, 30).toLowerCase()
|
||||
const date = new Date().toISOString().slice(0, 10)
|
||||
const sessionFolder = `.workflow/.team/RD-${slug}-${date}`
|
||||
Bash(`mkdir -p "${sessionFolder}"`)
|
||||
|
||||
// 4. Initialize state.md
|
||||
Write(`${sessionFolder}/state.md`, `# Roadmap Dev Session State
|
||||
|
||||
## Project Reference
|
||||
- Name: ${projectTech.project_name}
|
||||
- Session: RD-${slug}-${date}
|
||||
- Started: ${date}
|
||||
|
||||
## Current Position
|
||||
- Phase: 0 (Roadmap Discussion)
|
||||
- Status: initializing
|
||||
|
||||
## Accumulated Context
|
||||
- Task: ${taskDescription}
|
||||
`)
|
||||
```
|
||||
|
||||
### Phase 2: Roadmap Discussion (via command)
|
||||
|
||||
```javascript
|
||||
// Delegate to roadmap-discuss command
|
||||
Read("commands/roadmap-discuss.md")
|
||||
// Execute roadmap discussion with user
|
||||
// Produces: {sessionFolder}/roadmap.md, {sessionFolder}/config.json
|
||||
// Updates: {sessionFolder}/state.md
|
||||
```
|
||||
|
||||
**Command**: [commands/roadmap-discuss.md](commands/roadmap-discuss.md)
|
||||
|
||||
### Phase 3: Create Team + Dispatch First Phase
|
||||
|
||||
```javascript
|
||||
// 1. Create team and spawn workers
|
||||
TeamCreate({ team_name: "roadmap-dev" })
|
||||
// Spawn planner, executor, verifier (see SKILL.md Coordinator Spawn Template)
|
||||
|
||||
// 2. Dispatch first phase
|
||||
Read("commands/dispatch.md")
|
||||
// Creates: PLAN-101 (phase 1 planning task)
|
||||
```
|
||||
|
||||
**Command**: [commands/dispatch.md](commands/dispatch.md)
|
||||
|
||||
### Phase 4: Coordination Loop (Stop-Wait per phase)
|
||||
|
||||
```javascript
|
||||
Read("commands/monitor.md")
|
||||
// Executes: phase-by-phase Stop-Wait loop
|
||||
// Handles: phase transitions, gap closure, next phase dispatch
|
||||
// Continues until all roadmap phases complete
|
||||
```
|
||||
|
||||
**Command**: [commands/monitor.md](commands/monitor.md)
|
||||
|
||||
### Phase 5: Report + Persist
|
||||
|
||||
```javascript
|
||||
// 1. Update state.md with final status
|
||||
const finalState = Read(`${sessionFolder}/state.md`)
|
||||
// Update status to "completed"
|
||||
|
||||
// 2. Summary report to user
|
||||
const roadmap = Read(`${sessionFolder}/roadmap.md`)
|
||||
// Compile results from all phase summaries and verifications
|
||||
|
||||
// 3. Post-completion options
|
||||
AskUserQuestion({
|
||||
questions: [{
|
||||
question: "项目执行完成。下一步?",
|
||||
header: "Next",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "提交代码", description: "git add + commit 所有变更" },
|
||||
{ label: "继续下一个里程碑", description: "开始新的 roadmap discussion" },
|
||||
{ label: "完成", description: "结束 session" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| project-tech.json missing | Invoke /workflow:init automatically |
|
||||
| User cancels roadmap discussion | Save session state, exit gracefully |
|
||||
| Planner fails | Retry once, then ask user for guidance |
|
||||
| Executor fails on plan | Mark plan as failed, continue with next |
|
||||
| Verifier finds gaps (≤3 iterations) | Trigger gap closure: re-plan → re-execute → re-verify |
|
||||
| Verifier gaps persist (>3 iterations) | Report to user, ask for manual intervention |
|
||||
| Worker timeout | Kill worker, report partial results |
|
||||
@@ -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 |
|
||||
272
.claude/skills/team-roadmap-dev/roles/executor/role.md
Normal file
272
.claude/skills/team-roadmap-dev/roles/executor/role.md
Normal 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 |
|
||||
@@ -0,0 +1,362 @@
|
||||
# Command: create-plans
|
||||
|
||||
Generate execution plans via action-planning-agent. Produces IMPL_PLAN.md, .task/IMPL-*.json, and TODO_LIST.md — the same artifact format as workflow-plan skill.
|
||||
|
||||
## Purpose
|
||||
|
||||
Transform phase context into structured task JSONs and implementation plan. Delegates to action-planning-agent for document generation. Produces artifacts compatible with workflow-plan's output format, enabling reuse of executor and verifier logic.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 3 of planner execution (after research, before self-validation)
|
||||
- Called once per PLAN-* task
|
||||
|
||||
## Strategy
|
||||
|
||||
Delegate to action-planning-agent with phase context (context.md + roadmap phase section). The agent produces task JSONs with convergence criteria (replacing the old must_haves concept), dependency graph (replacing wave numbering), and implementation steps.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Source | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `sessionFolder` | From PLAN-* task description | Session artifact directory |
|
||||
| `phaseNumber` | From PLAN-* task description | Phase number (1-based) |
|
||||
|
||||
## Output Artifact Mapping (vs old plan-NN.md)
|
||||
|
||||
| Old (plan-NN.md) | New (IMPL-*.json) | Notes |
|
||||
|-------------------|--------------------|-------|
|
||||
| `plan: NN` | `id: "IMPL-N"` | Task identifier |
|
||||
| `wave: N` | `depends_on: [...]` | Dependency graph replaces explicit waves |
|
||||
| `files_modified: [...]` | `files: [{path, action, change}]` | Structured file list |
|
||||
| `requirements: [REQ-IDs]` | `description` + `scope` | Requirements embedded in description |
|
||||
| `must_haves.truths` | `convergence.criteria` | Observable behaviors → measurable criteria |
|
||||
| `must_haves.artifacts` | `files` + `convergence.verification` | File checks in verification command |
|
||||
| `must_haves.key_links` | `convergence.verification` | Import wiring in verification command |
|
||||
| Plan body (implementation steps) | `implementation: [...]` | Step-by-step actions |
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Load Phase Context
|
||||
|
||||
```javascript
|
||||
const context = Read(`${sessionFolder}/phase-${phaseNumber}/context.md`)
|
||||
const roadmap = Read(`${sessionFolder}/roadmap.md`)
|
||||
const config = JSON.parse(Read(`${sessionFolder}/config.json`))
|
||||
|
||||
// Extract phase section from roadmap
|
||||
const phaseGoal = extractPhaseGoal(roadmap, phaseNumber)
|
||||
const requirements = extractRequirements(roadmap, phaseNumber)
|
||||
const successCriteria = extractSuccessCriteria(roadmap, phaseNumber)
|
||||
|
||||
// Check for gap closure context
|
||||
const isGapClosure = context.includes("Gap Closure Context")
|
||||
|
||||
// Load prior phase summaries for cross-phase 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(Read(sf))
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Prepare Output Directories
|
||||
|
||||
```javascript
|
||||
Bash(`mkdir -p "${sessionFolder}/phase-${phaseNumber}/.task"`)
|
||||
```
|
||||
|
||||
### Step 3: Delegate to action-planning-agent
|
||||
|
||||
```javascript
|
||||
const taskDir = `${sessionFolder}/phase-${phaseNumber}/.task`
|
||||
const implPlanPath = `${sessionFolder}/phase-${phaseNumber}/IMPL_PLAN.md`
|
||||
const todoListPath = `${sessionFolder}/phase-${phaseNumber}/TODO_LIST.md`
|
||||
|
||||
Task({
|
||||
subagent_type: "action-planning-agent",
|
||||
run_in_background: false,
|
||||
description: `Generate phase ${phaseNumber} planning documents`,
|
||||
prompt: `
|
||||
## TASK OBJECTIVE
|
||||
Generate implementation planning documents (IMPL_PLAN.md, task JSONs, TODO_LIST.md) for roadmap-dev session phase ${phaseNumber}.
|
||||
|
||||
IMPORTANT: This is PLANNING ONLY - generate planning documents, NOT implementing code.
|
||||
|
||||
## PHASE CONTEXT
|
||||
${context}
|
||||
|
||||
## ROADMAP PHASE ${phaseNumber}
|
||||
Goal: ${phaseGoal}
|
||||
|
||||
Requirements:
|
||||
${requirements.map(r => `- ${r.id}: ${r.desc}`).join('\n')}
|
||||
|
||||
Success Criteria:
|
||||
${successCriteria.map(c => `- ${c}`).join('\n')}
|
||||
|
||||
${isGapClosure ? `## GAP CLOSURE
|
||||
This is a gap closure iteration. Only address gaps listed in context — do NOT re-plan completed work.
|
||||
Existing task JSONs in ${taskDir} represent prior work. Create gap-specific tasks starting from next available ID.` : ''}
|
||||
|
||||
${priorSummaries.length > 0 ? `## PRIOR PHASE CONTEXT
|
||||
${priorSummaries.join('\n\n---\n\n')}` : ''}
|
||||
|
||||
## SESSION PATHS
|
||||
Output:
|
||||
- Task Dir: ${taskDir}
|
||||
- IMPL_PLAN: ${implPlanPath}
|
||||
- TODO_LIST: ${todoListPath}
|
||||
|
||||
## CONTEXT METADATA
|
||||
Session: ${sessionFolder}
|
||||
Phase: ${phaseNumber}
|
||||
Depth: ${config.depth || 'standard'}
|
||||
|
||||
## USER CONFIGURATION
|
||||
Execution Method: agent
|
||||
Preferred CLI Tool: gemini
|
||||
|
||||
## EXPECTED DELIVERABLES
|
||||
1. Task JSON Files (${taskDir}/IMPL-*.json)
|
||||
- Unified flat schema (task-schema.json)
|
||||
- Quantified requirements with explicit counts
|
||||
- focus_paths from context.md relevant files
|
||||
- convergence criteria derived from success criteria (goal-backward)
|
||||
|
||||
2. Implementation Plan (${implPlanPath})
|
||||
- Phase goal and context
|
||||
- Task breakdown and execution strategy
|
||||
- Dependency graph
|
||||
|
||||
3. TODO List (${todoListPath})
|
||||
- Flat structure with [ ] for pending
|
||||
- Links to task JSONs
|
||||
|
||||
## TASK ID FORMAT
|
||||
Use: IMPL-{phaseNumber}{seq} (e.g., IMPL-101, IMPL-102 for phase 1)
|
||||
|
||||
## CONVERGENCE CRITERIA RULES (replacing old must_haves)
|
||||
Each task MUST include convergence:
|
||||
- criteria: Measurable conditions derived from success criteria (goal-backward, not task-forward)
|
||||
- Include file existence checks
|
||||
- Include export/symbol presence checks
|
||||
- Include test passage checks where applicable
|
||||
- verification: Executable command to verify criteria
|
||||
- definition_of_done: Business-language completion definition
|
||||
|
||||
## CLI EXECUTION ID FORMAT
|
||||
Each task: cli_execution.id = "RD-${sessionFolder.split('/').pop()}-{task_id}"
|
||||
|
||||
## QUALITY STANDARDS
|
||||
- Task count <= 10 per phase (hard limit)
|
||||
- All requirements quantified
|
||||
- Acceptance criteria measurable
|
||||
- Dependencies form a valid DAG (no cycles)
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
### Step 4: Validate Generated Artifacts
|
||||
|
||||
```javascript
|
||||
// 4a. Verify task JSONs were created
|
||||
const taskFiles = Glob(`${taskDir}/IMPL-*.json`)
|
||||
if (!taskFiles || taskFiles.length === 0) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "error",
|
||||
summary: `[planner] action-planning-agent produced no task JSONs for phase ${phaseNumber}`
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 4b. Validate each task JSON
|
||||
for (const taskFile of taskFiles) {
|
||||
const taskJson = JSON.parse(Read(taskFile))
|
||||
|
||||
// Required fields check
|
||||
const requiredFields = ['id', 'title', 'description', 'files', 'implementation', 'convergence']
|
||||
for (const field of requiredFields) {
|
||||
if (!taskJson[field]) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "plan_progress",
|
||||
summary: `[planner] Warning: ${taskFile} missing field: ${field}`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Convergence criteria check
|
||||
if (!taskJson.convergence?.criteria || taskJson.convergence.criteria.length === 0) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "plan_progress",
|
||||
summary: `[planner] Warning: ${taskFile} has no convergence criteria`
|
||||
})
|
||||
}
|
||||
|
||||
// Dependency cycle check (simple: task cannot depend on itself)
|
||||
if (taskJson.depends_on?.includes(taskJson.id)) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "error",
|
||||
summary: `[planner] Self-dependency detected in ${taskJson.id}`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 4c. Validate dependency DAG (no cycles)
|
||||
const allTasks = taskFiles.map(f => JSON.parse(Read(f)))
|
||||
const taskIds = new Set(allTasks.map(t => t.id))
|
||||
|
||||
// Check all depends_on references are valid
|
||||
for (const task of allTasks) {
|
||||
for (const dep of (task.depends_on || [])) {
|
||||
if (!taskIds.has(dep)) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "plan_progress",
|
||||
summary: `[planner] Warning: ${task.id} depends on unknown task ${dep}`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4d. Verify IMPL_PLAN.md exists
|
||||
const implPlanExists = Bash(`test -f "${implPlanPath}" && echo "EXISTS" || echo "NOT_FOUND"`).trim()
|
||||
if (implPlanExists === "NOT_FOUND") {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "plan_progress",
|
||||
summary: `[planner] Warning: IMPL_PLAN.md not generated, creating minimal version`
|
||||
})
|
||||
// Create minimal IMPL_PLAN.md from task JSONs
|
||||
generateMinimalImplPlan(allTasks, implPlanPath, phaseGoal, phaseNumber)
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Compute Wave Structure (for reporting)
|
||||
|
||||
```javascript
|
||||
// Derive wave structure from dependency graph (for reporting only — executor uses depends_on directly)
|
||||
function computeWaves(tasks) {
|
||||
const waves = {}
|
||||
const assigned = new Set()
|
||||
let currentWave = 1
|
||||
|
||||
while (assigned.size < tasks.length) {
|
||||
const waveMembers = tasks.filter(t =>
|
||||
!assigned.has(t.id) &&
|
||||
(t.depends_on || []).every(d => assigned.has(d))
|
||||
)
|
||||
|
||||
if (waveMembers.length === 0 && assigned.size < tasks.length) {
|
||||
const unassigned = tasks.find(t => !assigned.has(t.id))
|
||||
waveMembers.push(unassigned)
|
||||
}
|
||||
|
||||
for (const task of waveMembers) {
|
||||
waves[task.id] = currentWave
|
||||
assigned.add(task.id)
|
||||
}
|
||||
currentWave++
|
||||
}
|
||||
return { waves, totalWaves: currentWave - 1 }
|
||||
}
|
||||
|
||||
const { waves, totalWaves } = computeWaves(allTasks)
|
||||
```
|
||||
|
||||
### Step 6: Report Plan Structure
|
||||
|
||||
```javascript
|
||||
const taskCount = allTasks.length
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "plan_progress",
|
||||
summary: `[planner] Created ${taskCount} tasks across ${totalWaves} waves for phase ${phaseNumber}`,
|
||||
ref: `${sessionFolder}/phase-${phaseNumber}/`
|
||||
})
|
||||
|
||||
return {
|
||||
taskCount,
|
||||
totalWaves,
|
||||
waves,
|
||||
taskFiles,
|
||||
implPlanPath,
|
||||
todoListPath
|
||||
}
|
||||
```
|
||||
|
||||
## Gap Closure Plans
|
||||
|
||||
When creating plans for gap closure (re-planning after verification found gaps):
|
||||
|
||||
```javascript
|
||||
if (isGapClosure) {
|
||||
// 1. Existing IMPL-*.json files represent completed work
|
||||
// 2. action-planning-agent receives gap context and creates gap-specific tasks
|
||||
// 3. New task IDs start from next available (e.g., IMPL-103 if 101,102 exist)
|
||||
// 4. convergence criteria should directly address gap descriptions from verification.md
|
||||
// 5. Gap tasks may depend on existing completed tasks
|
||||
}
|
||||
```
|
||||
|
||||
## Helper: Minimal IMPL_PLAN.md Generation
|
||||
|
||||
```javascript
|
||||
function generateMinimalImplPlan(tasks, outputPath, phaseGoal, phaseNumber) {
|
||||
const content = `# Implementation Plan: Phase ${phaseNumber}
|
||||
|
||||
## Goal
|
||||
|
||||
${phaseGoal}
|
||||
|
||||
## Tasks
|
||||
|
||||
${tasks.map(t => `### ${t.id}: ${t.title}
|
||||
|
||||
${t.description}
|
||||
|
||||
**Files**: ${(t.files || []).map(f => f.path).join(', ')}
|
||||
**Depends on**: ${(t.depends_on || []).join(', ') || 'None'}
|
||||
|
||||
**Convergence Criteria**:
|
||||
${(t.convergence?.criteria || []).map(c => `- ${c}`).join('\n')}
|
||||
`).join('\n---\n\n')}
|
||||
|
||||
## Dependency Graph
|
||||
|
||||
${'```'}
|
||||
${tasks.map(t => `${t.id} → [${(t.depends_on || []).join(', ')}]`).join('\n')}
|
||||
${'```'}
|
||||
`
|
||||
|
||||
Write(outputPath, content)
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| context.md not found | Error — research phase was skipped or failed |
|
||||
| action-planning-agent fails | Retry once. If still fails, error to coordinator |
|
||||
| No task JSONs generated | Error to coordinator — agent may have misunderstood input |
|
||||
| Dependency cycle detected | Log warning, break cycle at lowest-numbered task |
|
||||
| Too many tasks (>10) | Log warning — agent should self-limit but validate |
|
||||
| Missing convergence criteria | Log warning — every task should have at least one criterion |
|
||||
| IMPL_PLAN.md not generated | Create minimal version from task JSONs |
|
||||
@@ -0,0 +1,219 @@
|
||||
# Command: research
|
||||
|
||||
Gather context for a phase before creating execution plans. Explores the codebase, reads requirements from roadmap, and produces a structured context.md file.
|
||||
|
||||
## Purpose
|
||||
|
||||
Build a comprehensive understanding of the phase's scope by combining roadmap requirements, prior phase outputs, and codebase analysis. The resulting context.md is the sole input for the create-plans command.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 2 of planner execution (after task discovery, before plan creation)
|
||||
- Called once per PLAN-* task (including gap closure iterations)
|
||||
|
||||
## Strategy
|
||||
|
||||
Subagent delegation (cli-explore-agent) for codebase exploration, supplemented by optional Gemini CLI for deep analysis when depth warrants it. Planner does NOT explore the codebase directly -- it delegates.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Source | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `sessionFolder` | From PLAN-* task description | Session artifact directory |
|
||||
| `phaseNumber` | From PLAN-* task description | Phase to research (1-based) |
|
||||
| `depth` | From config.json or task description | "quick" / "standard" / "comprehensive" |
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Read Roadmap and Extract Phase Requirements
|
||||
|
||||
```javascript
|
||||
const roadmap = Read(`${sessionFolder}/roadmap.md`)
|
||||
const config = JSON.parse(Read(`${sessionFolder}/config.json`))
|
||||
const depth = config.depth || "standard"
|
||||
|
||||
// Parse phase section from roadmap
|
||||
// Extract: goal, requirements (REQ-IDs), success criteria
|
||||
const phaseSection = extractPhaseSection(roadmap, phaseNumber)
|
||||
const phaseGoal = phaseSection.goal
|
||||
const requirements = phaseSection.requirements // [{id: "REQ-101", desc: "..."}, ...]
|
||||
const successCriteria = phaseSection.successCriteria // ["testable behavior 1", ...]
|
||||
```
|
||||
|
||||
### Step 2: Read Prior Phase Context (if applicable)
|
||||
|
||||
```javascript
|
||||
const priorContext = []
|
||||
|
||||
if (phaseNumber > 1) {
|
||||
// Load summaries from previous phases for dependency context
|
||||
for (let p = 1; p < phaseNumber; p++) {
|
||||
try {
|
||||
const summary = Glob(`${sessionFolder}/phase-${p}/summary-*.md`)
|
||||
for (const summaryFile of summary) {
|
||||
priorContext.push({
|
||||
phase: p,
|
||||
file: summaryFile,
|
||||
content: Read(summaryFile)
|
||||
})
|
||||
}
|
||||
} catch {
|
||||
// Prior phase may not have summaries yet (first phase)
|
||||
}
|
||||
|
||||
// Also load verification results for dependency awareness
|
||||
try {
|
||||
const verification = Read(`${sessionFolder}/phase-${p}/verification.md`)
|
||||
priorContext.push({
|
||||
phase: p,
|
||||
file: `${sessionFolder}/phase-${p}/verification.md`,
|
||||
content: verification
|
||||
})
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
// For gap closure: load the verification that triggered re-planning
|
||||
const isGapClosure = planTaskDescription.includes("Gap closure")
|
||||
let gapContext = null
|
||||
if (isGapClosure) {
|
||||
gapContext = Read(`${sessionFolder}/phase-${phaseNumber}/verification.md`)
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Codebase Exploration via cli-explore-agent
|
||||
|
||||
```javascript
|
||||
// Build exploration query from requirements
|
||||
const explorationQuery = requirements.map(r => r.desc).join('; ')
|
||||
|
||||
const exploreResult = Task({
|
||||
subagent_type: "cli-explore-agent",
|
||||
run_in_background: false,
|
||||
description: `Explore codebase for phase ${phaseNumber} requirements`,
|
||||
prompt: `Explore this codebase to gather context for the following requirements:
|
||||
|
||||
## Phase Goal
|
||||
${phaseGoal}
|
||||
|
||||
## Requirements
|
||||
${requirements.map(r => `- ${r.id}: ${r.desc}`).join('\n')}
|
||||
|
||||
## Success Criteria
|
||||
${successCriteria.map(c => `- ${c}`).join('\n')}
|
||||
|
||||
## What to Find
|
||||
1. Files that will need modification to satisfy these requirements
|
||||
2. Existing patterns and conventions relevant to this work
|
||||
3. Dependencies and integration points
|
||||
4. Test patterns used in this project
|
||||
5. Configuration or schema files that may need updates
|
||||
|
||||
## Output Format
|
||||
Provide a structured summary:
|
||||
- **Relevant Files**: List of files with brief description of relevance
|
||||
- **Patterns Found**: Coding patterns, naming conventions, architecture patterns
|
||||
- **Dependencies**: Internal and external dependencies that affect this work
|
||||
- **Test Infrastructure**: Test framework, test file locations, test patterns
|
||||
- **Risks**: Potential issues or complications discovered`
|
||||
})
|
||||
```
|
||||
|
||||
### Step 4: Optional Deep Analysis via Gemini CLI
|
||||
|
||||
```javascript
|
||||
// Only for comprehensive depth or complex phases
|
||||
if (depth === "comprehensive") {
|
||||
const analysisResult = Bash({
|
||||
command: `ccw cli -p "PURPOSE: Deep codebase analysis for implementation planning. Phase goal: ${phaseGoal}
|
||||
TASK: \
|
||||
- Analyze module boundaries and coupling for affected files \
|
||||
- Identify shared utilities and helpers that can be reused \
|
||||
- Map data flow through affected components \
|
||||
- Assess test coverage gaps in affected areas \
|
||||
- Identify backward compatibility concerns
|
||||
MODE: analysis
|
||||
CONTEXT: @**/* | Memory: Requirements: ${requirements.map(r => r.desc).join(', ')}
|
||||
EXPECTED: Structured analysis with: module map, reuse opportunities, data flow diagram, test gaps, compatibility risks
|
||||
CONSTRAINTS: Focus on files relevant to phase ${phaseNumber} requirements" \
|
||||
--tool gemini --mode analysis --rule analysis-analyze-code-patterns`,
|
||||
run_in_background: false,
|
||||
timeout: 300000
|
||||
})
|
||||
|
||||
// Store deep analysis result for context.md
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Write context.md
|
||||
|
||||
```javascript
|
||||
Bash(`mkdir -p "${sessionFolder}/phase-${phaseNumber}"`)
|
||||
|
||||
const contextContent = `# Phase ${phaseNumber} Context
|
||||
|
||||
Generated: ${new Date().toISOString().slice(0, 19)}
|
||||
Session: ${sessionFolder}
|
||||
Depth: ${depth}
|
||||
|
||||
## Phase Goal
|
||||
|
||||
${phaseGoal}
|
||||
|
||||
## Requirements
|
||||
|
||||
${requirements.map(r => `- **${r.id}**: ${r.desc}`).join('\n')}
|
||||
|
||||
## Success Criteria
|
||||
|
||||
${successCriteria.map(c => `- [ ] ${c}`).join('\n')}
|
||||
|
||||
## Prior Phase Dependencies
|
||||
|
||||
${priorContext.length > 0
|
||||
? priorContext.map(p => `### Phase ${p.phase}\n- Source: ${p.file}\n- Key outputs: ${extractKeyOutputs(p.content)}`).join('\n\n')
|
||||
: 'None (this is the first phase)'}
|
||||
|
||||
${isGapClosure ? `## Gap Closure Context\n\nThis is a gap closure iteration. Gaps from previous verification:\n${gapContext}` : ''}
|
||||
|
||||
## Relevant Files
|
||||
|
||||
${exploreResult.relevantFiles.map(f => `- \`${f.path}\`: ${f.description}`).join('\n')}
|
||||
|
||||
## Patterns Identified
|
||||
|
||||
${exploreResult.patterns.map(p => `- **${p.name}**: ${p.description}`).join('\n')}
|
||||
|
||||
## Dependencies
|
||||
|
||||
${exploreResult.dependencies.map(d => `- ${d}`).join('\n')}
|
||||
|
||||
## Test Infrastructure
|
||||
|
||||
${exploreResult.testInfo || 'Not analyzed (quick depth)'}
|
||||
|
||||
${depth === "comprehensive" && analysisResult ? `## Deep Analysis\n\n${analysisResult}` : ''}
|
||||
|
||||
## Questions / Risks
|
||||
|
||||
${exploreResult.risks.map(r => `- ${r}`).join('\n')}
|
||||
`
|
||||
|
||||
Write(`${sessionFolder}/phase-${phaseNumber}/context.md`, contextContent)
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
| Artifact | Path | Description |
|
||||
|----------|------|-------------|
|
||||
| context.md | `{sessionFolder}/phase-{N}/context.md` | Structured phase context for plan creation |
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| roadmap.md not found | Error to coordinator via message bus |
|
||||
| cli-explore-agent fails | Retry once. Fallback: use ACE search_context directly |
|
||||
| Gemini CLI fails | Skip deep analysis section, proceed with basic context |
|
||||
| Prior phase summaries missing | Log warning, proceed without dependency context |
|
||||
| Phase section not found in roadmap | Error to coordinator -- phase number may be invalid |
|
||||
286
.claude/skills/team-roadmap-dev/roles/planner/role.md
Normal file
286
.claude/skills/team-roadmap-dev/roles/planner/role.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# Role: planner
|
||||
|
||||
Research and plan creation per phase. Gathers codebase context via cli-explore-agent and Gemini CLI, then generates wave-based execution plans with must_haves verification criteria. Each plan is a self-contained unit of work that an executor can implement autonomously.
|
||||
|
||||
## Role Identity
|
||||
|
||||
- **Name**: `planner`
|
||||
- **Task Prefix**: `PLAN-*`
|
||||
- **Responsibility**: Orchestration (research + plan generation)
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[planner]`
|
||||
|
||||
## Role Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- All outputs must carry `[planner]` prefix
|
||||
- Only process `PLAN-*` prefixed tasks
|
||||
- Only communicate with coordinator (SendMessage)
|
||||
- Delegate research to commands/research.md
|
||||
- Delegate plan creation to commands/create-plans.md
|
||||
- Reference real files discovered during research (never fabricate paths)
|
||||
- Verify plans have no dependency cycles before reporting
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- Direct code writing or modification
|
||||
- Call code-developer or other implementation subagents
|
||||
- Create tasks for other roles (TaskCreate)
|
||||
- Interact with user (AskUserQuestion)
|
||||
- Process EXEC-* or VERIFY-* tasks
|
||||
- Skip the research phase
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `plan_ready` | planner -> coordinator | Plans created | Plan files written with wave structure |
|
||||
| `plan_progress` | planner -> coordinator | Research complete | Context gathered, starting plan creation |
|
||||
| `error` | planner -> coordinator | Failure | Research or planning failed |
|
||||
|
||||
## Message Bus
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: messageType,
|
||||
summary: `[planner] ${messageSummary}`,
|
||||
ref: artifactPath
|
||||
})
|
||||
```
|
||||
|
||||
### CLI Fallback
|
||||
|
||||
```javascript
|
||||
Bash(`ccw team log --team "roadmap-dev" --from "planner" --to "coordinator" --type "${type}" --summary "[planner] ${summary}" --json`)
|
||||
```
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `research` | [commands/research.md](commands/research.md) | Phase 2 | Context gathering via codebase exploration |
|
||||
| `create-plans` | [commands/create-plans.md](commands/create-plans.md) | Phase 3 | Wave-based plan file generation |
|
||||
|
||||
### Available Subagents
|
||||
|
||||
| Subagent | Purpose | When |
|
||||
|----------|---------|------|
|
||||
| `cli-explore-agent` | Codebase exploration (file discovery, pattern analysis) | Phase 2: Research |
|
||||
| `action-planning-agent` | Task JSON + IMPL_PLAN.md generation | Phase 3: Create Plans |
|
||||
|
||||
### CLI Tools
|
||||
|
||||
| Tool | Mode | When |
|
||||
|------|------|------|
|
||||
| `gemini` | analysis | Deep analysis for complex phases (optional, depth=comprehensive) |
|
||||
|
||||
## Execution
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
// Find assigned PLAN-* task
|
||||
const tasks = TaskList()
|
||||
const planTask = tasks.find(t =>
|
||||
t.subject.startsWith('PLAN-') &&
|
||||
t.status === 'pending' &&
|
||||
(!t.blockedBy || t.blockedBy.length === 0)
|
||||
)
|
||||
|
||||
if (!planTask) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "error",
|
||||
summary: "[planner] No available PLAN-* task found"
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
TaskUpdate({ taskId: planTask.id, status: "in_progress" })
|
||||
|
||||
// Parse task description for session context
|
||||
const taskDetails = TaskGet({ taskId: planTask.id })
|
||||
const sessionFolder = parseSessionFolder(taskDetails.description)
|
||||
const phaseNumber = parsePhaseNumber(taskDetails.description)
|
||||
const depth = parseDepth(taskDetails.description) || "standard"
|
||||
```
|
||||
|
||||
### Phase 2: Research (via command)
|
||||
|
||||
```javascript
|
||||
// Delegate to research command
|
||||
Read("commands/research.md")
|
||||
// Execute research steps:
|
||||
// 1. Read roadmap.md for phase goal and requirements
|
||||
// 2. Read prior phase summaries (if any)
|
||||
// 3. Launch cli-explore-agent for codebase exploration
|
||||
// 4. Optional: Gemini CLI for deeper analysis (if depth=comprehensive)
|
||||
// 5. Write context.md to {sessionFolder}/phase-{N}/context.md
|
||||
//
|
||||
// Produces: {sessionFolder}/phase-{N}/context.md
|
||||
```
|
||||
|
||||
**Command**: [commands/research.md](commands/research.md)
|
||||
|
||||
```javascript
|
||||
// Report research progress
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "plan_progress",
|
||||
summary: `[planner] Research complete for phase ${phaseNumber}. Context written.`,
|
||||
ref: `${sessionFolder}/phase-${phaseNumber}/context.md`
|
||||
})
|
||||
```
|
||||
|
||||
### Phase 3: Create Plans (via command)
|
||||
|
||||
```javascript
|
||||
// Delegate to create-plans command
|
||||
Read("commands/create-plans.md")
|
||||
// Execute plan creation steps:
|
||||
// 1. Load context.md for phase
|
||||
// 2. Prepare output directories (.task/)
|
||||
// 3. Delegate to action-planning-agent
|
||||
// 4. Agent produces IMPL_PLAN.md + .task/IMPL-*.json + TODO_LIST.md
|
||||
// 5. Validate generated artifacts
|
||||
// 6. Return task count and dependency structure
|
||||
//
|
||||
// Produces: {sessionFolder}/phase-{N}/IMPL_PLAN.md
|
||||
// {sessionFolder}/phase-{N}/.task/IMPL-*.json
|
||||
// {sessionFolder}/phase-{N}/TODO_LIST.md
|
||||
```
|
||||
|
||||
**Command**: [commands/create-plans.md](commands/create-plans.md)
|
||||
|
||||
### Phase 4: Self-Validation
|
||||
|
||||
```javascript
|
||||
// Verify task JSONs before reporting
|
||||
const taskFiles = Glob(`${sessionFolder}/phase-${phaseNumber}/.task/IMPL-*.json`)
|
||||
|
||||
for (const taskFile of taskFiles) {
|
||||
const taskJson = JSON.parse(Read(taskFile))
|
||||
|
||||
// 4a. Verify referenced files exist (for modify actions only)
|
||||
for (const fileEntry of (taskJson.files || [])) {
|
||||
if (fileEntry.action === 'modify') {
|
||||
const exists = Bash(`test -f "${fileEntry.path}" && echo "EXISTS" || echo "NOT_FOUND"`).trim()
|
||||
if (exists === "NOT_FOUND") {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "plan_progress",
|
||||
summary: `[planner] Warning: ${taskJson.id} references ${fileEntry.path} for modify but file not found`,
|
||||
ref: taskFile
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4b. Self-dependency check
|
||||
if ((taskJson.depends_on || []).includes(taskJson.id)) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "error",
|
||||
summary: `[planner] Self-dependency detected: ${taskJson.id}`,
|
||||
ref: taskFile
|
||||
})
|
||||
}
|
||||
|
||||
// 4c. Convergence criteria check
|
||||
if (!taskJson.convergence?.criteria?.length) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "plan_progress",
|
||||
summary: `[planner] Warning: ${taskJson.id} has no convergence criteria`,
|
||||
ref: taskFile
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 4d. Cross-dependency validation
|
||||
const allTasks = taskFiles.map(f => JSON.parse(Read(f)))
|
||||
const taskIds = new Set(allTasks.map(t => t.id))
|
||||
for (const task of allTasks) {
|
||||
for (const dep of (task.depends_on || [])) {
|
||||
if (!taskIds.has(dep)) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "plan_progress",
|
||||
summary: `[planner] Warning: ${task.id} depends on unknown task ${dep}`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
const taskCount = allTasks.length
|
||||
|
||||
// Compute wave count from dependency graph
|
||||
function computeWaveCount(tasks) {
|
||||
const waves = {}
|
||||
const assigned = new Set()
|
||||
let wave = 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) break
|
||||
for (const t of ready) { waves[t.id] = wave; assigned.add(t.id) }
|
||||
wave++
|
||||
}
|
||||
return wave - 1
|
||||
}
|
||||
const waveCount = computeWaveCount(allTasks)
|
||||
|
||||
// Log plan_ready message
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "planner", to: "coordinator",
|
||||
type: "plan_ready",
|
||||
summary: `[planner] Phase ${phaseNumber} planned: ${taskCount} tasks across ${waveCount} waves`,
|
||||
ref: `${sessionFolder}/phase-${phaseNumber}/`
|
||||
})
|
||||
|
||||
// Send message to coordinator
|
||||
SendMessage({
|
||||
to: "coordinator",
|
||||
message: `[planner] Phase ${phaseNumber} planning complete.
|
||||
- Tasks: ${taskCount}
|
||||
- Waves: ${waveCount}
|
||||
- IMPL_PLAN: ${sessionFolder}/phase-${phaseNumber}/IMPL_PLAN.md
|
||||
- Task JSONs: ${taskFiles.map(f => f).join(', ')}
|
||||
|
||||
All tasks validated. Ready for execution.`
|
||||
})
|
||||
|
||||
// Mark task complete
|
||||
TaskUpdate({ taskId: planTask.id, status: "completed" })
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| roadmap.md not found | Error to coordinator -- dispatch may have failed |
|
||||
| cli-explore-agent fails | Retry once. If still fails, use direct ACE search as fallback |
|
||||
| Gemini CLI fails | Skip deep analysis, proceed with basic context |
|
||||
| action-planning-agent fails | Retry once. If still fails, error to coordinator |
|
||||
| No task JSONs generated | Error to coordinator -- agent may have misunderstood input |
|
||||
| No requirements found for phase | Error to coordinator -- roadmap may be malformed |
|
||||
| Dependency cycle detected | Log warning, break cycle |
|
||||
| Referenced file not found | Log warning. If file is from prior wave, acceptable |
|
||||
@@ -0,0 +1,335 @@
|
||||
# Command: verify
|
||||
|
||||
Goal-backward verification of convergence criteria from IMPL-*.json task files against actual codebase state. Checks convergence criteria (measurable conditions), file operations (existence/content), and runs verification commands.
|
||||
|
||||
## Purpose
|
||||
|
||||
For each task's convergence criteria, verify that the expected goals are met in the actual codebase. This is goal-backward verification: check what should exist, NOT what tasks were done. Produce a structured pass/fail result per task with gap details for any failures.
|
||||
|
||||
## Key Principle
|
||||
|
||||
**Goal-backward, not task-forward.** Do not check "did the executor follow the steps?" — check "does the codebase now have the properties that were required?"
|
||||
|
||||
## When to Use
|
||||
|
||||
- Phase 3 of verifier execution (after loading targets, before compiling results)
|
||||
- Called once per VERIFY-* task
|
||||
|
||||
## Strategy
|
||||
|
||||
For each task, check convergence criteria and file operations. Use Bash for verification commands, Read/Grep for file checks, and optionally Gemini CLI for semantic validation of complex criteria.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Source | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `sessionFolder` | From VERIFY-* task description | Session artifact directory |
|
||||
| `phaseNumber` | From VERIFY-* task description | Phase number (1-based) |
|
||||
| `tasks` | From verifier Phase 2 | Parsed task JSON objects with convergence criteria |
|
||||
| `summaries` | From verifier Phase 2 | Parsed summary objects for context |
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Initialize Results
|
||||
|
||||
```javascript
|
||||
const verificationResults = []
|
||||
```
|
||||
|
||||
### Step 2: Verify Each Task
|
||||
|
||||
```javascript
|
||||
for (const task of tasks) {
|
||||
const taskResult = {
|
||||
task: task.id,
|
||||
title: task.title,
|
||||
status: 'pass', // will be downgraded if any check fails
|
||||
details: [],
|
||||
gaps: []
|
||||
}
|
||||
|
||||
// --- 2a. Check Convergence Criteria ---
|
||||
const criteria = task.convergence?.criteria || []
|
||||
for (const criterion of criteria) {
|
||||
const check = checkCriterion(criterion, task)
|
||||
taskResult.details.push({
|
||||
type: 'criterion',
|
||||
description: criterion,
|
||||
passed: check.passed
|
||||
})
|
||||
if (!check.passed) {
|
||||
taskResult.gaps.push({
|
||||
task: task.id,
|
||||
type: 'criterion',
|
||||
item: criterion,
|
||||
expected: criterion,
|
||||
actual: check.actual || 'Check failed'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// --- 2b. Check File Operations ---
|
||||
const files = task.files || []
|
||||
for (const fileEntry of files) {
|
||||
const fileChecks = checkFileEntry(fileEntry)
|
||||
for (const check of fileChecks) {
|
||||
taskResult.details.push(check.detail)
|
||||
if (!check.passed) {
|
||||
taskResult.gaps.push({
|
||||
...check.gap,
|
||||
task: task.id
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- 2c. Run Verification Command ---
|
||||
if (task.convergence?.verification) {
|
||||
const verifyCheck = runVerificationCommand(task.convergence.verification)
|
||||
taskResult.details.push({
|
||||
type: 'verification_command',
|
||||
description: `Verification: ${task.convergence.verification}`,
|
||||
passed: verifyCheck.passed
|
||||
})
|
||||
if (!verifyCheck.passed) {
|
||||
taskResult.gaps.push({
|
||||
task: task.id,
|
||||
type: 'verification_command',
|
||||
item: task.convergence.verification,
|
||||
expected: 'Command exits with code 0',
|
||||
actual: verifyCheck.actual || 'Command failed'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// --- 2d. Score task ---
|
||||
const totalChecks = taskResult.details.length
|
||||
const passedChecks = taskResult.details.filter(d => d.passed).length
|
||||
|
||||
if (passedChecks === totalChecks) {
|
||||
taskResult.status = 'pass'
|
||||
} else if (passedChecks > 0) {
|
||||
taskResult.status = 'partial'
|
||||
} else {
|
||||
taskResult.status = 'fail'
|
||||
}
|
||||
|
||||
verificationResults.push(taskResult)
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Criterion Checking Function
|
||||
|
||||
```javascript
|
||||
function checkCriterion(criterion, task) {
|
||||
// Criteria are measurable conditions
|
||||
// Strategy: derive testable assertions from criterion text
|
||||
|
||||
// Attempt 1: If criterion mentions a test command, run it
|
||||
const testMatch = criterion.match(/test[s]?\s+(pass|run|succeed)/i)
|
||||
if (testMatch) {
|
||||
const testResult = Bash(`npm test 2>&1 || yarn test 2>&1 || pytest 2>&1 || true`)
|
||||
const passed = !testResult.includes('FAIL') && !testResult.includes('failed')
|
||||
return { passed, actual: passed ? 'Tests pass' : 'Test failures detected' }
|
||||
}
|
||||
|
||||
// Attempt 2: If criterion mentions specific counts or exports, check files
|
||||
const filePaths = (task.files || []).map(f => f.path)
|
||||
for (const filePath of filePaths) {
|
||||
const exists = Bash(`test -f "${filePath}" && echo "EXISTS" || echo "NOT_FOUND"`).trim()
|
||||
if (exists === "EXISTS") {
|
||||
const content = Read(filePath)
|
||||
// Check if criterion keywords appear in the implementation
|
||||
const keywords = criterion.split(/\s+/).filter(w => w.length > 4)
|
||||
const relevant = keywords.filter(kw =>
|
||||
content.toLowerCase().includes(kw.toLowerCase())
|
||||
)
|
||||
if (relevant.length >= Math.ceil(keywords.length * 0.3)) {
|
||||
return { passed: true, actual: 'Implementation contains relevant logic' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt 3: Compile check for affected files
|
||||
for (const filePath of filePaths) {
|
||||
if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
|
||||
const compileCheck = Bash(`npx tsc --noEmit "${filePath}" 2>&1 || true`)
|
||||
if (compileCheck.includes('error TS')) {
|
||||
return { passed: false, actual: `TypeScript errors in ${filePath}` }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default: mark as passed if files exist and compile
|
||||
return { passed: true, actual: 'Files exist and compile without errors' }
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: File Entry Checking Function
|
||||
|
||||
```javascript
|
||||
function checkFileEntry(fileEntry) {
|
||||
const checks = []
|
||||
const path = fileEntry.path
|
||||
const action = fileEntry.action // create, modify, delete
|
||||
|
||||
// 4a. Check file existence based on action
|
||||
const exists = Bash(`test -f "${path}" && echo "EXISTS" || echo "NOT_FOUND"`).trim()
|
||||
|
||||
if (action === 'create' || action === 'modify') {
|
||||
checks.push({
|
||||
passed: exists === "EXISTS",
|
||||
detail: {
|
||||
type: 'file',
|
||||
description: `File exists: ${path} (${action})`,
|
||||
passed: exists === "EXISTS"
|
||||
},
|
||||
gap: exists !== "EXISTS" ? {
|
||||
type: 'file',
|
||||
item: `file_exists: ${path}`,
|
||||
expected: `File should exist (action: ${action})`,
|
||||
actual: 'File not found'
|
||||
} : null
|
||||
})
|
||||
|
||||
if (exists !== "EXISTS") {
|
||||
return checks.filter(c => c.gap !== null || c.passed)
|
||||
}
|
||||
|
||||
// 4b. Check minimum content (non-empty for create)
|
||||
if (action === 'create') {
|
||||
const content = Read(path)
|
||||
const lineCount = content.split('\n').length
|
||||
const minLines = 3 // Minimum for a meaningful file
|
||||
checks.push({
|
||||
passed: lineCount >= minLines,
|
||||
detail: {
|
||||
type: 'file',
|
||||
description: `${path}: has content (${lineCount} lines)`,
|
||||
passed: lineCount >= minLines
|
||||
},
|
||||
gap: lineCount < minLines ? {
|
||||
type: 'file',
|
||||
item: `min_content: ${path}`,
|
||||
expected: `>= ${minLines} lines`,
|
||||
actual: `${lineCount} lines`
|
||||
} : null
|
||||
})
|
||||
}
|
||||
} else if (action === 'delete') {
|
||||
checks.push({
|
||||
passed: exists === "NOT_FOUND",
|
||||
detail: {
|
||||
type: 'file',
|
||||
description: `File deleted: ${path}`,
|
||||
passed: exists === "NOT_FOUND"
|
||||
},
|
||||
gap: exists !== "NOT_FOUND" ? {
|
||||
type: 'file',
|
||||
item: `file_deleted: ${path}`,
|
||||
expected: 'File should be deleted',
|
||||
actual: 'File still exists'
|
||||
} : null
|
||||
})
|
||||
}
|
||||
|
||||
return checks.filter(c => c.gap !== null || c.passed)
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Verification Command Runner
|
||||
|
||||
```javascript
|
||||
function runVerificationCommand(command) {
|
||||
try {
|
||||
const result = Bash(`${command} 2>&1; echo "EXIT:$?"`)
|
||||
const exitCodeMatch = result.match(/EXIT:(\d+)/)
|
||||
const exitCode = exitCodeMatch ? parseInt(exitCodeMatch[1]) : 1
|
||||
return {
|
||||
passed: exitCode === 0,
|
||||
actual: exitCode === 0 ? 'Command succeeded' : `Exit code: ${exitCode}\n${result.slice(0, 200)}`
|
||||
}
|
||||
} catch (e) {
|
||||
return { passed: false, actual: `Command error: ${e.message}` }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 6: Write verification.md
|
||||
|
||||
```javascript
|
||||
const totalGaps = verificationResults.flatMap(r => r.gaps)
|
||||
const overallStatus = totalGaps.length === 0 ? 'passed' : 'gaps_found'
|
||||
|
||||
Write(`${sessionFolder}/phase-${phaseNumber}/verification.md`, `---
|
||||
phase: ${phaseNumber}
|
||||
status: ${overallStatus}
|
||||
tasks_checked: ${tasks.length}
|
||||
tasks_passed: ${verificationResults.filter(r => r.status === 'pass').length}
|
||||
gaps:
|
||||
${totalGaps.map(g => ` - task: "${g.task}"
|
||||
type: "${g.type}"
|
||||
item: "${g.item}"
|
||||
expected: "${g.expected}"
|
||||
actual: "${g.actual}"`).join('\n')}
|
||||
---
|
||||
|
||||
# Phase ${phaseNumber} Verification
|
||||
|
||||
## Summary
|
||||
|
||||
- **Status**: ${overallStatus}
|
||||
- **Tasks Checked**: ${tasks.length}
|
||||
- **Passed**: ${verificationResults.filter(r => r.status === 'pass').length}
|
||||
- **Partial**: ${verificationResults.filter(r => r.status === 'partial').length}
|
||||
- **Failed**: ${verificationResults.filter(r => r.status === 'fail').length}
|
||||
- **Total Gaps**: ${totalGaps.length}
|
||||
|
||||
## Task Results
|
||||
|
||||
${verificationResults.map(r => `### ${r.task}: ${r.title} — ${r.status.toUpperCase()}
|
||||
${r.details.map(d => `- [${d.passed ? 'x' : ' '}] (${d.type}) ${d.description}`).join('\n')}`).join('\n\n')}
|
||||
|
||||
${totalGaps.length > 0 ? `## Gaps for Re-Planning
|
||||
|
||||
The following gaps must be addressed in a gap closure iteration:
|
||||
|
||||
${totalGaps.map((g, i) => `### Gap ${i + 1}
|
||||
- **Task**: ${g.task}
|
||||
- **Type**: ${g.type}
|
||||
- **Item**: ${g.item}
|
||||
- **Expected**: ${g.expected}
|
||||
- **Actual**: ${g.actual}`).join('\n\n')}` : '## All Goals Met'}
|
||||
`)
|
||||
```
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
### Convergence Criteria
|
||||
|
||||
| Check Method | Tool | When |
|
||||
|--------------|------|------|
|
||||
| Run tests | Bash(`npm test`) | Criterion mentions "test" |
|
||||
| Compile check | Bash(`npx tsc --noEmit`) | TypeScript files |
|
||||
| Keyword match | Read + string match | General behavioral criteria |
|
||||
| Verification command | Bash(convergence.verification) | Always if provided |
|
||||
| Semantic check | Gemini CLI (analysis) | Complex criteria (optional) |
|
||||
|
||||
### File Operations
|
||||
|
||||
| Check | Tool | What |
|
||||
|-------|------|------|
|
||||
| File exists (create/modify) | Bash(`test -f`) | files[].path with action create/modify |
|
||||
| File deleted | Bash(`test -f`) | files[].path with action delete |
|
||||
| Minimum content | Read + line count | Newly created files |
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| No task JSON files found | Error to coordinator -- planner may have failed |
|
||||
| No summary files found | Error to coordinator -- executor may have failed |
|
||||
| Verification command fails | Record as gap with error output |
|
||||
| File referenced in task missing | Record as gap (file type) |
|
||||
| Task JSON malformed (no convergence) | Log warning, score as pass (nothing to check) |
|
||||
| All checks for a task fail | Score as 'fail', include all gaps |
|
||||
267
.claude/skills/team-roadmap-dev/roles/verifier/role.md
Normal file
267
.claude/skills/team-roadmap-dev/roles/verifier/role.md
Normal file
@@ -0,0 +1,267 @@
|
||||
# Role: verifier
|
||||
|
||||
Goal-backward verification per phase. Reads convergence criteria from IMPL-*.json task files and checks them against the actual codebase state after execution. Does NOT modify code — read-only validation. Produces verification.md with pass/fail results and structured gap lists.
|
||||
|
||||
## Role Identity
|
||||
|
||||
- **Name**: `verifier`
|
||||
- **Task Prefix**: `VERIFY-*`
|
||||
- **Responsibility**: Validation
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
- **Output Tag**: `[verifier]`
|
||||
|
||||
## Role Boundaries
|
||||
|
||||
### MUST
|
||||
|
||||
- All outputs must carry `[verifier]` prefix
|
||||
- Only process `VERIFY-*` prefixed tasks
|
||||
- Only communicate with coordinator (SendMessage)
|
||||
- Delegate verification to commands/verify.md
|
||||
- Check goals (what should exist), NOT tasks (what was done)
|
||||
- Produce structured gap lists for failed items
|
||||
- Remain read-only -- never modify source code
|
||||
|
||||
### MUST NOT
|
||||
|
||||
- Modify any source code or project files
|
||||
- Create plans or execute implementations
|
||||
- Create tasks for other roles (TaskCreate)
|
||||
- Interact with user (AskUserQuestion)
|
||||
- Process PLAN-* or EXEC-* tasks
|
||||
- Auto-fix issues (report them, let planner/executor handle fixes)
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `verify_passed` | verifier -> coordinator | All must_haves met | Phase verification passed |
|
||||
| `gaps_found` | verifier -> coordinator | Some must_haves failed | Structured gap list for re-planning |
|
||||
| `error` | verifier -> coordinator | Failure | Verification process failed |
|
||||
|
||||
## Message Bus
|
||||
|
||||
```javascript
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "verifier", to: "coordinator",
|
||||
type: messageType,
|
||||
summary: `[verifier] ${messageSummary}`,
|
||||
ref: artifactPath
|
||||
})
|
||||
```
|
||||
|
||||
### CLI Fallback
|
||||
|
||||
```javascript
|
||||
Bash(`ccw team log --team "roadmap-dev" --from "verifier" --to "coordinator" --type "${type}" --summary "[verifier] ${summary}" --json`)
|
||||
```
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | File | Phase | Description |
|
||||
|---------|------|-------|-------------|
|
||||
| `verify` | [commands/verify.md](commands/verify.md) | Phase 3 | Goal-backward must_haves checking |
|
||||
|
||||
### Available Subagents
|
||||
|
||||
None. Verifier executes checks directly using built-in tools (Read, Grep, Bash).
|
||||
|
||||
### CLI Tools
|
||||
|
||||
| Tool | Mode | When |
|
||||
|------|------|------|
|
||||
| `gemini` | analysis | Deep semantic checks for complex truths (optional) |
|
||||
|
||||
## Execution
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
// Find assigned VERIFY-* task
|
||||
const tasks = TaskList()
|
||||
const verifyTask = tasks.find(t =>
|
||||
t.subject.startsWith('VERIFY-') &&
|
||||
t.status === 'pending' &&
|
||||
(!t.blockedBy || t.blockedBy.length === 0)
|
||||
)
|
||||
|
||||
if (!verifyTask) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "verifier", to: "coordinator",
|
||||
type: "error",
|
||||
summary: "[verifier] No available VERIFY-* task found"
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
TaskUpdate({ taskId: verifyTask.id, status: "in_progress" })
|
||||
|
||||
// Parse task description for session context
|
||||
const taskDetails = TaskGet({ taskId: verifyTask.id })
|
||||
const sessionFolder = parseSessionFolder(taskDetails.description)
|
||||
const phaseNumber = parsePhaseNumber(taskDetails.description)
|
||||
```
|
||||
|
||||
### Phase 2: Load Verification Targets
|
||||
|
||||
```javascript
|
||||
// Read all task JSON files for convergence criteria
|
||||
const taskFiles = Glob(`${sessionFolder}/phase-${phaseNumber}/.task/IMPL-*.json`)
|
||||
const tasks = []
|
||||
|
||||
for (const taskFile of taskFiles) {
|
||||
const taskJson = JSON.parse(Read(taskFile))
|
||||
tasks.push({
|
||||
...taskJson,
|
||||
file: taskFile
|
||||
})
|
||||
}
|
||||
|
||||
// Read all summary files for what was done
|
||||
const summaryFiles = Glob(`${sessionFolder}/phase-${phaseNumber}/summary-*.md`)
|
||||
const summaries = []
|
||||
|
||||
for (const summaryFile of summaryFiles) {
|
||||
const content = Read(summaryFile)
|
||||
const frontmatter = parseYamlFrontmatter(content)
|
||||
summaries.push({
|
||||
file: summaryFile,
|
||||
task: frontmatter.task,
|
||||
affects: frontmatter.affects || frontmatter['key-files'] || [],
|
||||
provides: frontmatter.provides || []
|
||||
})
|
||||
}
|
||||
|
||||
if (tasks.length === 0) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "verifier", to: "coordinator",
|
||||
type: "error",
|
||||
summary: `[verifier] No task JSON files found in ${sessionFolder}/phase-${phaseNumber}/.task/`
|
||||
})
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 3: Goal-Backward Verification (via command)
|
||||
|
||||
```javascript
|
||||
// Delegate to verify command
|
||||
Read("commands/verify.md")
|
||||
// Execute goal-backward verification:
|
||||
// 1. For each task's convergence criteria: check criteria, files, verification command
|
||||
// 2. Score each task: pass / partial / fail
|
||||
// 3. Compile gap list
|
||||
//
|
||||
// Produces: verificationResults (structured data)
|
||||
```
|
||||
|
||||
**Command**: [commands/verify.md](commands/verify.md)
|
||||
|
||||
### Phase 4: Compile Results
|
||||
|
||||
```javascript
|
||||
// Aggregate pass/fail per task
|
||||
const results = {
|
||||
totalTasks: tasks.length,
|
||||
passed: 0,
|
||||
partial: 0,
|
||||
failed: 0,
|
||||
gaps: []
|
||||
}
|
||||
|
||||
for (const taskResult of verificationResults) {
|
||||
if (taskResult.status === 'pass') {
|
||||
results.passed++
|
||||
} else if (taskResult.status === 'partial') {
|
||||
results.partial++
|
||||
results.gaps.push(...taskResult.gaps)
|
||||
} else {
|
||||
results.failed++
|
||||
results.gaps.push(...taskResult.gaps)
|
||||
}
|
||||
}
|
||||
|
||||
const overallStatus = results.gaps.length === 0 ? 'passed' : 'gaps_found'
|
||||
```
|
||||
|
||||
### Phase 5: Write verification.md + Report
|
||||
|
||||
```javascript
|
||||
const verificationPath = `${sessionFolder}/phase-${phaseNumber}/verification.md`
|
||||
|
||||
Write(verificationPath, `---
|
||||
phase: ${phaseNumber}
|
||||
status: ${overallStatus}
|
||||
tasks_checked: ${results.totalTasks}
|
||||
tasks_passed: ${results.passed}
|
||||
gaps:
|
||||
${results.gaps.map(g => ` - task: "${g.task}"
|
||||
type: "${g.type}"
|
||||
item: "${g.item}"
|
||||
expected: "${g.expected}"
|
||||
actual: "${g.actual}"`).join('\n')}
|
||||
---
|
||||
|
||||
# Phase ${phaseNumber} Verification
|
||||
|
||||
## Summary
|
||||
|
||||
- **Status**: ${overallStatus}
|
||||
- **Tasks Checked**: ${results.totalTasks}
|
||||
- **Passed**: ${results.passed}
|
||||
- **Partial**: ${results.partial}
|
||||
- **Failed**: ${results.failed}
|
||||
- **Total Gaps**: ${results.gaps.length}
|
||||
|
||||
## Task Results
|
||||
|
||||
${verificationResults.map(r => `### ${r.task}: ${r.title} — ${r.status.toUpperCase()}
|
||||
${r.details.map(d => `- [${d.passed ? 'x' : ' '}] (${d.type}) ${d.description}`).join('\n')}`).join('\n\n')}
|
||||
|
||||
${results.gaps.length > 0 ? `## Gaps
|
||||
|
||||
${results.gaps.map((g, i) => `### Gap ${i + 1}: ${g.task} - ${g.type}
|
||||
- **Expected**: ${g.expected}
|
||||
- **Actual**: ${g.actual}
|
||||
- **Item**: ${g.item}`).join('\n\n')}` : '## No Gaps Found'}
|
||||
`)
|
||||
|
||||
const messageType = overallStatus === 'passed' ? 'verify_passed' : 'gaps_found'
|
||||
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: "roadmap-dev",
|
||||
from: "verifier", to: "coordinator",
|
||||
type: messageType,
|
||||
summary: `[verifier] Phase ${phaseNumber} verification: ${overallStatus}. ${results.passed}/${results.totalTasks} tasks passed. ${results.gaps.length} gaps.`,
|
||||
ref: verificationPath
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
to: "coordinator",
|
||||
message: `[verifier] Phase ${phaseNumber} verification complete.
|
||||
- Status: ${overallStatus}
|
||||
- Tasks: ${results.passed}/${results.totalTasks} passed
|
||||
- Gaps: ${results.gaps.length}
|
||||
${results.gaps.length > 0 ? `\nGap summary:\n${results.gaps.map(g => `- ${g.task}, ${g.type}: ${g.item}`).join('\n')}` : ''}
|
||||
|
||||
Verification written to: ${verificationPath}`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: verifyTask.id, status: "completed" })
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| No task JSON files found | Error to coordinator -- planner may have failed |
|
||||
| No summary files found | Error to coordinator -- executor may have failed |
|
||||
| File referenced in task missing | Record as gap (file type) |
|
||||
| Bash command fails during check | Record as gap with error message |
|
||||
| Verification command fails | Record as gap with exit code |
|
||||
| Gemini CLI fails | Fallback to direct checks, skip semantic analysis |
|
||||
96
.claude/skills/team-roadmap-dev/specs/team-config.json
Normal file
96
.claude/skills/team-roadmap-dev/specs/team-config.json
Normal file
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"team_name": "roadmap-dev",
|
||||
"team_display_name": "Roadmap Dev",
|
||||
"skill_name": "team-roadmap-dev",
|
||||
"skill_path": ".claude/skills/team-roadmap-dev/",
|
||||
"design_source": "roadmap-driven development workflow design (2026-02-24)",
|
||||
"pipeline_type": "Phased",
|
||||
"pipeline": {
|
||||
"stages": [
|
||||
{ "name": "PLAN", "role": "planner", "blockedBy": [] },
|
||||
{ "name": "EXEC", "role": "executor", "blockedBy": ["PLAN"] },
|
||||
{ "name": "VERIFY", "role": "verifier", "blockedBy": ["EXEC"] }
|
||||
],
|
||||
"diagram": "Coordinator (roadmap) → PLAN → EXEC → VERIFY → Coordinator (transition)",
|
||||
"gap_closure": "VERIFY fails → PLAN (gaps) → EXEC (gaps) → VERIFY (re-check), max 3 iterations"
|
||||
},
|
||||
"roles": [
|
||||
{
|
||||
"name": "coordinator",
|
||||
"display_name": "RD Coordinator",
|
||||
"responsibility_type": "Orchestration",
|
||||
"task_prefix": null,
|
||||
"description": "Human interaction, roadmap discussion, phase transitions, state management",
|
||||
"commands": ["roadmap-discuss", "dispatch", "monitor", "pause", "resume"],
|
||||
"message_types": ["phase_started", "phase_complete", "gap_closure", "project_complete", "error"]
|
||||
},
|
||||
{
|
||||
"name": "planner",
|
||||
"display_name": "RD Planner",
|
||||
"responsibility_type": "Orchestration",
|
||||
"task_prefix": "PLAN",
|
||||
"description": "Research, context gathering, task JSON generation via action-planning-agent",
|
||||
"commands": ["research", "create-plans"],
|
||||
"subagents": ["cli-explore-agent", "action-planning-agent"],
|
||||
"cli_tools": [{"tool": "gemini", "mode": "analysis"}],
|
||||
"message_types": ["plan_ready", "plan_progress", "error"]
|
||||
},
|
||||
{
|
||||
"name": "executor",
|
||||
"display_name": "RD Executor",
|
||||
"responsibility_type": "Code generation",
|
||||
"task_prefix": "EXEC",
|
||||
"description": "Code implementation from IMPL-*.json tasks, wave-based parallel execution",
|
||||
"commands": ["implement"],
|
||||
"subagents": ["code-developer"],
|
||||
"message_types": ["exec_complete", "exec_progress", "error"]
|
||||
},
|
||||
{
|
||||
"name": "verifier",
|
||||
"display_name": "RD Verifier",
|
||||
"responsibility_type": "Validation",
|
||||
"task_prefix": "VERIFY",
|
||||
"description": "Convergence criteria verification, gap detection, fix loop trigger",
|
||||
"commands": ["verify"],
|
||||
"cli_tools": [{"tool": "gemini", "mode": "analysis"}],
|
||||
"message_types": ["verify_passed", "gaps_found", "error"]
|
||||
}
|
||||
],
|
||||
"artifacts": {
|
||||
"fixed": {
|
||||
"roadmap.md": {
|
||||
"created_by": "coordinator (roadmap-discuss)",
|
||||
"purpose": "Phase plan with requirements and success criteria",
|
||||
"lifecycle": "Created once, updated at phase transitions"
|
||||
},
|
||||
"state.md": {
|
||||
"created_by": "coordinator",
|
||||
"purpose": "Living memory (<100 lines)",
|
||||
"lifecycle": "Updated every significant action"
|
||||
},
|
||||
"config.json": {
|
||||
"created_by": "coordinator (roadmap-discuss)",
|
||||
"purpose": "Session settings: mode, depth, gates",
|
||||
"lifecycle": "Created once, rarely updated"
|
||||
}
|
||||
},
|
||||
"dynamic": {
|
||||
"context.md": { "created_by": "planner (research)", "per": "phase" },
|
||||
"IMPL_PLAN.md": { "created_by": "planner (create-plans)", "per": "phase", "purpose": "Implementation overview with task dependency graph" },
|
||||
"IMPL-*.json": { "created_by": "planner (create-plans)", "per": "phase", "path": ".task/", "schema": "unified-flat-schema", "purpose": "Task JSON files with convergence criteria" },
|
||||
"TODO_LIST.md": { "created_by": "planner (create-plans)", "per": "phase", "purpose": "Checklist tracking for all tasks" },
|
||||
"summary-{ID}.md": { "created_by": "executor (implement)", "per": "task", "yaml_frontmatter": true },
|
||||
"verification.md": { "created_by": "verifier (verify)", "per": "phase" }
|
||||
}
|
||||
},
|
||||
"init_prerequisite": {
|
||||
"required_files": [".workflow/project-tech.json"],
|
||||
"optional_files": [".workflow/project-guidelines.json"],
|
||||
"init_command": "/workflow:init"
|
||||
},
|
||||
"_metadata": {
|
||||
"created_at": "2026-02-24",
|
||||
"version": "1.1.0",
|
||||
"based_on": "roadmap-driven development workflow design"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user