mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-09 02:24:11 +08:00
Add end-to-end tests for Graph Explorer, History, Orchestrator, and Project features
- Implemented E2E tests for code relationship visualization in Graph Explorer. - Added tests for archived session management in History, including search, filter, restore, and delete functionalities. - Created tests for workflow orchestration in Orchestrator, covering node creation, connection, deletion, and workflow management. - Developed tests for project statistics and timeline visualization in Project, including error handling and internationalization checks.
This commit is contained in:
301
.codex/skills/ccw-loop-b/README.md
Normal file
301
.codex/skills/ccw-loop-b/README.md
Normal file
@@ -0,0 +1,301 @@
|
||||
# CCW Loop-B: Hybrid Orchestrator Pattern
|
||||
|
||||
Iterative development workflow using coordinator + specialized workers architecture.
|
||||
|
||||
## Overview
|
||||
|
||||
CCW Loop-B implements a flexible orchestration pattern:
|
||||
- **Coordinator**: Main agent managing state, user interaction, worker scheduling
|
||||
- **Workers**: Specialized agents (init, develop, debug, validate, complete)
|
||||
- **Modes**: Interactive / Auto / Parallel execution
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Coordinator (Main Agent)
|
||||
|
|
||||
+-- Spawns Workers
|
||||
| - ccw-loop-b-init.md
|
||||
| - ccw-loop-b-develop.md
|
||||
| - ccw-loop-b-debug.md
|
||||
| - ccw-loop-b-validate.md
|
||||
| - ccw-loop-b-complete.md
|
||||
|
|
||||
+-- Batch Wait (parallel mode)
|
||||
+-- Sequential Wait (auto/interactive)
|
||||
+-- State Management
|
||||
+-- User Interaction
|
||||
```
|
||||
|
||||
## Subagent API
|
||||
|
||||
Core APIs for worker orchestration:
|
||||
|
||||
| API | 作用 |
|
||||
|-----|------|
|
||||
| `spawn_agent({ message })` | 创建 worker,返回 `agent_id` |
|
||||
| `wait({ ids, timeout_ms })` | 等待结果(唯一取结果入口) |
|
||||
| `send_input({ id, message })` | 继续交互 |
|
||||
| `close_agent({ id })` | 关闭回收 |
|
||||
|
||||
**可用模式**: 单 agent 深度交互 / 多 agent 并行 / 混合模式
|
||||
|
||||
## Execution Modes
|
||||
|
||||
### Interactive Mode (default)
|
||||
|
||||
Coordinator displays menu, user selects action, spawns corresponding worker.
|
||||
|
||||
```bash
|
||||
/ccw-loop-b TASK="Implement feature X"
|
||||
```
|
||||
|
||||
**Flow**:
|
||||
1. Init: Parse task, create breakdown
|
||||
2. Menu: Show options to user
|
||||
3. User selects action (develop/debug/validate)
|
||||
4. Spawn worker for selected action
|
||||
5. Wait for result
|
||||
6. Display result, back to menu
|
||||
7. Repeat until complete
|
||||
|
||||
### Auto Mode
|
||||
|
||||
Automated sequential execution following predefined workflow.
|
||||
|
||||
```bash
|
||||
/ccw-loop-b --mode=auto TASK="Fix bug Y"
|
||||
```
|
||||
|
||||
**Flow**:
|
||||
1. Init → 2. Develop → 3. Validate → 4. Complete
|
||||
|
||||
If issues found: loop back to Debug → Develop → Validate
|
||||
|
||||
### Parallel Mode
|
||||
|
||||
Spawn multiple workers simultaneously, batch wait for results.
|
||||
|
||||
```bash
|
||||
/ccw-loop-b --mode=parallel TASK="Analyze module Z"
|
||||
```
|
||||
|
||||
**Flow**:
|
||||
1. Init: Create analysis plan
|
||||
2. Spawn workers in parallel: [develop, debug, validate]
|
||||
3. Batch wait: `wait({ ids: [w1, w2, w3] })`
|
||||
4. Merge results
|
||||
5. Coordinator decides next action
|
||||
6. Complete
|
||||
|
||||
## Session Structure
|
||||
|
||||
```
|
||||
.workflow/.loop/
|
||||
+-- {loopId}.json # Master state
|
||||
+-- {loopId}.workers/ # Worker outputs
|
||||
| +-- init.output.json
|
||||
| +-- develop.output.json
|
||||
| +-- debug.output.json
|
||||
| +-- validate.output.json
|
||||
| +-- complete.output.json
|
||||
+-- {loopId}.progress/ # Human-readable logs
|
||||
+-- develop.md
|
||||
+-- debug.md
|
||||
+-- validate.md
|
||||
+-- summary.md
|
||||
```
|
||||
|
||||
## Worker Responsibilities
|
||||
|
||||
| Worker | Role | Specialization |
|
||||
|--------|------|----------------|
|
||||
| **init** | Session initialization | Task parsing, breakdown, planning |
|
||||
| **develop** | Code implementation | File operations, pattern matching, incremental development |
|
||||
| **debug** | Problem diagnosis | Root cause analysis, hypothesis testing, fix recommendations |
|
||||
| **validate** | Testing & verification | Test execution, coverage analysis, quality gates |
|
||||
| **complete** | Session finalization | Summary generation, commit preparation, cleanup |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Example 1: Simple Feature Implementation
|
||||
|
||||
```bash
|
||||
/ccw-loop-b TASK="Add user logout function"
|
||||
```
|
||||
|
||||
**Auto flow**:
|
||||
- Init: Parse requirements
|
||||
- Develop: Implement logout in `src/auth.ts`
|
||||
- Validate: Run tests
|
||||
- Complete: Generate commit message
|
||||
|
||||
### Example 2: Bug Investigation
|
||||
|
||||
```bash
|
||||
/ccw-loop-b TASK="Fix memory leak in WebSocket handler"
|
||||
```
|
||||
|
||||
**Interactive flow**:
|
||||
1. Init: Parse issue
|
||||
2. User selects "debug" → Spawn debug worker
|
||||
3. Debug: Root cause analysis → recommends fix
|
||||
4. User selects "develop" → Apply fix
|
||||
5. User selects "validate" → Verify fix works
|
||||
6. User selects "complete" → Generate summary
|
||||
|
||||
### Example 3: Comprehensive Analysis
|
||||
|
||||
```bash
|
||||
/ccw-loop-b --mode=parallel TASK="Analyze payment module for improvements"
|
||||
```
|
||||
|
||||
**Parallel flow**:
|
||||
- Spawn [develop, debug, validate] workers simultaneously
|
||||
- Develop: Analyze code quality and patterns
|
||||
- Debug: Identify potential issues
|
||||
- Validate: Check test coverage
|
||||
- Wait for all three to complete
|
||||
- Merge findings into comprehensive report
|
||||
|
||||
### Example 4: Resume Existing Loop
|
||||
|
||||
```bash
|
||||
/ccw-loop-b --loop-id=loop-b-20260122-abc123
|
||||
```
|
||||
|
||||
Continues from previous state, respects status (running/paused).
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. Worker Specialization
|
||||
|
||||
Each worker focuses on one domain:
|
||||
- **No overlap**: Clear boundaries between workers
|
||||
- **Reusable**: Same worker for different tasks
|
||||
- **Composable**: Combine workers for complex workflows
|
||||
|
||||
### 2. Flexible Coordination
|
||||
|
||||
Coordinator adapts to mode:
|
||||
- **Interactive**: Menu-driven, user controls flow
|
||||
- **Auto**: Predetermined sequence
|
||||
- **Parallel**: Concurrent execution with batch wait
|
||||
|
||||
### 3. State Management
|
||||
|
||||
Unified state at `.workflow/.loop/{loopId}.json`:
|
||||
- **API compatible**: Works with CCW API
|
||||
- **Extension fields**: Skill-specific data in `skill_state`
|
||||
- **Worker outputs**: Structured JSON for each action
|
||||
|
||||
### 4. Progress Tracking
|
||||
|
||||
Human-readable logs:
|
||||
- **Per-worker progress**: `{action}.md` files
|
||||
- **Summary**: Consolidated achievements
|
||||
- **Commit-ready**: Formatted commit messages
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Start with Init**: Always initialize before execution
|
||||
2. **Use appropriate mode**:
|
||||
- Interactive: Complex tasks needing user decisions
|
||||
- Auto: Well-defined workflows
|
||||
- Parallel: Independent analysis tasks
|
||||
3. **Clean up workers**: `close_agent()` after each worker completes
|
||||
4. **Batch wait wisely**: Use in parallel mode for efficiency
|
||||
5. **Track progress**: Document in progress files
|
||||
6. **Validate often**: After each develop phase
|
||||
|
||||
## Implementation Patterns
|
||||
|
||||
### Pattern 1: Single Worker Deep Interaction
|
||||
|
||||
```javascript
|
||||
const workerId = spawn_agent({ message: workerPrompt })
|
||||
const result1 = wait({ ids: [workerId] })
|
||||
|
||||
// Continue with same worker
|
||||
send_input({ id: workerId, message: "Continue with next task" })
|
||||
const result2 = wait({ ids: [workerId] })
|
||||
|
||||
close_agent({ id: workerId })
|
||||
```
|
||||
|
||||
### Pattern 2: Multi-Worker Parallel
|
||||
|
||||
```javascript
|
||||
const workers = {
|
||||
develop: spawn_agent({ message: developPrompt }),
|
||||
debug: spawn_agent({ message: debugPrompt }),
|
||||
validate: spawn_agent({ message: validatePrompt })
|
||||
}
|
||||
|
||||
// Batch wait
|
||||
const results = wait({ ids: Object.values(workers), timeout_ms: 900000 })
|
||||
|
||||
// Process all results
|
||||
Object.values(workers).forEach(id => close_agent({ id }))
|
||||
```
|
||||
|
||||
### Pattern 3: Sequential Worker Chain
|
||||
|
||||
```javascript
|
||||
const actions = ['init', 'develop', 'validate', 'complete']
|
||||
|
||||
for (const action of actions) {
|
||||
const workerId = spawn_agent({ message: buildPrompt(action) })
|
||||
const result = wait({ ids: [workerId] })
|
||||
|
||||
updateState(action, result)
|
||||
close_agent({ id: workerId })
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Recovery |
|
||||
|-------|----------|
|
||||
| Worker timeout | `send_input` request convergence |
|
||||
| Worker fails | Log error, coordinator decides retry strategy |
|
||||
| Partial results | Use completed workers, mark incomplete |
|
||||
| State corruption | Rebuild from progress files |
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
.codex/skills/ccw-loop-b/
|
||||
+-- SKILL.md # Entry point
|
||||
+-- README.md # This file
|
||||
+-- phases/
|
||||
| +-- state-schema.md # State structure definition
|
||||
+-- specs/
|
||||
+-- action-catalog.md # Action reference
|
||||
|
||||
.codex/agents/
|
||||
+-- ccw-loop-b-init.md # Worker: Init
|
||||
+-- ccw-loop-b-develop.md # Worker: Develop
|
||||
+-- ccw-loop-b-debug.md # Worker: Debug
|
||||
+-- ccw-loop-b-validate.md # Worker: Validate
|
||||
+-- ccw-loop-b-complete.md # Worker: Complete
|
||||
```
|
||||
|
||||
## Comparison: ccw-loop vs ccw-loop-b
|
||||
|
||||
| Aspect | ccw-loop | ccw-loop-b |
|
||||
|--------|----------|------------|
|
||||
| Pattern | Single agent, multi-phase | Coordinator + workers |
|
||||
| Worker model | Single agent handles all | Specialized workers per action |
|
||||
| Parallelization | Sequential only | Supports parallel mode |
|
||||
| Flexibility | Fixed sequence | Mode-based (interactive/auto/parallel) |
|
||||
| Best for | Simple linear workflows | Complex tasks needing specialization |
|
||||
|
||||
## Contributing
|
||||
|
||||
To add new workers:
|
||||
1. Create worker role file in `.codex/agents/`
|
||||
2. Define clear responsibilities
|
||||
3. Update `action-catalog.md`
|
||||
4. Add worker to coordinator spawn logic
|
||||
5. Test integration with existing workers
|
||||
323
.codex/skills/ccw-loop-b/SKILL.md
Normal file
323
.codex/skills/ccw-loop-b/SKILL.md
Normal file
@@ -0,0 +1,323 @@
|
||||
---
|
||||
name: CCW Loop-B
|
||||
description: Hybrid orchestrator pattern for iterative development. Coordinator + specialized workers with batch wait support. Triggers on "ccw-loop-b".
|
||||
argument-hint: TASK="<task description>" [--loop-id=<id>] [--mode=<interactive|auto|parallel>]
|
||||
---
|
||||
|
||||
# CCW Loop-B - Hybrid Orchestrator Pattern
|
||||
|
||||
协调器 + 专用 worker 的迭代开发工作流。支持单 agent 深度交互、多 agent 并行、混合模式灵活切换。
|
||||
|
||||
## Arguments
|
||||
|
||||
| Arg | Required | Description |
|
||||
|-----|----------|-------------|
|
||||
| TASK | No | Task description (for new loop) |
|
||||
| --loop-id | No | Existing loop ID to continue |
|
||||
| --mode | No | `interactive` (default) / `auto` / `parallel` |
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
+------------------------------------------------------------+
|
||||
| Main Coordinator |
|
||||
| 职责: 状态管理 + worker 调度 + 结果汇聚 + 用户交互 |
|
||||
+------------------------------------------------------------+
|
||||
|
|
||||
+--------------------+--------------------+
|
||||
| | |
|
||||
v v v
|
||||
+----------------+ +----------------+ +----------------+
|
||||
| Worker-Develop | | Worker-Debug | | Worker-Validate|
|
||||
| 专注: 代码实现 | | 专注: 问题诊断 | | 专注: 测试验证 |
|
||||
+----------------+ +----------------+ +----------------+
|
||||
```
|
||||
|
||||
## Execution Modes
|
||||
|
||||
### Mode: Interactive (default)
|
||||
|
||||
协调器展示菜单,用户选择 action,spawn 对应 worker 执行。
|
||||
|
||||
```
|
||||
Coordinator -> Show menu -> User selects -> spawn worker -> wait -> Display result -> Loop
|
||||
```
|
||||
|
||||
### Mode: Auto
|
||||
|
||||
自动按预设顺序执行,worker 完成后自动切换到下一阶段。
|
||||
|
||||
```
|
||||
Init -> Develop -> [if issues] Debug -> Validate -> [if fail] Loop back -> Complete
|
||||
```
|
||||
|
||||
### Mode: Parallel
|
||||
|
||||
并行 spawn 多个 worker 分析不同维度,batch wait 汇聚结果。
|
||||
|
||||
```
|
||||
Coordinator -> spawn [develop, debug, validate] in parallel -> wait({ ids: all }) -> Merge -> Decide
|
||||
```
|
||||
|
||||
## Session Structure
|
||||
|
||||
```
|
||||
.workflow/.loop/
|
||||
+-- {loopId}.json # Master state
|
||||
+-- {loopId}.workers/ # Worker outputs
|
||||
| +-- develop.output.json
|
||||
| +-- debug.output.json
|
||||
| +-- validate.output.json
|
||||
+-- {loopId}.progress/ # Human-readable progress
|
||||
+-- develop.md
|
||||
+-- debug.md
|
||||
+-- validate.md
|
||||
+-- summary.md
|
||||
```
|
||||
|
||||
## Subagent API
|
||||
|
||||
| API | 作用 |
|
||||
|-----|------|
|
||||
| `spawn_agent({ message })` | 创建 agent,返回 `agent_id` |
|
||||
| `wait({ ids, timeout_ms })` | 等待结果(唯一取结果入口) |
|
||||
| `send_input({ id, message })` | 继续交互 |
|
||||
| `close_agent({ id })` | 关闭回收 |
|
||||
|
||||
## Implementation
|
||||
|
||||
### Coordinator Logic
|
||||
|
||||
```javascript
|
||||
// ==================== HYBRID ORCHESTRATOR ====================
|
||||
|
||||
// 1. Initialize
|
||||
const loopId = args['--loop-id'] || generateLoopId()
|
||||
const mode = args['--mode'] || 'interactive'
|
||||
let state = readOrCreateState(loopId, taskDescription)
|
||||
|
||||
// 2. Mode selection
|
||||
switch (mode) {
|
||||
case 'interactive':
|
||||
await runInteractiveMode(loopId, state)
|
||||
break
|
||||
|
||||
case 'auto':
|
||||
await runAutoMode(loopId, state)
|
||||
break
|
||||
|
||||
case 'parallel':
|
||||
await runParallelMode(loopId, state)
|
||||
break
|
||||
}
|
||||
```
|
||||
|
||||
### Interactive Mode (单 agent 交互或按需 spawn worker)
|
||||
|
||||
```javascript
|
||||
async function runInteractiveMode(loopId, state) {
|
||||
while (state.status === 'running') {
|
||||
// Show menu, get user choice
|
||||
const action = await showMenuAndGetChoice(state)
|
||||
|
||||
if (action === 'exit') break
|
||||
|
||||
// Spawn specialized worker for the action
|
||||
const workerId = spawn_agent({
|
||||
message: buildWorkerPrompt(action, loopId, state)
|
||||
})
|
||||
|
||||
// Wait for worker completion
|
||||
const result = wait({ ids: [workerId], timeout_ms: 600000 })
|
||||
const output = result.status[workerId].completed
|
||||
|
||||
// Update state and display result
|
||||
state = updateState(loopId, action, output)
|
||||
displayResult(output)
|
||||
|
||||
// Cleanup worker
|
||||
close_agent({ id: workerId })
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Auto Mode (顺序执行 worker 链)
|
||||
|
||||
```javascript
|
||||
async function runAutoMode(loopId, state) {
|
||||
const actionSequence = ['init', 'develop', 'debug', 'validate', 'complete']
|
||||
let currentIndex = state.skill_state?.action_index || 0
|
||||
|
||||
while (currentIndex < actionSequence.length && state.status === 'running') {
|
||||
const action = actionSequence[currentIndex]
|
||||
|
||||
// Spawn worker
|
||||
const workerId = spawn_agent({
|
||||
message: buildWorkerPrompt(action, loopId, state)
|
||||
})
|
||||
|
||||
const result = wait({ ids: [workerId], timeout_ms: 600000 })
|
||||
const output = result.status[workerId].completed
|
||||
|
||||
// Parse worker result to determine next step
|
||||
const workerResult = parseWorkerResult(output)
|
||||
|
||||
// Update state
|
||||
state = updateState(loopId, action, output)
|
||||
|
||||
close_agent({ id: workerId })
|
||||
|
||||
// Determine next action
|
||||
if (workerResult.needs_loop_back) {
|
||||
// Loop back to develop or debug
|
||||
currentIndex = actionSequence.indexOf(workerResult.loop_back_to)
|
||||
} else if (workerResult.status === 'failed') {
|
||||
// Stop on failure
|
||||
break
|
||||
} else {
|
||||
currentIndex++
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Parallel Mode (批量 spawn + wait)
|
||||
|
||||
```javascript
|
||||
async function runParallelMode(loopId, state) {
|
||||
// Spawn multiple workers in parallel
|
||||
const workers = {
|
||||
develop: spawn_agent({ message: buildWorkerPrompt('develop', loopId, state) }),
|
||||
debug: spawn_agent({ message: buildWorkerPrompt('debug', loopId, state) }),
|
||||
validate: spawn_agent({ message: buildWorkerPrompt('validate', loopId, state) })
|
||||
}
|
||||
|
||||
// Batch wait for all workers
|
||||
const results = wait({
|
||||
ids: Object.values(workers),
|
||||
timeout_ms: 900000 // 15 minutes for all
|
||||
})
|
||||
|
||||
// Collect outputs
|
||||
const outputs = {}
|
||||
for (const [role, workerId] of Object.entries(workers)) {
|
||||
outputs[role] = results.status[workerId].completed
|
||||
close_agent({ id: workerId })
|
||||
}
|
||||
|
||||
// Merge and analyze results
|
||||
const mergedAnalysis = mergeWorkerOutputs(outputs)
|
||||
|
||||
// Update state with merged results
|
||||
updateState(loopId, 'parallel-analysis', mergedAnalysis)
|
||||
|
||||
// Coordinator decides next action based on merged results
|
||||
const decision = decideNextAction(mergedAnalysis)
|
||||
return decision
|
||||
}
|
||||
```
|
||||
|
||||
### Worker Prompt Builder
|
||||
|
||||
```javascript
|
||||
function buildWorkerPrompt(action, loopId, state) {
|
||||
const workerRoles = {
|
||||
develop: '~/.codex/agents/ccw-loop-b-develop.md',
|
||||
debug: '~/.codex/agents/ccw-loop-b-debug.md',
|
||||
validate: '~/.codex/agents/ccw-loop-b-validate.md',
|
||||
init: '~/.codex/agents/ccw-loop-b-init.md',
|
||||
complete: '~/.codex/agents/ccw-loop-b-complete.md'
|
||||
}
|
||||
|
||||
return `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ${workerRoles[action]} (MUST read first)
|
||||
2. Read: .workflow/project-tech.json
|
||||
3. Read: .workflow/project-guidelines.json
|
||||
|
||||
---
|
||||
|
||||
## LOOP CONTEXT
|
||||
|
||||
- **Loop ID**: ${loopId}
|
||||
- **Action**: ${action}
|
||||
- **State File**: .workflow/.loop/${loopId}.json
|
||||
- **Output File**: .workflow/.loop/${loopId}.workers/${action}.output.json
|
||||
- **Progress File**: .workflow/.loop/${loopId}.progress/${action}.md
|
||||
|
||||
## CURRENT STATE
|
||||
|
||||
${JSON.stringify(state, null, 2)}
|
||||
|
||||
## TASK DESCRIPTION
|
||||
|
||||
${state.description}
|
||||
|
||||
## EXPECTED OUTPUT
|
||||
|
||||
\`\`\`
|
||||
WORKER_RESULT:
|
||||
- action: ${action}
|
||||
- status: success | failed | needs_input
|
||||
- summary: <brief summary>
|
||||
- files_changed: [list]
|
||||
- next_suggestion: <suggested next action>
|
||||
- loop_back_to: <action name if needs loop back>
|
||||
|
||||
DETAILED_OUTPUT:
|
||||
<structured output specific to action type>
|
||||
\`\`\`
|
||||
|
||||
Execute the ${action} action now.
|
||||
`
|
||||
}
|
||||
```
|
||||
|
||||
## Worker Roles
|
||||
|
||||
| Worker | Role File | 专注领域 |
|
||||
|--------|-----------|----------|
|
||||
| init | ccw-loop-b-init.md | 会话初始化、任务解析 |
|
||||
| develop | ccw-loop-b-develop.md | 代码实现、重构 |
|
||||
| debug | ccw-loop-b-debug.md | 问题诊断、假设验证 |
|
||||
| validate | ccw-loop-b-validate.md | 测试执行、覆盖率 |
|
||||
| complete | ccw-loop-b-complete.md | 总结收尾 |
|
||||
|
||||
## State Schema
|
||||
|
||||
See [phases/state-schema.md](phases/state-schema.md)
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Interactive mode (default)
|
||||
/ccw-loop-b TASK="Implement user authentication"
|
||||
|
||||
# Auto mode
|
||||
/ccw-loop-b --mode=auto TASK="Fix login bug"
|
||||
|
||||
# Parallel analysis mode
|
||||
/ccw-loop-b --mode=parallel TASK="Analyze and improve payment module"
|
||||
|
||||
# Resume existing loop
|
||||
/ccw-loop-b --loop-id=loop-b-20260122-abc123
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| Worker timeout | send_input 请求收敛 |
|
||||
| Worker failed | Log error, 协调器决策是否重试 |
|
||||
| Batch wait partial timeout | 使用已完成结果继续 |
|
||||
| State corrupted | 从 progress 文件重建 |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **协调器保持轻量**: 只做调度和状态管理,具体工作交给 worker
|
||||
2. **Worker 职责单一**: 每个 worker 专注一个领域
|
||||
3. **结果标准化**: Worker 输出遵循统一 WORKER_RESULT 格式
|
||||
4. **灵活模式切换**: 根据任务复杂度选择合适模式
|
||||
5. **及时清理**: Worker 完成后 close_agent 释放资源
|
||||
257
.codex/skills/ccw-loop-b/phases/orchestrator.md
Normal file
257
.codex/skills/ccw-loop-b/phases/orchestrator.md
Normal file
@@ -0,0 +1,257 @@
|
||||
# Orchestrator (Hybrid Pattern)
|
||||
|
||||
协调器负责状态管理、worker 调度、结果汇聚。
|
||||
|
||||
## Role
|
||||
|
||||
```
|
||||
Read state -> Select mode -> Spawn workers -> Wait results -> Merge -> Update state -> Loop/Exit
|
||||
```
|
||||
|
||||
## State Management
|
||||
|
||||
### Read State
|
||||
|
||||
```javascript
|
||||
function readState(loopId) {
|
||||
const stateFile = `.workflow/.loop/${loopId}.json`
|
||||
return fs.existsSync(stateFile)
|
||||
? JSON.parse(Read(stateFile))
|
||||
: null
|
||||
}
|
||||
```
|
||||
|
||||
### Create State
|
||||
|
||||
```javascript
|
||||
function createState(loopId, taskDescription, mode) {
|
||||
const now = new Date().toISOString()
|
||||
|
||||
return {
|
||||
loop_id: loopId,
|
||||
title: taskDescription.substring(0, 100),
|
||||
description: taskDescription,
|
||||
mode: mode,
|
||||
status: 'running',
|
||||
current_iteration: 0,
|
||||
max_iterations: 10,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
skill_state: {
|
||||
phase: 'init',
|
||||
action_index: 0,
|
||||
workers_completed: [],
|
||||
parallel_results: null
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Mode Handlers
|
||||
|
||||
### Interactive Mode
|
||||
|
||||
```javascript
|
||||
async function runInteractiveMode(loopId, state) {
|
||||
while (state.status === 'running') {
|
||||
// 1. Show menu
|
||||
const action = await showMenu(state)
|
||||
if (action === 'exit') break
|
||||
|
||||
// 2. Spawn worker
|
||||
const worker = spawn_agent({
|
||||
message: buildWorkerPrompt(action, loopId, state)
|
||||
})
|
||||
|
||||
// 3. Wait for result
|
||||
const result = wait({ ids: [worker], timeout_ms: 600000 })
|
||||
|
||||
// 4. Handle timeout
|
||||
if (result.timed_out) {
|
||||
send_input({ id: worker, message: 'Please converge and output WORKER_RESULT' })
|
||||
const retryResult = wait({ ids: [worker], timeout_ms: 300000 })
|
||||
if (retryResult.timed_out) {
|
||||
console.log('Worker timeout, skipping')
|
||||
close_agent({ id: worker })
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Process output
|
||||
const output = result.status[worker].completed
|
||||
state = processWorkerOutput(loopId, action, output, state)
|
||||
|
||||
// 6. Cleanup
|
||||
close_agent({ id: worker })
|
||||
|
||||
// 7. Display result
|
||||
displayResult(output)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Auto Mode
|
||||
|
||||
```javascript
|
||||
async function runAutoMode(loopId, state) {
|
||||
const sequence = ['init', 'develop', 'debug', 'validate', 'complete']
|
||||
let idx = state.skill_state?.action_index || 0
|
||||
|
||||
while (idx < sequence.length && state.status === 'running') {
|
||||
const action = sequence[idx]
|
||||
|
||||
// Spawn and wait
|
||||
const worker = spawn_agent({ message: buildWorkerPrompt(action, loopId, state) })
|
||||
const result = wait({ ids: [worker], timeout_ms: 600000 })
|
||||
const output = result.status[worker].completed
|
||||
close_agent({ id: worker })
|
||||
|
||||
// Parse result
|
||||
const workerResult = parseWorkerResult(output)
|
||||
state = processWorkerOutput(loopId, action, output, state)
|
||||
|
||||
// Determine next
|
||||
if (workerResult.loop_back_to) {
|
||||
idx = sequence.indexOf(workerResult.loop_back_to)
|
||||
} else if (workerResult.status === 'failed') {
|
||||
break
|
||||
} else {
|
||||
idx++
|
||||
}
|
||||
|
||||
// Update action index
|
||||
state.skill_state.action_index = idx
|
||||
saveState(loopId, state)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Parallel Mode
|
||||
|
||||
```javascript
|
||||
async function runParallelMode(loopId, state) {
|
||||
// Spawn all workers
|
||||
const workers = {
|
||||
develop: spawn_agent({ message: buildWorkerPrompt('develop', loopId, state) }),
|
||||
debug: spawn_agent({ message: buildWorkerPrompt('debug', loopId, state) }),
|
||||
validate: spawn_agent({ message: buildWorkerPrompt('validate', loopId, state) })
|
||||
}
|
||||
|
||||
// Batch wait
|
||||
const results = wait({
|
||||
ids: Object.values(workers),
|
||||
timeout_ms: 900000
|
||||
})
|
||||
|
||||
// Collect outputs
|
||||
const outputs = {}
|
||||
for (const [role, id] of Object.entries(workers)) {
|
||||
if (results.status[id].completed) {
|
||||
outputs[role] = results.status[id].completed
|
||||
}
|
||||
close_agent({ id })
|
||||
}
|
||||
|
||||
// Merge analysis
|
||||
state.skill_state.parallel_results = outputs
|
||||
saveState(loopId, state)
|
||||
|
||||
// Coordinator analyzes merged results
|
||||
return analyzeAndDecide(outputs)
|
||||
}
|
||||
```
|
||||
|
||||
## Worker Prompt Template
|
||||
|
||||
```javascript
|
||||
function buildWorkerPrompt(action, loopId, state) {
|
||||
const roleFiles = {
|
||||
init: '~/.codex/agents/ccw-loop-b-init.md',
|
||||
develop: '~/.codex/agents/ccw-loop-b-develop.md',
|
||||
debug: '~/.codex/agents/ccw-loop-b-debug.md',
|
||||
validate: '~/.codex/agents/ccw-loop-b-validate.md',
|
||||
complete: '~/.codex/agents/ccw-loop-b-complete.md'
|
||||
}
|
||||
|
||||
return `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS
|
||||
1. **Read role definition**: ${roleFiles[action]}
|
||||
2. Read: .workflow/project-tech.json
|
||||
3. Read: .workflow/project-guidelines.json
|
||||
|
||||
---
|
||||
|
||||
## CONTEXT
|
||||
- Loop ID: ${loopId}
|
||||
- Action: ${action}
|
||||
- State: ${JSON.stringify(state, null, 2)}
|
||||
|
||||
## TASK
|
||||
${state.description}
|
||||
|
||||
## OUTPUT FORMAT
|
||||
\`\`\`
|
||||
WORKER_RESULT:
|
||||
- action: ${action}
|
||||
- status: success | failed | needs_input
|
||||
- summary: <brief>
|
||||
- files_changed: []
|
||||
- next_suggestion: <action>
|
||||
- loop_back_to: <action or null>
|
||||
|
||||
DETAILED_OUTPUT:
|
||||
<action-specific output>
|
||||
\`\`\`
|
||||
`
|
||||
}
|
||||
```
|
||||
|
||||
## Result Processing
|
||||
|
||||
```javascript
|
||||
function parseWorkerResult(output) {
|
||||
const result = {
|
||||
action: 'unknown',
|
||||
status: 'unknown',
|
||||
summary: '',
|
||||
files_changed: [],
|
||||
next_suggestion: null,
|
||||
loop_back_to: null
|
||||
}
|
||||
|
||||
const match = output.match(/WORKER_RESULT:\s*([\s\S]*?)(?:DETAILED_OUTPUT:|$)/)
|
||||
if (match) {
|
||||
const lines = match[1].split('\n')
|
||||
for (const line of lines) {
|
||||
const m = line.match(/^-\s*(\w+):\s*(.+)$/)
|
||||
if (m) {
|
||||
const [, key, value] = m
|
||||
if (key === 'files_changed') {
|
||||
try { result.files_changed = JSON.parse(value) } catch {}
|
||||
} else {
|
||||
result[key] = value.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
## Termination Conditions
|
||||
|
||||
1. User exits (interactive)
|
||||
2. Sequence complete (auto)
|
||||
3. Worker failed with no recovery
|
||||
4. Max iterations reached
|
||||
5. API paused/stopped
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Worker 生命周期**: spawn → wait → close,不保留 worker
|
||||
2. **结果持久化**: Worker 输出写入 `.workflow/.loop/{loopId}.workers/`
|
||||
3. **状态同步**: 每次 worker 完成后更新 state
|
||||
4. **超时处理**: send_input 请求收敛,再超时则跳过
|
||||
181
.codex/skills/ccw-loop-b/phases/state-schema.md
Normal file
181
.codex/skills/ccw-loop-b/phases/state-schema.md
Normal file
@@ -0,0 +1,181 @@
|
||||
# State Schema (CCW Loop-B)
|
||||
|
||||
## Master State Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"loop_id": "loop-b-20260122-abc123",
|
||||
"title": "Implement user authentication",
|
||||
"description": "Full task description here",
|
||||
"mode": "interactive | auto | parallel",
|
||||
"status": "running | paused | completed | failed",
|
||||
"current_iteration": 3,
|
||||
"max_iterations": 10,
|
||||
"created_at": "2026-01-22T10:00:00.000Z",
|
||||
"updated_at": "2026-01-22T10:30:00.000Z",
|
||||
|
||||
"skill_state": {
|
||||
"phase": "develop | debug | validate | complete",
|
||||
"action_index": 2,
|
||||
"workers_completed": ["init", "develop"],
|
||||
"parallel_results": null,
|
||||
"pending_tasks": [],
|
||||
"completed_tasks": [],
|
||||
"findings": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Field Descriptions
|
||||
|
||||
### Core Fields (API Compatible)
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `loop_id` | string | Unique identifier |
|
||||
| `title` | string | Short title (max 100 chars) |
|
||||
| `description` | string | Full task description |
|
||||
| `mode` | enum | Execution mode |
|
||||
| `status` | enum | Current status |
|
||||
| `current_iteration` | number | Iteration counter |
|
||||
| `max_iterations` | number | Safety limit |
|
||||
| `created_at` | ISO string | Creation timestamp |
|
||||
| `updated_at` | ISO string | Last update timestamp |
|
||||
|
||||
### Skill State Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `phase` | enum | Current execution phase |
|
||||
| `action_index` | number | Position in action sequence (auto mode) |
|
||||
| `workers_completed` | array | List of completed worker actions |
|
||||
| `parallel_results` | object | Merged results from parallel mode |
|
||||
| `pending_tasks` | array | Tasks waiting to be executed |
|
||||
| `completed_tasks` | array | Tasks already done |
|
||||
| `findings` | array | Discoveries during execution |
|
||||
|
||||
## Worker Output Structure
|
||||
|
||||
Each worker writes to `.workflow/.loop/{loopId}.workers/{action}.output.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "develop",
|
||||
"status": "success",
|
||||
"summary": "Implemented 3 functions",
|
||||
"files_changed": ["src/auth.ts", "src/utils.ts"],
|
||||
"next_suggestion": "validate",
|
||||
"loop_back_to": null,
|
||||
"timestamp": "2026-01-22T10:15:00.000Z",
|
||||
"detailed_output": {
|
||||
"tasks_completed": [
|
||||
{ "id": "T1", "description": "Create auth module" }
|
||||
],
|
||||
"metrics": {
|
||||
"lines_added": 150,
|
||||
"lines_removed": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Progress File Structure
|
||||
|
||||
Human-readable progress in `.workflow/.loop/{loopId}.progress/{action}.md`:
|
||||
|
||||
```markdown
|
||||
# Develop Progress
|
||||
|
||||
## Session: loop-b-20260122-abc123
|
||||
|
||||
### Iteration 1 (2026-01-22 10:15)
|
||||
|
||||
**Task**: Implement auth module
|
||||
|
||||
**Changes**:
|
||||
- Created `src/auth.ts` with login/logout functions
|
||||
- Added JWT token handling in `src/utils.ts`
|
||||
|
||||
**Status**: Success
|
||||
|
||||
---
|
||||
|
||||
### Iteration 2 (2026-01-22 10:30)
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
## Status Transitions
|
||||
|
||||
```
|
||||
+--------+
|
||||
| init |
|
||||
+--------+
|
||||
|
|
||||
v
|
||||
+------> +---------+
|
||||
| | develop |
|
||||
| +---------+
|
||||
| |
|
||||
| +--------+--------+
|
||||
| | |
|
||||
| v v
|
||||
| +-------+ +---------+
|
||||
| | debug |<------| validate|
|
||||
| +-------+ +---------+
|
||||
| | |
|
||||
| +--------+--------+
|
||||
| |
|
||||
| v
|
||||
| [needs fix?]
|
||||
| yes | | no
|
||||
| v v
|
||||
+------------+ +----------+
|
||||
| complete |
|
||||
+----------+
|
||||
```
|
||||
|
||||
## Parallel Results Schema
|
||||
|
||||
When `mode === 'parallel'`:
|
||||
|
||||
```json
|
||||
{
|
||||
"parallel_results": {
|
||||
"develop": {
|
||||
"status": "success",
|
||||
"summary": "...",
|
||||
"suggestions": []
|
||||
},
|
||||
"debug": {
|
||||
"status": "success",
|
||||
"issues_found": [],
|
||||
"suggestions": []
|
||||
},
|
||||
"validate": {
|
||||
"status": "success",
|
||||
"test_results": {},
|
||||
"coverage": {}
|
||||
},
|
||||
"merged_at": "2026-01-22T10:45:00.000Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
.workflow/.loop/
|
||||
+-- loop-b-20260122-abc123.json # Master state
|
||||
+-- loop-b-20260122-abc123.workers/
|
||||
| +-- init.output.json
|
||||
| +-- develop.output.json
|
||||
| +-- debug.output.json
|
||||
| +-- validate.output.json
|
||||
| +-- complete.output.json
|
||||
+-- loop-b-20260122-abc123.progress/
|
||||
+-- develop.md
|
||||
+-- debug.md
|
||||
+-- validate.md
|
||||
+-- summary.md
|
||||
```
|
||||
383
.codex/skills/ccw-loop-b/specs/action-catalog.md
Normal file
383
.codex/skills/ccw-loop-b/specs/action-catalog.md
Normal file
@@ -0,0 +1,383 @@
|
||||
# Action Catalog (CCW Loop-B)
|
||||
|
||||
Complete reference of worker actions and their capabilities.
|
||||
|
||||
## Action Matrix
|
||||
|
||||
| Action | Worker Agent | Purpose | Input Requirements | Output |
|
||||
|--------|--------------|---------|-------------------|--------|
|
||||
| init | ccw-loop-b-init.md | Session initialization | Task description | Task breakdown + execution plan |
|
||||
| develop | ccw-loop-b-develop.md | Code implementation | Task list | Code changes + progress update |
|
||||
| debug | ccw-loop-b-debug.md | Problem diagnosis | Issue description | Root cause analysis + fix suggestions |
|
||||
| validate | ccw-loop-b-validate.md | Testing and verification | Files to test | Test results + coverage report |
|
||||
| complete | ccw-loop-b-complete.md | Session finalization | All worker outputs | Summary + commit message |
|
||||
|
||||
## Detailed Action Specifications
|
||||
|
||||
### INIT
|
||||
|
||||
**Purpose**: Parse requirements, create execution plan
|
||||
|
||||
**Preconditions**:
|
||||
- `status === 'running'`
|
||||
- `skill_state === null` (first time)
|
||||
|
||||
**Input**:
|
||||
```
|
||||
- Task description (text)
|
||||
- Project context files
|
||||
```
|
||||
|
||||
**Execution**:
|
||||
1. Read `.workflow/project-tech.json`
|
||||
2. Read `.workflow/project-guidelines.json`
|
||||
3. Parse task into phases
|
||||
4. Create task breakdown
|
||||
5. Generate execution plan
|
||||
|
||||
**Output**:
|
||||
```
|
||||
WORKER_RESULT:
|
||||
- action: init
|
||||
- status: success
|
||||
- summary: "Initialized with 5 tasks"
|
||||
- next_suggestion: develop
|
||||
|
||||
TASK_BREAKDOWN:
|
||||
- T1: Create auth module
|
||||
- T2: Implement JWT utils
|
||||
- T3: Write tests
|
||||
- T4: Validate implementation
|
||||
- T5: Documentation
|
||||
|
||||
EXECUTION_PLAN:
|
||||
1. Develop (T1-T2)
|
||||
2. Validate (T3-T4)
|
||||
3. Complete (T5)
|
||||
```
|
||||
|
||||
**Effects**:
|
||||
- `skill_state.pending_tasks` populated
|
||||
- Progress structure created
|
||||
- Ready for develop phase
|
||||
|
||||
---
|
||||
|
||||
### DEVELOP
|
||||
|
||||
**Purpose**: Implement code, create/modify files
|
||||
|
||||
**Preconditions**:
|
||||
- `skill_state.pending_tasks.length > 0`
|
||||
- `status === 'running'`
|
||||
|
||||
**Input**:
|
||||
```
|
||||
- Task list from state
|
||||
- Project conventions
|
||||
- Existing code patterns
|
||||
```
|
||||
|
||||
**Execution**:
|
||||
1. Load pending tasks
|
||||
2. Find existing patterns
|
||||
3. Implement tasks one by one
|
||||
4. Update progress file
|
||||
5. Mark tasks completed
|
||||
|
||||
**Output**:
|
||||
```
|
||||
WORKER_RESULT:
|
||||
- action: develop
|
||||
- status: success
|
||||
- summary: "Implemented 3 tasks"
|
||||
- files_changed: ["src/auth.ts", "src/utils.ts"]
|
||||
- next_suggestion: validate
|
||||
|
||||
DETAILED_OUTPUT:
|
||||
tasks_completed: [T1, T2]
|
||||
metrics:
|
||||
lines_added: 180
|
||||
lines_removed: 15
|
||||
```
|
||||
|
||||
**Effects**:
|
||||
- Files created/modified
|
||||
- `skill_state.completed_tasks` updated
|
||||
- Progress documented
|
||||
|
||||
**Failure Modes**:
|
||||
- Pattern unclear → suggest debug
|
||||
- Task blocked → mark blocked, continue
|
||||
- Partial completion → set `loop_back_to: "develop"`
|
||||
|
||||
---
|
||||
|
||||
### DEBUG
|
||||
|
||||
**Purpose**: Diagnose issues, root cause analysis
|
||||
|
||||
**Preconditions**:
|
||||
- Issue exists (test failure, bug report, etc.)
|
||||
- `status === 'running'`
|
||||
|
||||
**Input**:
|
||||
```
|
||||
- Issue description
|
||||
- Error messages
|
||||
- Stack traces
|
||||
- Reproduction steps
|
||||
```
|
||||
|
||||
**Execution**:
|
||||
1. Understand problem symptoms
|
||||
2. Gather evidence from code
|
||||
3. Form hypothesis
|
||||
4. Test hypothesis
|
||||
5. Document root cause
|
||||
6. Suggest fixes
|
||||
|
||||
**Output**:
|
||||
```
|
||||
WORKER_RESULT:
|
||||
- action: debug
|
||||
- status: success
|
||||
- summary: "Root cause: memory leak in event listeners"
|
||||
- next_suggestion: develop (apply fixes)
|
||||
|
||||
ROOT_CAUSE_ANALYSIS:
|
||||
hypothesis: "Listener accumulation"
|
||||
confidence: high
|
||||
evidence: [...]
|
||||
mechanism: "Detailed explanation"
|
||||
|
||||
FIX_RECOMMENDATIONS:
|
||||
1. Add removeAllListeners() on disconnect
|
||||
2. Verification: Monitor memory usage
|
||||
```
|
||||
|
||||
**Effects**:
|
||||
- `skill_state.findings` updated
|
||||
- Fix recommendations documented
|
||||
- Ready for develop to apply fixes
|
||||
|
||||
**Failure Modes**:
|
||||
- Insufficient info → request more data
|
||||
- Multiple hypotheses → rank by likelihood
|
||||
- Inconclusive → suggest investigation areas
|
||||
|
||||
---
|
||||
|
||||
### VALIDATE
|
||||
|
||||
**Purpose**: Run tests, check coverage, quality gates
|
||||
|
||||
**Preconditions**:
|
||||
- Code exists to validate
|
||||
- `status === 'running'`
|
||||
|
||||
**Input**:
|
||||
```
|
||||
- Files to test
|
||||
- Test configuration
|
||||
- Coverage requirements
|
||||
```
|
||||
|
||||
**Execution**:
|
||||
1. Identify test framework
|
||||
2. Run unit tests
|
||||
3. Run integration tests
|
||||
4. Measure coverage
|
||||
5. Check quality (lint, types, security)
|
||||
6. Generate report
|
||||
|
||||
**Output**:
|
||||
```
|
||||
WORKER_RESULT:
|
||||
- action: validate
|
||||
- status: success
|
||||
- summary: "113 tests pass, coverage 95%"
|
||||
- next_suggestion: complete (all pass) | develop (fix failures)
|
||||
|
||||
TEST_RESULTS:
|
||||
unit_tests: { passed: 98, failed: 0 }
|
||||
integration_tests: { passed: 15, failed: 0 }
|
||||
coverage: "95%"
|
||||
|
||||
QUALITY_CHECKS:
|
||||
lint: ✓ Pass
|
||||
types: ✓ Pass
|
||||
security: ✓ Pass
|
||||
```
|
||||
|
||||
**Effects**:
|
||||
- Test results documented
|
||||
- Coverage measured
|
||||
- Quality gates verified
|
||||
|
||||
**Failure Modes**:
|
||||
- Tests fail → document failures, suggest fixes
|
||||
- Coverage low → identify gaps
|
||||
- Quality issues → flag problems
|
||||
|
||||
---
|
||||
|
||||
### COMPLETE
|
||||
|
||||
**Purpose**: Finalize session, generate summary, commit
|
||||
|
||||
**Preconditions**:
|
||||
- All tasks completed
|
||||
- Tests passing
|
||||
- `status === 'running'`
|
||||
|
||||
**Input**:
|
||||
```
|
||||
- All worker outputs
|
||||
- Progress files
|
||||
- Current state
|
||||
```
|
||||
|
||||
**Execution**:
|
||||
1. Read all worker outputs
|
||||
2. Consolidate achievements
|
||||
3. Verify completeness
|
||||
4. Generate summary
|
||||
5. Prepare commit message
|
||||
6. Cleanup and archive
|
||||
|
||||
**Output**:
|
||||
```
|
||||
WORKER_RESULT:
|
||||
- action: complete
|
||||
- status: success
|
||||
- summary: "Session completed successfully"
|
||||
- next_suggestion: null
|
||||
|
||||
SESSION_SUMMARY:
|
||||
achievements: [...]
|
||||
files_changed: [...]
|
||||
test_results: { ... }
|
||||
quality_checks: { ... }
|
||||
|
||||
COMMIT_SUGGESTION:
|
||||
message: "feat: ..."
|
||||
files: [...]
|
||||
ready_for_pr: true
|
||||
```
|
||||
|
||||
**Effects**:
|
||||
- `status` → 'completed'
|
||||
- Summary file created
|
||||
- Progress archived
|
||||
- Commit message ready
|
||||
|
||||
**Failure Modes**:
|
||||
- Pending tasks remain → mark partial
|
||||
- Quality gates fail → list failures
|
||||
|
||||
---
|
||||
|
||||
## Action Flow Diagrams
|
||||
|
||||
### Interactive Mode Flow
|
||||
|
||||
```
|
||||
+------+
|
||||
| INIT |
|
||||
+------+
|
||||
|
|
||||
v
|
||||
+------+ user selects
|
||||
| MENU |-------------+
|
||||
+------+ |
|
||||
^ v
|
||||
| +--------------+
|
||||
| | spawn worker |
|
||||
| +--------------+
|
||||
| |
|
||||
| v
|
||||
| +------+-------+
|
||||
+---------| wait result |
|
||||
+------+-------+
|
||||
|
|
||||
v
|
||||
+------+-------+
|
||||
| update state |
|
||||
+--------------+
|
||||
|
|
||||
v
|
||||
[completed?] --no--> [back to MENU]
|
||||
|
|
||||
yes
|
||||
v
|
||||
+----------+
|
||||
| COMPLETE |
|
||||
+----------+
|
||||
```
|
||||
|
||||
### Auto Mode Flow
|
||||
|
||||
```
|
||||
+------+ +---------+ +-------+ +----------+ +----------+
|
||||
| INIT | ---> | DEVELOP | ---> | DEBUG | ---> | VALIDATE | ---> | COMPLETE |
|
||||
+------+ +---------+ +-------+ +----------+ +----------+
|
||||
^ | |
|
||||
| +--- [issues] |
|
||||
+--------------------------------+
|
||||
[tests fail]
|
||||
```
|
||||
|
||||
### Parallel Mode Flow
|
||||
|
||||
```
|
||||
+------+
|
||||
| INIT |
|
||||
+------+
|
||||
|
|
||||
v
|
||||
+---------------------+
|
||||
| spawn all workers |
|
||||
| [develop, debug, |
|
||||
| validate] |
|
||||
+---------------------+
|
||||
|
|
||||
v
|
||||
+---------------------+
|
||||
| wait({ ids: all }) |
|
||||
+---------------------+
|
||||
|
|
||||
v
|
||||
+---------------------+
|
||||
| merge results |
|
||||
+---------------------+
|
||||
|
|
||||
v
|
||||
+---------------------+
|
||||
| coordinator decides |
|
||||
+---------------------+
|
||||
|
|
||||
v
|
||||
+----------+
|
||||
| COMPLETE |
|
||||
+----------+
|
||||
```
|
||||
|
||||
## Worker Coordination
|
||||
|
||||
| Scenario | Worker Sequence | Mode |
|
||||
|----------|-----------------|------|
|
||||
| Simple task | init → develop → validate → complete | Auto |
|
||||
| Complex task | init → develop → debug → develop → validate → complete | Auto |
|
||||
| Bug fix | init → debug → develop → validate → complete | Auto |
|
||||
| Analysis | init → [develop \|\| debug \|\| validate] → complete | Parallel |
|
||||
| Interactive | init → menu → user selects → worker → menu → ... | Interactive |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Init always first**: Parse requirements before execution
|
||||
2. **Validate often**: After each develop phase
|
||||
3. **Debug when needed**: Don't skip diagnosis
|
||||
4. **Complete always last**: Ensure proper cleanup
|
||||
5. **Use parallel wisely**: For independent analysis tasks
|
||||
6. **Follow sequence**: In auto mode, respect dependencies
|
||||
171
.codex/skills/ccw-loop/README.md
Normal file
171
.codex/skills/ccw-loop/README.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# CCW Loop Skill (Codex Version)
|
||||
|
||||
Stateless iterative development loop workflow using Codex subagent pattern.
|
||||
|
||||
## Overview
|
||||
|
||||
CCW Loop is an autonomous development workflow that supports:
|
||||
- **Develop**: Task decomposition -> Code implementation -> Progress tracking
|
||||
- **Debug**: Hypothesis generation -> Evidence collection -> Root cause analysis
|
||||
- **Validate**: Test execution -> Coverage check -> Quality assessment
|
||||
|
||||
## Subagent 机制
|
||||
|
||||
核心 API: `spawn_agent` / `wait` / `send_input` / `close_agent`
|
||||
|
||||
可用模式: 单 agent 深度交互 / 多 agent 并行 / 混合模式
|
||||
|
||||
## Installation
|
||||
|
||||
Files are in `.codex/skills/ccw-loop/`:
|
||||
|
||||
```
|
||||
.codex/skills/ccw-loop/
|
||||
+-- SKILL.md # Main skill definition
|
||||
+-- README.md # This file
|
||||
+-- phases/
|
||||
| +-- orchestrator.md # Orchestration logic
|
||||
| +-- state-schema.md # State structure
|
||||
| +-- actions/
|
||||
| +-- action-init.md # Initialize session
|
||||
| +-- action-develop.md # Development task
|
||||
| +-- action-debug.md # Hypothesis debugging
|
||||
| +-- action-validate.md # Test validation
|
||||
| +-- action-complete.md # Complete loop
|
||||
| +-- action-menu.md # Interactive menu
|
||||
+-- specs/
|
||||
| +-- action-catalog.md # Action catalog
|
||||
+-- templates/
|
||||
+-- (templates)
|
||||
|
||||
.codex/agents/
|
||||
+-- ccw-loop-executor.md # Executor agent role
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Start New Loop
|
||||
|
||||
```bash
|
||||
# Direct call with task description
|
||||
/ccw-loop TASK="Implement user authentication"
|
||||
|
||||
# Auto-cycle mode
|
||||
/ccw-loop --auto TASK="Fix login bug and add tests"
|
||||
```
|
||||
|
||||
### Continue Existing Loop
|
||||
|
||||
```bash
|
||||
# Resume from loop ID
|
||||
/ccw-loop --loop-id=loop-v2-20260122-abc123
|
||||
|
||||
# API triggered (from Dashboard)
|
||||
/ccw-loop --loop-id=loop-v2-20260122-abc123 --auto
|
||||
```
|
||||
|
||||
## Execution Flow
|
||||
|
||||
```
|
||||
1. Parse arguments (task or --loop-id)
|
||||
2. Create/read state from .workflow/.loop/{loopId}.json
|
||||
3. spawn_agent with ccw-loop-executor role
|
||||
4. Main loop:
|
||||
a. wait() for agent output
|
||||
b. Parse ACTION_RESULT
|
||||
c. Handle outcome:
|
||||
- COMPLETED/PAUSED/STOPPED: exit loop
|
||||
- WAITING_INPUT: collect user input, send_input
|
||||
- Next action: send_input to continue
|
||||
d. Update state file
|
||||
5. close_agent when done
|
||||
```
|
||||
|
||||
## Session Files
|
||||
|
||||
```
|
||||
.workflow/.loop/
|
||||
+-- {loopId}.json # Master state (API + Skill)
|
||||
+-- {loopId}.progress/
|
||||
+-- develop.md # Development timeline
|
||||
+-- debug.md # Understanding evolution
|
||||
+-- validate.md # Validation report
|
||||
+-- changes.log # Code changes (NDJSON)
|
||||
+-- debug.log # Debug log (NDJSON)
|
||||
+-- summary.md # Completion summary
|
||||
```
|
||||
|
||||
## Codex Pattern Highlights
|
||||
|
||||
### Single Agent Deep Interaction
|
||||
|
||||
Instead of creating multiple agents, use `send_input` for multi-phase:
|
||||
|
||||
```javascript
|
||||
const agent = spawn_agent({ message: role + task })
|
||||
|
||||
// Phase 1: INIT
|
||||
const initResult = wait({ ids: [agent] })
|
||||
|
||||
// Phase 2: DEVELOP (via send_input, same agent)
|
||||
send_input({ id: agent, message: 'Execute DEVELOP' })
|
||||
const devResult = wait({ ids: [agent] })
|
||||
|
||||
// Phase 3: VALIDATE (via send_input, same agent)
|
||||
send_input({ id: agent, message: 'Execute VALIDATE' })
|
||||
const valResult = wait({ ids: [agent] })
|
||||
|
||||
// Only close when all done
|
||||
close_agent({ id: agent })
|
||||
```
|
||||
|
||||
### Role Path Passing
|
||||
|
||||
Agent reads role file itself (no content embedding):
|
||||
|
||||
```javascript
|
||||
spawn_agent({
|
||||
message: `
|
||||
### MANDATORY FIRST STEPS
|
||||
1. **Read role definition**: ~/.codex/agents/ccw-loop-executor.md
|
||||
2. Read: .workflow/project-tech.json
|
||||
...
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
### Explicit Lifecycle Management
|
||||
|
||||
- Always use `wait({ ids })` to get results
|
||||
- Never assume `close_agent` returns results
|
||||
- Only `close_agent` when confirming no more interaction needed
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| Agent timeout | `send_input` requesting convergence |
|
||||
| Session not found | Create new session |
|
||||
| State corrupted | Rebuild from progress files |
|
||||
| Tests fail | Loop back to DEBUG |
|
||||
| >10 iterations | Warn and suggest break |
|
||||
|
||||
## Integration
|
||||
|
||||
### Dashboard Integration
|
||||
|
||||
Works with CCW Dashboard Loop Monitor:
|
||||
- Dashboard creates loop via API
|
||||
- API triggers this skill with `--loop-id`
|
||||
- Skill reads/writes `.workflow/.loop/{loopId}.json`
|
||||
- Dashboard polls state for real-time updates
|
||||
|
||||
### Control Signals
|
||||
|
||||
- `paused`: Skill exits gracefully, waits for resume
|
||||
- `failed`: Skill terminates
|
||||
- `running`: Skill continues execution
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
350
.codex/skills/ccw-loop/SKILL.md
Normal file
350
.codex/skills/ccw-loop/SKILL.md
Normal file
@@ -0,0 +1,350 @@
|
||||
---
|
||||
name: CCW Loop
|
||||
description: Stateless iterative development loop workflow with documented progress. Supports develop, debug, and validate phases with file-based state tracking. Triggers on "ccw-loop", "dev loop", "development loop", "开发循环", "迭代开发".
|
||||
argument-hint: TASK="<task description>" [--loop-id=<id>] [--auto]
|
||||
---
|
||||
|
||||
# CCW Loop - Codex Stateless Iterative Development Workflow
|
||||
|
||||
Stateless iterative development loop using Codex subagent pattern. Supports develop, debug, and validate phases with file-based state tracking.
|
||||
|
||||
## Arguments
|
||||
|
||||
| Arg | Required | Description |
|
||||
|-----|----------|-------------|
|
||||
| TASK | No | Task description (for new loop, mutually exclusive with --loop-id) |
|
||||
| --loop-id | No | Existing loop ID to continue (from API or previous session) |
|
||||
| --auto | No | Auto-cycle mode (develop -> debug -> validate -> complete) |
|
||||
|
||||
## Unified Architecture (Codex Subagent Pattern)
|
||||
|
||||
```
|
||||
+-------------------------------------------------------------+
|
||||
| Dashboard (UI) |
|
||||
| [Create] [Start] [Pause] [Resume] [Stop] [View Progress] |
|
||||
+-------------------------------------------------------------+
|
||||
|
|
||||
v
|
||||
+-------------------------------------------------------------+
|
||||
| loop-v2-routes.ts (Control Plane) |
|
||||
| |
|
||||
| State: .workflow/.loop/{loopId}.json (MASTER) |
|
||||
| Tasks: .workflow/.loop/{loopId}.tasks.jsonl |
|
||||
| |
|
||||
| /start -> Trigger ccw-loop skill with --loop-id |
|
||||
| /pause -> Set status='paused' (skill checks before action) |
|
||||
| /stop -> Set status='failed' (skill terminates) |
|
||||
| /resume -> Set status='running' (skill continues) |
|
||||
+-------------------------------------------------------------+
|
||||
|
|
||||
v
|
||||
+-------------------------------------------------------------+
|
||||
| ccw-loop Skill (Execution Plane) |
|
||||
| |
|
||||
| Codex Pattern: spawn_agent -> wait -> send_input -> close |
|
||||
| |
|
||||
| Reads/Writes: .workflow/.loop/{loopId}.json (unified state) |
|
||||
| Writes: .workflow/.loop/{loopId}.progress/* (progress files) |
|
||||
| |
|
||||
| BEFORE each action: |
|
||||
| -> Check status: paused/stopped -> exit gracefully |
|
||||
| -> running -> continue with action |
|
||||
| |
|
||||
| Actions: init -> develop -> debug -> validate -> complete |
|
||||
+-------------------------------------------------------------+
|
||||
```
|
||||
|
||||
## Key Design Principles (Codex Adaptation)
|
||||
|
||||
1. **Unified State**: API and Skill share `.workflow/.loop/{loopId}.json` state file
|
||||
2. **Control Signals**: Skill checks status field before each action (paused/stopped)
|
||||
3. **File-Driven**: All progress documented in `.workflow/.loop/{loopId}.progress/`
|
||||
4. **Resumable**: Continue any loop with `--loop-id`
|
||||
5. **Dual Trigger**: Supports API trigger (`--loop-id`) and direct call (task description)
|
||||
6. **Single Agent Deep Interaction**: Use send_input for multi-phase execution instead of multiple agents
|
||||
|
||||
## Subagent 机制
|
||||
|
||||
### 核心 API
|
||||
|
||||
| API | 作用 |
|
||||
|-----|------|
|
||||
| `spawn_agent({ message })` | 创建 subagent,返回 `agent_id` |
|
||||
| `wait({ ids, timeout_ms })` | 等待结果(唯一取结果入口) |
|
||||
| `send_input({ id, message })` | 继续交互/追问 |
|
||||
| `close_agent({ id })` | 关闭回收(不可逆) |
|
||||
|
||||
### 可用模式
|
||||
|
||||
- **单 Agent 深度交互**: 一个 agent 多阶段,`send_input` 继续
|
||||
- **多 Agent 并行**: 主协调器 + 多 worker,`wait({ ids: [...] })` 批量等待
|
||||
- **混合模式**: 按需组合
|
||||
|
||||
## Execution Modes
|
||||
|
||||
### Mode 1: Interactive
|
||||
|
||||
User manually selects each action, suitable for complex tasks.
|
||||
|
||||
```
|
||||
User -> Select action -> Execute -> View results -> Select next action
|
||||
```
|
||||
|
||||
### Mode 2: Auto-Loop
|
||||
|
||||
Automatic execution in preset order, suitable for standard development flow.
|
||||
|
||||
```
|
||||
Develop -> Debug -> Validate -> (if issues) -> Develop -> ...
|
||||
```
|
||||
|
||||
## Session Structure (Unified Location)
|
||||
|
||||
```
|
||||
.workflow/.loop/
|
||||
+-- {loopId}.json # Master state file (API + Skill shared)
|
||||
+-- {loopId}.tasks.jsonl # Task list (API managed)
|
||||
+-- {loopId}.progress/ # Skill progress files
|
||||
+-- develop.md # Development progress timeline
|
||||
+-- debug.md # Understanding evolution document
|
||||
+-- validate.md # Validation report
|
||||
+-- changes.log # Code changes log (NDJSON)
|
||||
+-- debug.log # Debug log (NDJSON)
|
||||
```
|
||||
|
||||
## Implementation (Codex Subagent Pattern)
|
||||
|
||||
### Session Setup
|
||||
|
||||
```javascript
|
||||
// Helper: Get UTC+8 (China Standard Time) ISO string
|
||||
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
|
||||
|
||||
// loopId source:
|
||||
// 1. API trigger: from --loop-id parameter
|
||||
// 2. Direct call: generate new loop-v2-{timestamp}-{random}
|
||||
|
||||
const loopId = args['--loop-id'] || (() => {
|
||||
const timestamp = getUtc8ISOString().replace(/[-:]/g, '').split('.')[0]
|
||||
const random = Math.random().toString(36).substring(2, 10)
|
||||
return `loop-v2-${timestamp}-${random}`
|
||||
})()
|
||||
|
||||
const loopFile = `.workflow/.loop/${loopId}.json`
|
||||
const progressDir = `.workflow/.loop/${loopId}.progress`
|
||||
|
||||
// Create progress directory
|
||||
mkdir -p "${progressDir}"
|
||||
```
|
||||
|
||||
### Main Execution Flow (Single Agent Deep Interaction)
|
||||
|
||||
```javascript
|
||||
// ==================== CODEX CCW-LOOP: SINGLE AGENT ORCHESTRATOR ====================
|
||||
|
||||
// Step 1: Read or create initial state
|
||||
let state = null
|
||||
if (existingLoopId) {
|
||||
state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
if (!state) {
|
||||
console.error(`Loop not found: ${loopId}`)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
state = createInitialState(loopId, taskDescription)
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
}
|
||||
|
||||
// Step 2: Create orchestrator agent (single agent handles all phases)
|
||||
const agent = spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/ccw-loop-executor.md (MUST read first)
|
||||
2. Read: .workflow/project-tech.json
|
||||
3. Read: .workflow/project-guidelines.json
|
||||
|
||||
---
|
||||
|
||||
## LOOP CONTEXT
|
||||
|
||||
- **Loop ID**: ${loopId}
|
||||
- **State File**: .workflow/.loop/${loopId}.json
|
||||
- **Progress Dir**: ${progressDir}
|
||||
- **Mode**: ${mode} // 'interactive' or 'auto'
|
||||
|
||||
## CURRENT STATE
|
||||
|
||||
${JSON.stringify(state, null, 2)}
|
||||
|
||||
## TASK DESCRIPTION
|
||||
|
||||
${taskDescription}
|
||||
|
||||
## EXECUTION INSTRUCTIONS
|
||||
|
||||
You are executing CCW Loop orchestrator. Your job:
|
||||
|
||||
1. **Check Control Signals**
|
||||
- Read .workflow/.loop/${loopId}.json
|
||||
- If status === 'paused' -> Output "PAUSED" and stop
|
||||
- If status === 'failed' -> Output "STOPPED" and stop
|
||||
- If status === 'running' -> Continue
|
||||
|
||||
2. **Select Next Action**
|
||||
Based on skill_state:
|
||||
- If not initialized -> Execute INIT
|
||||
- If mode === 'interactive' -> Output MENU and wait for input
|
||||
- If mode === 'auto' -> Auto-select based on state
|
||||
|
||||
3. **Execute Action**
|
||||
- Follow action instructions from ~/.codex/skills/ccw-loop/phases/actions/
|
||||
- Update progress files in ${progressDir}/
|
||||
- Update state in .workflow/.loop/${loopId}.json
|
||||
|
||||
4. **Output Format**
|
||||
\`\`\`
|
||||
ACTION_RESULT:
|
||||
- action: {action_name}
|
||||
- status: success | failed | needs_input
|
||||
- message: {user message}
|
||||
- state_updates: {JSON of skill_state updates}
|
||||
|
||||
NEXT_ACTION_NEEDED: {action_name} | WAITING_INPUT | COMPLETED | PAUSED
|
||||
\`\`\`
|
||||
|
||||
## FIRST ACTION
|
||||
|
||||
${!state.skill_state ? 'Execute: INIT' : mode === 'auto' ? 'Auto-select next action' : 'Show MENU'}
|
||||
`
|
||||
})
|
||||
|
||||
// Step 3: Main orchestration loop
|
||||
let iteration = 0
|
||||
const maxIterations = state.max_iterations || 10
|
||||
|
||||
while (iteration < maxIterations) {
|
||||
iteration++
|
||||
|
||||
// Wait for agent output
|
||||
const result = wait({ ids: [agent], timeout_ms: 600000 })
|
||||
const output = result.status[agent].completed
|
||||
|
||||
// Parse action result
|
||||
const actionResult = parseActionResult(output)
|
||||
|
||||
// Handle different outcomes
|
||||
switch (actionResult.next_action) {
|
||||
case 'COMPLETED':
|
||||
case 'PAUSED':
|
||||
case 'STOPPED':
|
||||
close_agent({ id: agent })
|
||||
return actionResult
|
||||
|
||||
case 'WAITING_INPUT':
|
||||
// Interactive mode: display menu, get user choice
|
||||
const userChoice = await displayMenuAndGetChoice(actionResult)
|
||||
|
||||
// Send user choice back to agent
|
||||
send_input({
|
||||
id: agent,
|
||||
message: `
|
||||
## USER INPUT RECEIVED
|
||||
|
||||
Action selected: ${userChoice.action}
|
||||
${userChoice.data ? `Additional data: ${JSON.stringify(userChoice.data)}` : ''}
|
||||
|
||||
## EXECUTE SELECTED ACTION
|
||||
|
||||
Follow instructions for: ${userChoice.action}
|
||||
Update state and progress files accordingly.
|
||||
`
|
||||
})
|
||||
break
|
||||
|
||||
default:
|
||||
// Auto mode: agent continues to next action
|
||||
// Check if we need to prompt for continuation
|
||||
if (actionResult.next_action && actionResult.next_action !== 'NONE') {
|
||||
send_input({
|
||||
id: agent,
|
||||
message: `
|
||||
## CONTINUE EXECUTION
|
||||
|
||||
Previous action completed: ${actionResult.action}
|
||||
Result: ${actionResult.status}
|
||||
|
||||
## EXECUTE NEXT ACTION
|
||||
|
||||
Continue with: ${actionResult.next_action}
|
||||
`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Update iteration count in state
|
||||
const currentState = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
currentState.current_iteration = iteration
|
||||
currentState.updated_at = getUtc8ISOString()
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(currentState, null, 2))
|
||||
}
|
||||
|
||||
// Step 4: Cleanup
|
||||
close_agent({ id: agent })
|
||||
```
|
||||
|
||||
## Action Catalog
|
||||
|
||||
| Action | Purpose | Output Files | Trigger |
|
||||
|--------|---------|--------------|---------|
|
||||
| [action-init](phases/actions/action-init.md) | Initialize loop session | meta.json, state.json | First run |
|
||||
| [action-develop](phases/actions/action-develop.md) | Execute development task | progress.md, tasks.json | Has pending tasks |
|
||||
| [action-debug](phases/actions/action-debug.md) | Hypothesis-driven debug | understanding.md, hypotheses.json | Needs debugging |
|
||||
| [action-validate](phases/actions/action-validate.md) | Test and validate | validation.md, test-results.json | Needs validation |
|
||||
| [action-complete](phases/actions/action-complete.md) | Complete loop | summary.md | All done |
|
||||
| [action-menu](phases/actions/action-menu.md) | Display action menu | - | Interactive mode |
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Start new loop (direct call)
|
||||
/ccw-loop TASK="Implement user authentication"
|
||||
|
||||
# Continue existing loop (API trigger or manual resume)
|
||||
/ccw-loop --loop-id=loop-v2-20260122-abc123
|
||||
|
||||
# Auto-cycle mode
|
||||
/ccw-loop --auto TASK="Fix login bug and add tests"
|
||||
|
||||
# API triggered auto-cycle
|
||||
/ccw-loop --loop-id=loop-v2-20260122-abc123 --auto
|
||||
```
|
||||
|
||||
## Reference Documents
|
||||
|
||||
| Document | Purpose |
|
||||
|----------|---------|
|
||||
| [phases/orchestrator.md](phases/orchestrator.md) | Orchestrator: state reading + action selection |
|
||||
| [phases/state-schema.md](phases/state-schema.md) | State structure definition |
|
||||
| [specs/loop-requirements.md](specs/loop-requirements.md) | Loop requirements specification |
|
||||
| [specs/action-catalog.md](specs/action-catalog.md) | Action catalog |
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| Session not found | Create new session |
|
||||
| State file corrupted | Rebuild from file contents |
|
||||
| Agent timeout | send_input to request convergence |
|
||||
| Agent unexpectedly closed | Re-spawn, paste previous output |
|
||||
| Tests fail | Loop back to develop/debug |
|
||||
| >10 iterations | Warn user, suggest break |
|
||||
|
||||
## Codex Best Practices Applied
|
||||
|
||||
1. **Role Path Passing**: Agent reads role file itself (no content embedding)
|
||||
2. **Single Agent Deep Interaction**: Use send_input for multi-phase instead of multiple agents
|
||||
3. **Delayed close_agent**: Only close after confirming no more interaction needed
|
||||
4. **Context Reuse**: Same agent maintains all exploration context automatically
|
||||
5. **Explicit wait()**: Always use wait({ ids }) to get results, not close_agent
|
||||
269
.codex/skills/ccw-loop/phases/actions/action-complete.md
Normal file
269
.codex/skills/ccw-loop/phases/actions/action-complete.md
Normal file
@@ -0,0 +1,269 @@
|
||||
# Action: COMPLETE
|
||||
|
||||
Complete CCW Loop session and generate summary report.
|
||||
|
||||
## Purpose
|
||||
|
||||
- Generate completion report
|
||||
- Aggregate all phase results
|
||||
- Provide follow-up recommendations
|
||||
- Offer expansion to issues
|
||||
- Mark status as completed
|
||||
|
||||
## Preconditions
|
||||
|
||||
- [ ] state.status === 'running'
|
||||
- [ ] state.skill_state !== null
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Verify Control Signals
|
||||
|
||||
```javascript
|
||||
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
|
||||
if (state.status !== 'running') {
|
||||
return {
|
||||
action: 'COMPLETE',
|
||||
status: 'failed',
|
||||
message: `Cannot complete: status is ${state.status}`,
|
||||
next_action: state.status === 'paused' ? 'PAUSED' : 'STOPPED'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Aggregate Statistics
|
||||
|
||||
```javascript
|
||||
const stats = {
|
||||
// Time statistics
|
||||
duration: Date.now() - new Date(state.created_at).getTime(),
|
||||
iterations: state.current_iteration,
|
||||
|
||||
// Development statistics
|
||||
develop: {
|
||||
total_tasks: state.skill_state.develop.total,
|
||||
completed_tasks: state.skill_state.develop.completed,
|
||||
completion_rate: state.skill_state.develop.total > 0
|
||||
? ((state.skill_state.develop.completed / state.skill_state.develop.total) * 100).toFixed(1)
|
||||
: 0
|
||||
},
|
||||
|
||||
// Debug statistics
|
||||
debug: {
|
||||
iterations: state.skill_state.debug.iteration,
|
||||
hypotheses_tested: state.skill_state.debug.hypotheses.length,
|
||||
root_cause_found: state.skill_state.debug.confirmed_hypothesis !== null
|
||||
},
|
||||
|
||||
// Validation statistics
|
||||
validate: {
|
||||
runs: state.skill_state.validate.test_results.length,
|
||||
passed: state.skill_state.validate.passed,
|
||||
coverage: state.skill_state.validate.coverage,
|
||||
failed_tests: state.skill_state.validate.failed_tests.length
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Generate Summary Report
|
||||
|
||||
```javascript
|
||||
const timestamp = getUtc8ISOString()
|
||||
|
||||
const summaryReport = `# CCW Loop Session Summary
|
||||
|
||||
**Loop ID**: ${loopId}
|
||||
**Task**: ${state.description}
|
||||
**Started**: ${state.created_at}
|
||||
**Completed**: ${timestamp}
|
||||
**Duration**: ${formatDuration(stats.duration)}
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
${state.skill_state.validate.passed
|
||||
? 'All tests passed, validation successful'
|
||||
: state.skill_state.develop.completed === state.skill_state.develop.total
|
||||
? 'Development complete, validation not passed - needs debugging'
|
||||
: 'Task partially complete - pending items remain'}
|
||||
|
||||
---
|
||||
|
||||
## Development Phase
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total Tasks | ${stats.develop.total_tasks} |
|
||||
| Completed | ${stats.develop.completed_tasks} |
|
||||
| Completion Rate | ${stats.develop.completion_rate}% |
|
||||
|
||||
### Completed Tasks
|
||||
|
||||
${state.skill_state.develop.tasks.filter(t => t.status === 'completed').map(t => `
|
||||
- ${t.description}
|
||||
- Files: ${t.files_changed?.join(', ') || 'N/A'}
|
||||
- Completed: ${t.completed_at}
|
||||
`).join('\n')}
|
||||
|
||||
### Pending Tasks
|
||||
|
||||
${state.skill_state.develop.tasks.filter(t => t.status !== 'completed').map(t => `
|
||||
- ${t.description}
|
||||
`).join('\n') || '_None_'}
|
||||
|
||||
---
|
||||
|
||||
## Debug Phase
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Iterations | ${stats.debug.iterations} |
|
||||
| Hypotheses Tested | ${stats.debug.hypotheses_tested} |
|
||||
| Root Cause Found | ${stats.debug.root_cause_found ? 'Yes' : 'No'} |
|
||||
|
||||
${stats.debug.root_cause_found ? `
|
||||
### Confirmed Root Cause
|
||||
|
||||
${state.skill_state.debug.confirmed_hypothesis}: ${state.skill_state.debug.hypotheses.find(h => h.id === state.skill_state.debug.confirmed_hypothesis)?.description}
|
||||
` : ''}
|
||||
|
||||
---
|
||||
|
||||
## Validation Phase
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Test Runs | ${stats.validate.runs} |
|
||||
| Status | ${stats.validate.passed ? 'PASSED' : 'FAILED'} |
|
||||
| Coverage | ${stats.validate.coverage || 'N/A'}% |
|
||||
| Failed Tests | ${stats.validate.failed_tests} |
|
||||
|
||||
---
|
||||
|
||||
## Recommendations
|
||||
|
||||
${generateRecommendations(stats, state)}
|
||||
|
||||
---
|
||||
|
||||
## Session Artifacts
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| \`develop.md\` | Development progress timeline |
|
||||
| \`debug.md\` | Debug exploration and learnings |
|
||||
| \`validate.md\` | Validation report |
|
||||
| \`test-results.json\` | Test execution results |
|
||||
|
||||
---
|
||||
|
||||
*Generated by CCW Loop at ${timestamp}*
|
||||
`
|
||||
|
||||
Write(`${progressDir}/summary.md`, summaryReport)
|
||||
```
|
||||
|
||||
### Step 4: Update State to Completed
|
||||
|
||||
```javascript
|
||||
state.status = 'completed'
|
||||
state.completed_at = timestamp
|
||||
state.updated_at = timestamp
|
||||
state.skill_state.last_action = 'COMPLETE'
|
||||
state.skill_state.summary = stats
|
||||
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
ACTION_RESULT:
|
||||
- action: COMPLETE
|
||||
- status: success
|
||||
- message: Loop completed. Duration: {duration}, Iterations: {N}
|
||||
- state_updates: {
|
||||
"status": "completed",
|
||||
"completed_at": "{timestamp}"
|
||||
}
|
||||
|
||||
FILES_UPDATED:
|
||||
- .workflow/.loop/{loopId}.json: Status set to completed
|
||||
- .workflow/.loop/{loopId}.progress/summary.md: Summary report generated
|
||||
|
||||
NEXT_ACTION_NEEDED: COMPLETED
|
||||
```
|
||||
|
||||
## Expansion Options
|
||||
|
||||
After completion, offer expansion to issues:
|
||||
|
||||
```
|
||||
## Expansion Options
|
||||
|
||||
Would you like to create follow-up issues?
|
||||
|
||||
1. [test] Add more test cases
|
||||
2. [enhance] Feature enhancements
|
||||
3. [refactor] Code refactoring
|
||||
4. [doc] Documentation updates
|
||||
5. [none] No expansion needed
|
||||
|
||||
Select options (comma-separated) or 'none':
|
||||
```
|
||||
|
||||
## Helper Functions
|
||||
|
||||
```javascript
|
||||
function formatDuration(ms) {
|
||||
const seconds = Math.floor(ms / 1000)
|
||||
const minutes = Math.floor(seconds / 60)
|
||||
const hours = Math.floor(minutes / 60)
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}h ${minutes % 60}m`
|
||||
} else if (minutes > 0) {
|
||||
return `${minutes}m ${seconds % 60}s`
|
||||
} else {
|
||||
return `${seconds}s`
|
||||
}
|
||||
}
|
||||
|
||||
function generateRecommendations(stats, state) {
|
||||
const recommendations = []
|
||||
|
||||
if (stats.develop.completion_rate < 100) {
|
||||
recommendations.push('- Complete remaining development tasks')
|
||||
}
|
||||
|
||||
if (!stats.validate.passed) {
|
||||
recommendations.push('- Fix failing tests')
|
||||
}
|
||||
|
||||
if (stats.validate.coverage && stats.validate.coverage < 80) {
|
||||
recommendations.push(`- Improve test coverage (current: ${stats.validate.coverage}%)`)
|
||||
}
|
||||
|
||||
if (recommendations.length === 0) {
|
||||
recommendations.push('- Consider code review')
|
||||
recommendations.push('- Update documentation')
|
||||
recommendations.push('- Prepare for deployment')
|
||||
}
|
||||
|
||||
return recommendations.join('\n')
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error Type | Recovery |
|
||||
|------------|----------|
|
||||
| Report generation failed | Show basic stats, skip file write |
|
||||
| Issue creation failed | Log error, continue completion |
|
||||
|
||||
## Next Actions
|
||||
|
||||
- None (terminal state)
|
||||
- To continue: Use `/ccw-loop --loop-id={loopId}` to reopen (will set status back to running)
|
||||
286
.codex/skills/ccw-loop/phases/actions/action-debug.md
Normal file
286
.codex/skills/ccw-loop/phases/actions/action-debug.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# Action: DEBUG
|
||||
|
||||
Hypothesis-driven debugging with understanding evolution documentation.
|
||||
|
||||
## Purpose
|
||||
|
||||
- Locate error source
|
||||
- Generate testable hypotheses
|
||||
- Add NDJSON instrumentation
|
||||
- Analyze log evidence
|
||||
- Correct understanding based on evidence
|
||||
- Apply fixes
|
||||
|
||||
## Preconditions
|
||||
|
||||
- [ ] state.status === 'running'
|
||||
- [ ] state.skill_state !== null
|
||||
|
||||
## Mode Detection
|
||||
|
||||
```javascript
|
||||
const understandingPath = `${progressDir}/debug.md`
|
||||
const debugLogPath = `${progressDir}/debug.log`
|
||||
|
||||
const understandingExists = fs.existsSync(understandingPath)
|
||||
const logHasContent = fs.existsSync(debugLogPath) && fs.statSync(debugLogPath).size > 0
|
||||
|
||||
const debugMode = logHasContent ? 'analyze' : (understandingExists ? 'continue' : 'explore')
|
||||
```
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Mode: Explore (First Debug)
|
||||
|
||||
#### Step E1: Get Bug Description
|
||||
|
||||
```javascript
|
||||
// From test failures or user input
|
||||
const bugDescription = state.skill_state.validate?.failed_tests?.[0]
|
||||
|| await getUserInput('Describe the bug:')
|
||||
```
|
||||
|
||||
#### Step E2: Search Codebase
|
||||
|
||||
```javascript
|
||||
// Use ACE search_context to find related code
|
||||
const searchResults = mcp__ace-tool__search_context({
|
||||
project_root_path: '.',
|
||||
query: `code related to: ${bugDescription}`
|
||||
})
|
||||
```
|
||||
|
||||
#### Step E3: Generate Hypotheses
|
||||
|
||||
```javascript
|
||||
const hypotheses = [
|
||||
{
|
||||
id: 'H1',
|
||||
description: 'Most likely cause',
|
||||
testable_condition: 'What to check',
|
||||
logging_point: 'file.ts:functionName:42',
|
||||
evidence_criteria: {
|
||||
confirm: 'If we see X, hypothesis confirmed',
|
||||
reject: 'If we see Y, hypothesis rejected'
|
||||
},
|
||||
likelihood: 1,
|
||||
status: 'pending',
|
||||
evidence: null,
|
||||
verdict_reason: null
|
||||
},
|
||||
// H2, H3...
|
||||
]
|
||||
```
|
||||
|
||||
#### Step E4: Create Understanding Document
|
||||
|
||||
```javascript
|
||||
const initialUnderstanding = `# Understanding Document
|
||||
|
||||
**Loop ID**: ${loopId}
|
||||
**Bug Description**: ${bugDescription}
|
||||
**Started**: ${getUtc8ISOString()}
|
||||
|
||||
---
|
||||
|
||||
## Exploration Timeline
|
||||
|
||||
### Iteration 1 - Initial Exploration (${getUtc8ISOString()})
|
||||
|
||||
#### Current Understanding
|
||||
|
||||
Based on bug description and code search:
|
||||
|
||||
- Error pattern: [identified pattern]
|
||||
- Affected areas: [files/modules]
|
||||
- Initial hypothesis: [first thoughts]
|
||||
|
||||
#### Evidence from Code Search
|
||||
|
||||
[Search results summary]
|
||||
|
||||
#### Hypotheses
|
||||
|
||||
${hypotheses.map(h => `
|
||||
**${h.id}**: ${h.description}
|
||||
- Testable condition: ${h.testable_condition}
|
||||
- Logging point: ${h.logging_point}
|
||||
- Likelihood: ${h.likelihood}
|
||||
`).join('\n')}
|
||||
|
||||
---
|
||||
|
||||
## Current Consolidated Understanding
|
||||
|
||||
[Summary of what we know so far]
|
||||
`
|
||||
|
||||
Write(understandingPath, initialUnderstanding)
|
||||
Write(`${progressDir}/hypotheses.json`, JSON.stringify({ hypotheses, iteration: 1 }, null, 2))
|
||||
```
|
||||
|
||||
#### Step E5: Add NDJSON Logging Points
|
||||
|
||||
```javascript
|
||||
// For each hypothesis, add instrumentation
|
||||
for (const hypothesis of hypotheses) {
|
||||
const [file, func, line] = hypothesis.logging_point.split(':')
|
||||
|
||||
const logStatement = `console.log(JSON.stringify({
|
||||
hid: "${hypothesis.id}",
|
||||
ts: Date.now(),
|
||||
func: "${func}",
|
||||
data: { /* relevant context */ }
|
||||
}))`
|
||||
|
||||
// Add to file using Edit tool
|
||||
}
|
||||
```
|
||||
|
||||
### Mode: Analyze (Has Logs)
|
||||
|
||||
#### Step A1: Parse Debug Log
|
||||
|
||||
```javascript
|
||||
const logContent = Read(debugLogPath)
|
||||
const entries = logContent.split('\n')
|
||||
.filter(l => l.trim())
|
||||
.map(l => JSON.parse(l))
|
||||
|
||||
// Group by hypothesis ID
|
||||
const byHypothesis = entries.reduce((acc, e) => {
|
||||
acc[e.hid] = acc[e.hid] || []
|
||||
acc[e.hid].push(e)
|
||||
return acc
|
||||
}, {})
|
||||
```
|
||||
|
||||
#### Step A2: Evaluate Evidence
|
||||
|
||||
```javascript
|
||||
const hypothesesData = JSON.parse(Read(`${progressDir}/hypotheses.json`))
|
||||
|
||||
for (const hypothesis of hypothesesData.hypotheses) {
|
||||
const evidence = byHypothesis[hypothesis.id] || []
|
||||
|
||||
// Evaluate against criteria
|
||||
if (matchesConfirmCriteria(evidence, hypothesis.evidence_criteria.confirm)) {
|
||||
hypothesis.status = 'confirmed'
|
||||
hypothesis.evidence = evidence
|
||||
hypothesis.verdict_reason = 'Evidence matches confirm criteria'
|
||||
} else if (matchesRejectCriteria(evidence, hypothesis.evidence_criteria.reject)) {
|
||||
hypothesis.status = 'rejected'
|
||||
hypothesis.evidence = evidence
|
||||
hypothesis.verdict_reason = 'Evidence matches reject criteria'
|
||||
} else {
|
||||
hypothesis.status = 'inconclusive'
|
||||
hypothesis.evidence = evidence
|
||||
hypothesis.verdict_reason = 'Insufficient evidence'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Step A3: Update Understanding
|
||||
|
||||
```javascript
|
||||
const iteration = hypothesesData.iteration + 1
|
||||
const timestamp = getUtc8ISOString()
|
||||
|
||||
const analysisEntry = `
|
||||
### Iteration ${iteration} - Evidence Analysis (${timestamp})
|
||||
|
||||
#### Log Analysis Results
|
||||
|
||||
${hypothesesData.hypotheses.map(h => `
|
||||
**${h.id}**: ${h.status.toUpperCase()}
|
||||
- Evidence: ${JSON.stringify(h.evidence?.slice(0, 3))}
|
||||
- Reasoning: ${h.verdict_reason}
|
||||
`).join('\n')}
|
||||
|
||||
#### Corrected Understanding
|
||||
|
||||
[Any corrections to previous assumptions]
|
||||
|
||||
${confirmedHypothesis ? `
|
||||
#### Root Cause Identified
|
||||
|
||||
**${confirmedHypothesis.id}**: ${confirmedHypothesis.description}
|
||||
` : `
|
||||
#### Next Steps
|
||||
|
||||
[What to investigate next]
|
||||
`}
|
||||
|
||||
---
|
||||
`
|
||||
|
||||
const existingUnderstanding = Read(understandingPath)
|
||||
Write(understandingPath, existingUnderstanding + analysisEntry)
|
||||
```
|
||||
|
||||
### Step: Update State
|
||||
|
||||
```javascript
|
||||
state.skill_state.debug.active_bug = bugDescription
|
||||
state.skill_state.debug.hypotheses = hypothesesData.hypotheses
|
||||
state.skill_state.debug.hypotheses_count = hypothesesData.hypotheses.length
|
||||
state.skill_state.debug.iteration = iteration
|
||||
state.skill_state.debug.last_analysis_at = timestamp
|
||||
|
||||
if (confirmedHypothesis) {
|
||||
state.skill_state.debug.confirmed_hypothesis = confirmedHypothesis.id
|
||||
}
|
||||
|
||||
state.skill_state.last_action = 'DEBUG'
|
||||
state.updated_at = timestamp
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
ACTION_RESULT:
|
||||
- action: DEBUG
|
||||
- status: success
|
||||
- message: {Mode description} - {result summary}
|
||||
- state_updates: {
|
||||
"debug.iteration": {N},
|
||||
"debug.confirmed_hypothesis": "{id or null}"
|
||||
}
|
||||
|
||||
FILES_UPDATED:
|
||||
- .workflow/.loop/{loopId}.progress/debug.md: Understanding updated
|
||||
- .workflow/.loop/{loopId}.progress/hypotheses.json: Hypotheses updated
|
||||
- [Source files]: Instrumentation added
|
||||
|
||||
NEXT_ACTION_NEEDED: {DEBUG | VALIDATE | DEVELOP | MENU}
|
||||
```
|
||||
|
||||
## Next Action Selection
|
||||
|
||||
```javascript
|
||||
if (confirmedHypothesis) {
|
||||
// Root cause found, apply fix and validate
|
||||
return 'VALIDATE'
|
||||
} else if (allRejected) {
|
||||
// Generate new hypotheses
|
||||
return 'DEBUG'
|
||||
} else {
|
||||
// Need more evidence - prompt user to reproduce bug
|
||||
return 'WAITING_INPUT' // User needs to trigger bug
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error Type | Recovery |
|
||||
|------------|----------|
|
||||
| Empty debug.log | Prompt user to reproduce bug |
|
||||
| All hypotheses rejected | Generate new hypotheses |
|
||||
| >5 iterations | Suggest escalation |
|
||||
|
||||
## Next Actions
|
||||
|
||||
- Root cause found: `VALIDATE`
|
||||
- Need more evidence: `DEBUG` (after reproduction)
|
||||
- All rejected: `DEBUG` (new hypotheses)
|
||||
183
.codex/skills/ccw-loop/phases/actions/action-develop.md
Normal file
183
.codex/skills/ccw-loop/phases/actions/action-develop.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# Action: DEVELOP
|
||||
|
||||
Execute development task and record progress to develop.md.
|
||||
|
||||
## Purpose
|
||||
|
||||
- Execute next pending development task
|
||||
- Implement code changes
|
||||
- Record progress to Markdown file
|
||||
- Update task status in state
|
||||
|
||||
## Preconditions
|
||||
|
||||
- [ ] state.status === 'running'
|
||||
- [ ] state.skill_state !== null
|
||||
- [ ] state.skill_state.develop.tasks.some(t => t.status === 'pending')
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Verify Control Signals
|
||||
|
||||
```javascript
|
||||
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
|
||||
if (state.status !== 'running') {
|
||||
return {
|
||||
action: 'DEVELOP',
|
||||
status: 'failed',
|
||||
message: `Cannot develop: status is ${state.status}`,
|
||||
next_action: state.status === 'paused' ? 'PAUSED' : 'STOPPED'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Find Next Pending Task
|
||||
|
||||
```javascript
|
||||
const tasks = state.skill_state.develop.tasks
|
||||
const currentTask = tasks.find(t => t.status === 'pending')
|
||||
|
||||
if (!currentTask) {
|
||||
return {
|
||||
action: 'DEVELOP',
|
||||
status: 'success',
|
||||
message: 'All development tasks completed',
|
||||
next_action: mode === 'auto' ? 'VALIDATE' : 'MENU'
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as in_progress
|
||||
currentTask.status = 'in_progress'
|
||||
```
|
||||
|
||||
### Step 3: Execute Development Task
|
||||
|
||||
```javascript
|
||||
console.log(`Executing task: ${currentTask.description}`)
|
||||
|
||||
// Use appropriate tools based on task type
|
||||
// - ACE search_context for finding patterns
|
||||
// - Read for loading files
|
||||
// - Edit/Write for making changes
|
||||
|
||||
// Record files changed
|
||||
const filesChanged = []
|
||||
|
||||
// Implementation logic...
|
||||
```
|
||||
|
||||
### Step 4: Record Changes to Log (NDJSON)
|
||||
|
||||
```javascript
|
||||
const changesLogPath = `${progressDir}/changes.log`
|
||||
const timestamp = getUtc8ISOString()
|
||||
|
||||
const changeEntry = {
|
||||
timestamp: timestamp,
|
||||
task_id: currentTask.id,
|
||||
description: currentTask.description,
|
||||
files_changed: filesChanged,
|
||||
result: 'success'
|
||||
}
|
||||
|
||||
// Append to NDJSON log
|
||||
const existingLog = Read(changesLogPath) || ''
|
||||
Write(changesLogPath, existingLog + JSON.stringify(changeEntry) + '\n')
|
||||
```
|
||||
|
||||
### Step 5: Update Progress Document
|
||||
|
||||
```javascript
|
||||
const progressPath = `${progressDir}/develop.md`
|
||||
const iteration = state.skill_state.develop.completed + 1
|
||||
|
||||
const progressEntry = `
|
||||
### Iteration ${iteration} - ${currentTask.description} (${timestamp})
|
||||
|
||||
#### Task Details
|
||||
|
||||
- **ID**: ${currentTask.id}
|
||||
- **Tool**: ${currentTask.tool}
|
||||
- **Mode**: ${currentTask.mode}
|
||||
|
||||
#### Implementation Summary
|
||||
|
||||
[Implementation description]
|
||||
|
||||
#### Files Changed
|
||||
|
||||
${filesChanged.map(f => `- \`${f}\``).join('\n') || '- No files changed'}
|
||||
|
||||
#### Status: COMPLETED
|
||||
|
||||
---
|
||||
|
||||
`
|
||||
|
||||
const existingProgress = Read(progressPath)
|
||||
Write(progressPath, existingProgress + progressEntry)
|
||||
```
|
||||
|
||||
### Step 6: Update State
|
||||
|
||||
```javascript
|
||||
currentTask.status = 'completed'
|
||||
currentTask.completed_at = timestamp
|
||||
currentTask.files_changed = filesChanged
|
||||
|
||||
state.skill_state.develop.completed += 1
|
||||
state.skill_state.develop.current_task = null
|
||||
state.skill_state.develop.last_progress_at = timestamp
|
||||
state.skill_state.last_action = 'DEVELOP'
|
||||
state.skill_state.completed_actions.push('DEVELOP')
|
||||
state.updated_at = timestamp
|
||||
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
ACTION_RESULT:
|
||||
- action: DEVELOP
|
||||
- status: success
|
||||
- message: Task completed: {task_description}
|
||||
- state_updates: {
|
||||
"develop.completed": {N},
|
||||
"develop.last_progress_at": "{timestamp}"
|
||||
}
|
||||
|
||||
FILES_UPDATED:
|
||||
- .workflow/.loop/{loopId}.json: Task status updated
|
||||
- .workflow/.loop/{loopId}.progress/develop.md: Progress entry added
|
||||
- .workflow/.loop/{loopId}.progress/changes.log: Change entry added
|
||||
|
||||
NEXT_ACTION_NEEDED: {DEVELOP | DEBUG | VALIDATE | MENU}
|
||||
```
|
||||
|
||||
## Auto Mode Next Action Selection
|
||||
|
||||
```javascript
|
||||
const pendingTasks = tasks.filter(t => t.status === 'pending')
|
||||
|
||||
if (pendingTasks.length > 0) {
|
||||
return 'DEVELOP' // More tasks to do
|
||||
} else {
|
||||
return 'DEBUG' // All done, check for issues
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error Type | Recovery |
|
||||
|------------|----------|
|
||||
| Task execution failed | Mark task as failed, continue to next |
|
||||
| File write failed | Retry once, then report error |
|
||||
| All tasks done | Move to DEBUG or VALIDATE |
|
||||
|
||||
## Next Actions
|
||||
|
||||
- More pending tasks: `DEVELOP`
|
||||
- All tasks complete: `DEBUG` (auto) or `MENU` (interactive)
|
||||
- Task failed: `DEVELOP` (retry) or `DEBUG` (investigate)
|
||||
164
.codex/skills/ccw-loop/phases/actions/action-init.md
Normal file
164
.codex/skills/ccw-loop/phases/actions/action-init.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# Action: INIT
|
||||
|
||||
Initialize CCW Loop session, create directory structure and initial state.
|
||||
|
||||
## Purpose
|
||||
|
||||
- Create session directory structure
|
||||
- Initialize state file with skill_state
|
||||
- Analyze task description to generate development tasks
|
||||
- Prepare execution environment
|
||||
|
||||
## Preconditions
|
||||
|
||||
- [ ] state.status === 'running'
|
||||
- [ ] state.skill_state === null
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Verify Control Signals
|
||||
|
||||
```javascript
|
||||
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
|
||||
if (state.status !== 'running') {
|
||||
return {
|
||||
action: 'INIT',
|
||||
status: 'failed',
|
||||
message: `Cannot init: status is ${state.status}`,
|
||||
next_action: state.status === 'paused' ? 'PAUSED' : 'STOPPED'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Create Directory Structure
|
||||
|
||||
```javascript
|
||||
const progressDir = `.workflow/.loop/${loopId}.progress`
|
||||
|
||||
// Directories created by orchestrator, verify they exist
|
||||
// mkdir -p ${progressDir}
|
||||
```
|
||||
|
||||
### Step 3: Analyze Task and Generate Tasks
|
||||
|
||||
```javascript
|
||||
// Analyze task description
|
||||
const taskDescription = state.description
|
||||
|
||||
// Generate 3-7 development tasks based on analysis
|
||||
// Use ACE search or smart_search to find relevant patterns
|
||||
|
||||
const tasks = [
|
||||
{
|
||||
id: 'task-001',
|
||||
description: 'Task description based on analysis',
|
||||
tool: 'gemini',
|
||||
mode: 'write',
|
||||
status: 'pending',
|
||||
priority: 1,
|
||||
files: [],
|
||||
created_at: getUtc8ISOString(),
|
||||
completed_at: null
|
||||
}
|
||||
// ... more tasks
|
||||
]
|
||||
```
|
||||
|
||||
### Step 4: Initialize Progress Document
|
||||
|
||||
```javascript
|
||||
const progressPath = `${progressDir}/develop.md`
|
||||
|
||||
const progressInitial = `# Development Progress
|
||||
|
||||
**Loop ID**: ${loopId}
|
||||
**Task**: ${taskDescription}
|
||||
**Started**: ${getUtc8ISOString()}
|
||||
|
||||
---
|
||||
|
||||
## Task List
|
||||
|
||||
${tasks.map((t, i) => `${i + 1}. [ ] ${t.description}`).join('\n')}
|
||||
|
||||
---
|
||||
|
||||
## Progress Timeline
|
||||
|
||||
`
|
||||
|
||||
Write(progressPath, progressInitial)
|
||||
```
|
||||
|
||||
### Step 5: Update State
|
||||
|
||||
```javascript
|
||||
const skillState = {
|
||||
current_action: 'init',
|
||||
last_action: null,
|
||||
completed_actions: [],
|
||||
mode: mode,
|
||||
|
||||
develop: {
|
||||
total: tasks.length,
|
||||
completed: 0,
|
||||
current_task: null,
|
||||
tasks: tasks,
|
||||
last_progress_at: null
|
||||
},
|
||||
|
||||
debug: {
|
||||
active_bug: null,
|
||||
hypotheses_count: 0,
|
||||
hypotheses: [],
|
||||
confirmed_hypothesis: null,
|
||||
iteration: 0,
|
||||
last_analysis_at: null
|
||||
},
|
||||
|
||||
validate: {
|
||||
pass_rate: 0,
|
||||
coverage: 0,
|
||||
test_results: [],
|
||||
passed: false,
|
||||
failed_tests: [],
|
||||
last_run_at: null
|
||||
},
|
||||
|
||||
errors: []
|
||||
}
|
||||
|
||||
state.skill_state = skillState
|
||||
state.updated_at = getUtc8ISOString()
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
ACTION_RESULT:
|
||||
- action: INIT
|
||||
- status: success
|
||||
- message: Session initialized with {N} development tasks
|
||||
|
||||
FILES_UPDATED:
|
||||
- .workflow/.loop/{loopId}.json: skill_state initialized
|
||||
- .workflow/.loop/{loopId}.progress/develop.md: Progress document created
|
||||
|
||||
NEXT_ACTION_NEEDED: {DEVELOP (auto) | MENU (interactive)}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error Type | Recovery |
|
||||
|------------|----------|
|
||||
| Directory creation failed | Report error, stop |
|
||||
| Task analysis failed | Create single generic task |
|
||||
| State write failed | Retry once, then stop |
|
||||
|
||||
## Next Actions
|
||||
|
||||
- Success (auto mode): `DEVELOP`
|
||||
- Success (interactive): `MENU`
|
||||
- Failed: Report error
|
||||
205
.codex/skills/ccw-loop/phases/actions/action-menu.md
Normal file
205
.codex/skills/ccw-loop/phases/actions/action-menu.md
Normal file
@@ -0,0 +1,205 @@
|
||||
# Action: MENU
|
||||
|
||||
Display interactive action menu for user selection.
|
||||
|
||||
## Purpose
|
||||
|
||||
- Show current state summary
|
||||
- Display available actions
|
||||
- Wait for user selection
|
||||
- Return selected action
|
||||
|
||||
## Preconditions
|
||||
|
||||
- [ ] state.status === 'running'
|
||||
- [ ] state.skill_state !== null
|
||||
- [ ] mode === 'interactive'
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Verify Control Signals
|
||||
|
||||
```javascript
|
||||
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
|
||||
if (state.status !== 'running') {
|
||||
return {
|
||||
action: 'MENU',
|
||||
status: 'failed',
|
||||
message: `Cannot show menu: status is ${state.status}`,
|
||||
next_action: state.status === 'paused' ? 'PAUSED' : 'STOPPED'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Generate Status Summary
|
||||
|
||||
```javascript
|
||||
// Development progress
|
||||
const developProgress = state.skill_state.develop.total > 0
|
||||
? `${state.skill_state.develop.completed}/${state.skill_state.develop.total} (${((state.skill_state.develop.completed / state.skill_state.develop.total) * 100).toFixed(0)}%)`
|
||||
: 'Not started'
|
||||
|
||||
// Debug status
|
||||
const debugStatus = state.skill_state.debug.confirmed_hypothesis
|
||||
? 'Root cause found'
|
||||
: state.skill_state.debug.iteration > 0
|
||||
? `Iteration ${state.skill_state.debug.iteration}`
|
||||
: 'Not started'
|
||||
|
||||
// Validation status
|
||||
const validateStatus = state.skill_state.validate.passed
|
||||
? 'PASSED'
|
||||
: state.skill_state.validate.test_results.length > 0
|
||||
? `FAILED (${state.skill_state.validate.failed_tests.length} failures)`
|
||||
: 'Not run'
|
||||
```
|
||||
|
||||
### Step 3: Display Menu
|
||||
|
||||
```javascript
|
||||
const menuDisplay = `
|
||||
================================================================
|
||||
CCW Loop - ${loopId}
|
||||
================================================================
|
||||
|
||||
Task: ${state.description}
|
||||
Iteration: ${state.current_iteration}
|
||||
|
||||
+-----------------------------------------------------+
|
||||
| Phase | Status |
|
||||
+-----------------------------------------------------+
|
||||
| Develop | ${developProgress.padEnd(35)}|
|
||||
| Debug | ${debugStatus.padEnd(35)}|
|
||||
| Validate | ${validateStatus.padEnd(35)}|
|
||||
+-----------------------------------------------------+
|
||||
|
||||
================================================================
|
||||
|
||||
MENU_OPTIONS:
|
||||
1. [develop] Continue Development - ${state.skill_state.develop.total - state.skill_state.develop.completed} tasks pending
|
||||
2. [debug] Start Debugging - ${debugStatus}
|
||||
3. [validate] Run Validation - ${validateStatus}
|
||||
4. [status] View Detailed Status
|
||||
5. [complete] Complete Loop
|
||||
6. [exit] Exit (save and quit)
|
||||
`
|
||||
|
||||
console.log(menuDisplay)
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
ACTION_RESULT:
|
||||
- action: MENU
|
||||
- status: success
|
||||
- message: ${menuDisplay}
|
||||
|
||||
MENU_OPTIONS:
|
||||
1. [develop] Continue Development - {N} tasks pending
|
||||
2. [debug] Start Debugging - {status}
|
||||
3. [validate] Run Validation - {status}
|
||||
4. [status] View Detailed Status
|
||||
5. [complete] Complete Loop
|
||||
6. [exit] Exit (save and quit)
|
||||
|
||||
NEXT_ACTION_NEEDED: WAITING_INPUT
|
||||
```
|
||||
|
||||
## User Input Handling
|
||||
|
||||
When user provides input, orchestrator sends it back via `send_input`:
|
||||
|
||||
```javascript
|
||||
// User selects "develop"
|
||||
send_input({
|
||||
id: agent,
|
||||
message: `
|
||||
## USER INPUT RECEIVED
|
||||
|
||||
Action selected: develop
|
||||
|
||||
## EXECUTE SELECTED ACTION
|
||||
|
||||
Execute DEVELOP action.
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
## Status Detail View
|
||||
|
||||
If user selects "status":
|
||||
|
||||
```javascript
|
||||
const detailView = `
|
||||
## Detailed Status
|
||||
|
||||
### Development Progress
|
||||
|
||||
${Read(`${progressDir}/develop.md`)?.substring(0, 1000) || 'No progress recorded'}
|
||||
|
||||
### Debug Status
|
||||
|
||||
${state.skill_state.debug.hypotheses.length > 0
|
||||
? state.skill_state.debug.hypotheses.map(h => ` ${h.id}: ${h.status} - ${h.description.substring(0, 50)}...`).join('\n')
|
||||
: ' No debugging started'}
|
||||
|
||||
### Validation Results
|
||||
|
||||
${state.skill_state.validate.test_results.length > 0
|
||||
? ` Last run: ${state.skill_state.validate.last_run_at}
|
||||
Pass rate: ${state.skill_state.validate.pass_rate}%`
|
||||
: ' No validation run yet'}
|
||||
`
|
||||
|
||||
console.log(detailView)
|
||||
|
||||
// Return to menu
|
||||
return {
|
||||
action: 'MENU',
|
||||
status: 'success',
|
||||
message: detailView,
|
||||
next_action: 'MENU' // Show menu again
|
||||
}
|
||||
```
|
||||
|
||||
## Exit Handling
|
||||
|
||||
If user selects "exit":
|
||||
|
||||
```javascript
|
||||
// Save current state
|
||||
state.status = 'user_exit'
|
||||
state.updated_at = getUtc8ISOString()
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
|
||||
return {
|
||||
action: 'MENU',
|
||||
status: 'success',
|
||||
message: 'Session saved. Use --loop-id to resume.',
|
||||
next_action: 'COMPLETED'
|
||||
}
|
||||
```
|
||||
|
||||
## Action Mapping
|
||||
|
||||
| User Selection | Next Action |
|
||||
|----------------|-------------|
|
||||
| develop | DEVELOP |
|
||||
| debug | DEBUG |
|
||||
| validate | VALIDATE |
|
||||
| status | MENU (after showing details) |
|
||||
| complete | COMPLETE |
|
||||
| exit | COMPLETED (save and exit) |
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error Type | Recovery |
|
||||
|------------|----------|
|
||||
| Invalid selection | Show menu again |
|
||||
| User cancels | Return to menu |
|
||||
|
||||
## Next Actions
|
||||
|
||||
Based on user selection - forwarded via `send_input` by orchestrator.
|
||||
250
.codex/skills/ccw-loop/phases/actions/action-validate.md
Normal file
250
.codex/skills/ccw-loop/phases/actions/action-validate.md
Normal file
@@ -0,0 +1,250 @@
|
||||
# Action: VALIDATE
|
||||
|
||||
Run tests and verify implementation, record results to validate.md.
|
||||
|
||||
## Purpose
|
||||
|
||||
- Run unit tests
|
||||
- Run integration tests
|
||||
- Check code coverage
|
||||
- Generate validation report
|
||||
- Determine pass/fail status
|
||||
|
||||
## Preconditions
|
||||
|
||||
- [ ] state.status === 'running'
|
||||
- [ ] state.skill_state !== null
|
||||
- [ ] (develop.completed > 0) OR (debug.confirmed_hypothesis !== null)
|
||||
|
||||
## Execution Steps
|
||||
|
||||
### Step 1: Verify Control Signals
|
||||
|
||||
```javascript
|
||||
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
|
||||
if (state.status !== 'running') {
|
||||
return {
|
||||
action: 'VALIDATE',
|
||||
status: 'failed',
|
||||
message: `Cannot validate: status is ${state.status}`,
|
||||
next_action: state.status === 'paused' ? 'PAUSED' : 'STOPPED'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Detect Test Framework
|
||||
|
||||
```javascript
|
||||
const packageJson = JSON.parse(Read('package.json') || '{}')
|
||||
const testScript = packageJson.scripts?.test || 'npm test'
|
||||
const coverageScript = packageJson.scripts?.['test:coverage']
|
||||
```
|
||||
|
||||
### Step 3: Run Tests
|
||||
|
||||
```javascript
|
||||
const testResult = await Bash({
|
||||
command: testScript,
|
||||
timeout: 300000 // 5 minutes
|
||||
})
|
||||
|
||||
// Parse test output based on framework
|
||||
const testResults = parseTestOutput(testResult.stdout, testResult.stderr)
|
||||
```
|
||||
|
||||
### Step 4: Run Coverage (if available)
|
||||
|
||||
```javascript
|
||||
let coverageData = null
|
||||
|
||||
if (coverageScript) {
|
||||
const coverageResult = await Bash({
|
||||
command: coverageScript,
|
||||
timeout: 300000
|
||||
})
|
||||
|
||||
coverageData = parseCoverageReport(coverageResult.stdout)
|
||||
Write(`${progressDir}/coverage.json`, JSON.stringify(coverageData, null, 2))
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Generate Validation Report
|
||||
|
||||
```javascript
|
||||
const timestamp = getUtc8ISOString()
|
||||
const iteration = (state.skill_state.validate.test_results?.length || 0) + 1
|
||||
|
||||
const validationReport = `# Validation Report
|
||||
|
||||
**Loop ID**: ${loopId}
|
||||
**Task**: ${state.description}
|
||||
**Validated**: ${timestamp}
|
||||
|
||||
---
|
||||
|
||||
## Iteration ${iteration} - Validation Run
|
||||
|
||||
### Test Execution Summary
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total Tests | ${testResults.total} |
|
||||
| Passed | ${testResults.passed} |
|
||||
| Failed | ${testResults.failed} |
|
||||
| Skipped | ${testResults.skipped} |
|
||||
| Duration | ${testResults.duration_ms}ms |
|
||||
| **Pass Rate** | **${((testResults.passed / testResults.total) * 100).toFixed(1)}%** |
|
||||
|
||||
### Coverage Report
|
||||
|
||||
${coverageData ? `
|
||||
| File | Statements | Branches | Functions | Lines |
|
||||
|------|------------|----------|-----------|-------|
|
||||
${coverageData.files.map(f => `| ${f.path} | ${f.statements}% | ${f.branches}% | ${f.functions}% | ${f.lines}% |`).join('\n')}
|
||||
|
||||
**Overall Coverage**: ${coverageData.overall.statements}%
|
||||
` : '_No coverage data available_'}
|
||||
|
||||
### Failed Tests
|
||||
|
||||
${testResults.failed > 0 ? testResults.failures.map(f => `
|
||||
#### ${f.test_name}
|
||||
|
||||
- **Suite**: ${f.suite}
|
||||
- **Error**: ${f.error_message}
|
||||
`).join('\n') : '_All tests passed_'}
|
||||
|
||||
---
|
||||
|
||||
## Validation Decision
|
||||
|
||||
**Result**: ${testResults.failed === 0 ? 'PASS' : 'FAIL'}
|
||||
|
||||
${testResults.failed > 0 ? `
|
||||
### Next Actions
|
||||
|
||||
1. Review failed tests
|
||||
2. Debug failures using DEBUG action
|
||||
3. Fix issues and re-run validation
|
||||
` : `
|
||||
### Next Actions
|
||||
|
||||
1. Consider code review
|
||||
2. Complete loop
|
||||
`}
|
||||
`
|
||||
|
||||
Write(`${progressDir}/validate.md`, validationReport)
|
||||
```
|
||||
|
||||
### Step 6: Save Test Results
|
||||
|
||||
```javascript
|
||||
const testResultsData = {
|
||||
iteration,
|
||||
timestamp,
|
||||
summary: {
|
||||
total: testResults.total,
|
||||
passed: testResults.passed,
|
||||
failed: testResults.failed,
|
||||
skipped: testResults.skipped,
|
||||
pass_rate: ((testResults.passed / testResults.total) * 100).toFixed(1),
|
||||
duration_ms: testResults.duration_ms
|
||||
},
|
||||
tests: testResults.tests,
|
||||
failures: testResults.failures,
|
||||
coverage: coverageData?.overall || null
|
||||
}
|
||||
|
||||
Write(`${progressDir}/test-results.json`, JSON.stringify(testResultsData, null, 2))
|
||||
```
|
||||
|
||||
### Step 7: Update State
|
||||
|
||||
```javascript
|
||||
const validationPassed = testResults.failed === 0 && testResults.passed > 0
|
||||
|
||||
state.skill_state.validate.test_results.push(testResultsData)
|
||||
state.skill_state.validate.pass_rate = parseFloat(testResultsData.summary.pass_rate)
|
||||
state.skill_state.validate.coverage = coverageData?.overall?.statements || 0
|
||||
state.skill_state.validate.passed = validationPassed
|
||||
state.skill_state.validate.failed_tests = testResults.failures.map(f => f.test_name)
|
||||
state.skill_state.validate.last_run_at = timestamp
|
||||
|
||||
state.skill_state.last_action = 'VALIDATE'
|
||||
state.updated_at = timestamp
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
ACTION_RESULT:
|
||||
- action: VALIDATE
|
||||
- status: success
|
||||
- message: Validation {PASSED | FAILED} - {pass_count}/{total_count} tests passed
|
||||
- state_updates: {
|
||||
"validate.passed": {true | false},
|
||||
"validate.pass_rate": {N},
|
||||
"validate.failed_tests": [{list}]
|
||||
}
|
||||
|
||||
FILES_UPDATED:
|
||||
- .workflow/.loop/{loopId}.progress/validate.md: Validation report created
|
||||
- .workflow/.loop/{loopId}.progress/test-results.json: Test results saved
|
||||
- .workflow/.loop/{loopId}.progress/coverage.json: Coverage data saved (if available)
|
||||
|
||||
NEXT_ACTION_NEEDED: {COMPLETE | DEBUG | DEVELOP | MENU}
|
||||
```
|
||||
|
||||
## Next Action Selection
|
||||
|
||||
```javascript
|
||||
if (validationPassed) {
|
||||
const pendingTasks = state.skill_state.develop.tasks.filter(t => t.status === 'pending')
|
||||
if (pendingTasks.length === 0) {
|
||||
return 'COMPLETE'
|
||||
} else {
|
||||
return 'DEVELOP'
|
||||
}
|
||||
} else {
|
||||
// Tests failed - need debugging
|
||||
return 'DEBUG'
|
||||
}
|
||||
```
|
||||
|
||||
## Test Output Parsers
|
||||
|
||||
### Jest/Vitest Parser
|
||||
|
||||
```javascript
|
||||
function parseJestOutput(stdout) {
|
||||
const summaryMatch = stdout.match(/Tests:\s+(\d+)\s+passed.*?(\d+)\s+failed.*?(\d+)\s+total/)
|
||||
// ... implementation
|
||||
}
|
||||
```
|
||||
|
||||
### Pytest Parser
|
||||
|
||||
```javascript
|
||||
function parsePytestOutput(stdout) {
|
||||
const summaryMatch = stdout.match(/(\d+)\s+passed.*?(\d+)\s+failed/)
|
||||
// ... implementation
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error Type | Recovery |
|
||||
|------------|----------|
|
||||
| Tests don't run | Check test script config, report error |
|
||||
| All tests fail | Suggest DEBUG action |
|
||||
| Coverage tool missing | Skip coverage, run tests only |
|
||||
| Timeout | Increase timeout or split tests |
|
||||
|
||||
## Next Actions
|
||||
|
||||
- Validation passed, no pending: `COMPLETE`
|
||||
- Validation passed, has pending: `DEVELOP`
|
||||
- Validation failed: `DEBUG`
|
||||
416
.codex/skills/ccw-loop/phases/orchestrator.md
Normal file
416
.codex/skills/ccw-loop/phases/orchestrator.md
Normal file
@@ -0,0 +1,416 @@
|
||||
# Orchestrator (Codex Pattern)
|
||||
|
||||
Orchestrate CCW Loop using Codex subagent pattern: `spawn_agent -> wait -> send_input -> close_agent`.
|
||||
|
||||
## Role
|
||||
|
||||
Check control signals -> Read file state -> Select action -> Execute via agent -> Update files -> Loop until complete or paused/stopped.
|
||||
|
||||
## Codex Pattern Overview
|
||||
|
||||
```
|
||||
+-- spawn_agent (ccw-loop-executor role) --+
|
||||
| |
|
||||
| Phase 1: INIT or first action |
|
||||
| | |
|
||||
| v |
|
||||
| wait() -> get result |
|
||||
| | |
|
||||
| v |
|
||||
| [If needs input] Collect user input |
|
||||
| | |
|
||||
| v |
|
||||
| send_input(user choice + next action) |
|
||||
| | |
|
||||
| v |
|
||||
| wait() -> get result |
|
||||
| | |
|
||||
| v |
|
||||
| [Loop until COMPLETED/PAUSED/STOPPED] |
|
||||
| | |
|
||||
+----------v-------------------------------+
|
||||
|
|
||||
close_agent()
|
||||
```
|
||||
|
||||
## State Management (Unified Location)
|
||||
|
||||
### Read State
|
||||
|
||||
```javascript
|
||||
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
|
||||
|
||||
/**
|
||||
* Read loop state (unified location)
|
||||
* @param loopId - Loop ID (e.g., "loop-v2-20260122-abc123")
|
||||
*/
|
||||
function readLoopState(loopId) {
|
||||
const stateFile = `.workflow/.loop/${loopId}.json`
|
||||
|
||||
if (!fs.existsSync(stateFile)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const state = JSON.parse(Read(stateFile))
|
||||
return state
|
||||
}
|
||||
```
|
||||
|
||||
### Create New Loop State (Direct Call)
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* Create new loop state (only for direct calls, API triggers have existing state)
|
||||
*/
|
||||
function createLoopState(loopId, taskDescription) {
|
||||
const stateFile = `.workflow/.loop/${loopId}.json`
|
||||
const now = getUtc8ISOString()
|
||||
|
||||
const state = {
|
||||
// API compatible fields
|
||||
loop_id: loopId,
|
||||
title: taskDescription.substring(0, 100),
|
||||
description: taskDescription,
|
||||
max_iterations: 10,
|
||||
status: 'running', // Direct call sets to running
|
||||
current_iteration: 0,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
|
||||
// Skill extension fields
|
||||
skill_state: null // Initialized by INIT action
|
||||
}
|
||||
|
||||
// Ensure directories exist
|
||||
mkdir -p ".loop"
|
||||
mkdir -p ".workflow/.loop/${loopId}.progress"
|
||||
|
||||
Write(stateFile, JSON.stringify(state, null, 2))
|
||||
return state
|
||||
}
|
||||
```
|
||||
|
||||
## Main Execution Flow (Codex Subagent)
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* Run CCW Loop orchestrator using Codex subagent pattern
|
||||
* @param options.loopId - Existing Loop ID (API trigger)
|
||||
* @param options.task - Task description (direct call)
|
||||
* @param options.mode - 'interactive' | 'auto'
|
||||
*/
|
||||
async function runOrchestrator(options = {}) {
|
||||
const { loopId: existingLoopId, task, mode = 'interactive' } = options
|
||||
|
||||
console.log('=== CCW Loop Orchestrator (Codex) Started ===')
|
||||
|
||||
// 1. Determine loopId and initial state
|
||||
let loopId
|
||||
let state
|
||||
|
||||
if (existingLoopId) {
|
||||
// API trigger: use existing loopId
|
||||
loopId = existingLoopId
|
||||
state = readLoopState(loopId)
|
||||
|
||||
if (!state) {
|
||||
console.error(`Loop not found: ${loopId}`)
|
||||
return { status: 'error', message: 'Loop not found' }
|
||||
}
|
||||
|
||||
console.log(`Resuming loop: ${loopId}`)
|
||||
console.log(`Status: ${state.status}`)
|
||||
|
||||
} else if (task) {
|
||||
// Direct call: create new loopId
|
||||
const timestamp = getUtc8ISOString().replace(/[-:]/g, '').split('.')[0]
|
||||
const random = Math.random().toString(36).substring(2, 10)
|
||||
loopId = `loop-v2-${timestamp}-${random}`
|
||||
|
||||
console.log(`Creating new loop: ${loopId}`)
|
||||
console.log(`Task: ${task}`)
|
||||
|
||||
state = createLoopState(loopId, task)
|
||||
|
||||
} else {
|
||||
console.error('Either --loop-id or task description is required')
|
||||
return { status: 'error', message: 'Missing loopId or task' }
|
||||
}
|
||||
|
||||
const progressDir = `.workflow/.loop/${loopId}.progress`
|
||||
|
||||
// 2. Create executor agent (single agent for entire loop)
|
||||
const agent = spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/ccw-loop-executor.md (MUST read first)
|
||||
2. Read: .workflow/project-tech.json (if exists)
|
||||
3. Read: .workflow/project-guidelines.json (if exists)
|
||||
|
||||
---
|
||||
|
||||
## LOOP CONTEXT
|
||||
|
||||
- **Loop ID**: ${loopId}
|
||||
- **State File**: .workflow/.loop/${loopId}.json
|
||||
- **Progress Dir**: ${progressDir}
|
||||
- **Mode**: ${mode}
|
||||
|
||||
## CURRENT STATE
|
||||
|
||||
${JSON.stringify(state, null, 2)}
|
||||
|
||||
## TASK DESCRIPTION
|
||||
|
||||
${state.description || task}
|
||||
|
||||
## FIRST ACTION
|
||||
|
||||
${!state.skill_state ? 'Execute: INIT' : mode === 'auto' ? 'Auto-select next action' : 'Show MENU'}
|
||||
|
||||
Read the role definition first, then execute the appropriate action.
|
||||
`
|
||||
})
|
||||
|
||||
// 3. Main orchestration loop
|
||||
let iteration = state.current_iteration || 0
|
||||
const maxIterations = state.max_iterations || 10
|
||||
let continueLoop = true
|
||||
|
||||
while (continueLoop && iteration < maxIterations) {
|
||||
iteration++
|
||||
|
||||
// Wait for agent output
|
||||
const result = wait({ ids: [agent], timeout_ms: 600000 })
|
||||
|
||||
// Check for timeout
|
||||
if (result.timed_out) {
|
||||
console.log('Agent timeout, requesting convergence...')
|
||||
send_input({
|
||||
id: agent,
|
||||
message: `
|
||||
## TIMEOUT NOTIFICATION
|
||||
|
||||
Execution timeout reached. Please:
|
||||
1. Output current progress
|
||||
2. Save any pending state updates
|
||||
3. Return ACTION_RESULT with current status
|
||||
`
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
const output = result.status[agent].completed
|
||||
|
||||
// Parse action result
|
||||
const actionResult = parseActionResult(output)
|
||||
|
||||
console.log(`\n[Iteration ${iteration}] Action: ${actionResult.action}, Status: ${actionResult.status}`)
|
||||
|
||||
// Update iteration in state
|
||||
state = readLoopState(loopId)
|
||||
state.current_iteration = iteration
|
||||
state.updated_at = getUtc8ISOString()
|
||||
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||
|
||||
// Handle different outcomes
|
||||
switch (actionResult.next_action) {
|
||||
case 'COMPLETED':
|
||||
console.log('Loop completed successfully')
|
||||
continueLoop = false
|
||||
break
|
||||
|
||||
case 'PAUSED':
|
||||
console.log('Loop paused by API, exiting gracefully')
|
||||
continueLoop = false
|
||||
break
|
||||
|
||||
case 'STOPPED':
|
||||
console.log('Loop stopped by API')
|
||||
continueLoop = false
|
||||
break
|
||||
|
||||
case 'WAITING_INPUT':
|
||||
// Interactive mode: display menu, get user choice
|
||||
if (mode === 'interactive') {
|
||||
const userChoice = await displayMenuAndGetChoice(actionResult)
|
||||
|
||||
// Send user choice back to agent
|
||||
send_input({
|
||||
id: agent,
|
||||
message: `
|
||||
## USER INPUT RECEIVED
|
||||
|
||||
Action selected: ${userChoice.action}
|
||||
${userChoice.data ? `Additional data: ${JSON.stringify(userChoice.data)}` : ''}
|
||||
|
||||
## EXECUTE SELECTED ACTION
|
||||
|
||||
Read action instructions and execute: ${userChoice.action}
|
||||
Update state and progress files accordingly.
|
||||
Output ACTION_RESULT when complete.
|
||||
`
|
||||
})
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
// Continue with next action
|
||||
if (actionResult.next_action && actionResult.next_action !== 'NONE') {
|
||||
send_input({
|
||||
id: agent,
|
||||
message: `
|
||||
## CONTINUE EXECUTION
|
||||
|
||||
Previous action completed: ${actionResult.action}
|
||||
Result: ${actionResult.status}
|
||||
${actionResult.message ? `Message: ${actionResult.message}` : ''}
|
||||
|
||||
## EXECUTE NEXT ACTION
|
||||
|
||||
Continue with: ${actionResult.next_action}
|
||||
Read action instructions and execute.
|
||||
Output ACTION_RESULT when complete.
|
||||
`
|
||||
})
|
||||
} else {
|
||||
// No next action specified, check if should continue
|
||||
if (actionResult.status === 'failed') {
|
||||
console.log(`Action failed: ${actionResult.message}`)
|
||||
}
|
||||
continueLoop = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Check iteration limit
|
||||
if (iteration >= maxIterations) {
|
||||
console.log(`\nReached maximum iterations (${maxIterations})`)
|
||||
console.log('Consider breaking down the task or taking a break.')
|
||||
}
|
||||
|
||||
// 5. Cleanup
|
||||
close_agent({ id: agent })
|
||||
|
||||
console.log('\n=== CCW Loop Orchestrator (Codex) Finished ===')
|
||||
|
||||
// Return final state
|
||||
const finalState = readLoopState(loopId)
|
||||
return {
|
||||
status: finalState.status,
|
||||
loop_id: loopId,
|
||||
iterations: iteration,
|
||||
final_state: finalState
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse action result from agent output
|
||||
*/
|
||||
function parseActionResult(output) {
|
||||
const result = {
|
||||
action: 'unknown',
|
||||
status: 'unknown',
|
||||
message: '',
|
||||
state_updates: {},
|
||||
next_action: 'NONE'
|
||||
}
|
||||
|
||||
// Parse ACTION_RESULT block
|
||||
const actionMatch = output.match(/ACTION_RESULT:\s*([\s\S]*?)(?:FILES_UPDATED:|NEXT_ACTION_NEEDED:|$)/)
|
||||
if (actionMatch) {
|
||||
const lines = actionMatch[1].split('\n')
|
||||
for (const line of lines) {
|
||||
const match = line.match(/^-\s*(\w+):\s*(.+)$/)
|
||||
if (match) {
|
||||
const [, key, value] = match
|
||||
if (key === 'state_updates') {
|
||||
try {
|
||||
result.state_updates = JSON.parse(value)
|
||||
} catch (e) {
|
||||
// Try parsing multi-line JSON
|
||||
}
|
||||
} else {
|
||||
result[key] = value.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse NEXT_ACTION_NEEDED
|
||||
const nextMatch = output.match(/NEXT_ACTION_NEEDED:\s*(\S+)/)
|
||||
if (nextMatch) {
|
||||
result.next_action = nextMatch[1]
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Display menu and get user choice (interactive mode)
|
||||
*/
|
||||
async function displayMenuAndGetChoice(actionResult) {
|
||||
// Parse MENU_OPTIONS from output
|
||||
const menuMatch = actionResult.message.match(/MENU_OPTIONS:\s*([\s\S]*?)(?:WAITING_INPUT:|$)/)
|
||||
|
||||
if (menuMatch) {
|
||||
console.log('\n' + menuMatch[1])
|
||||
}
|
||||
|
||||
// Use AskUserQuestion to get choice
|
||||
const response = await AskUserQuestion({
|
||||
questions: [{
|
||||
question: "Select next action:",
|
||||
header: "Action",
|
||||
multiSelect: false,
|
||||
options: [
|
||||
{ label: "develop", description: "Continue development" },
|
||||
{ label: "debug", description: "Start debugging" },
|
||||
{ label: "validate", description: "Run validation" },
|
||||
{ label: "complete", description: "Complete loop" },
|
||||
{ label: "exit", description: "Exit and save" }
|
||||
]
|
||||
}]
|
||||
})
|
||||
|
||||
return { action: response["Action"] }
|
||||
}
|
||||
```
|
||||
|
||||
## Action Catalog
|
||||
|
||||
| Action | Purpose | Preconditions | Effects |
|
||||
|--------|---------|---------------|---------|
|
||||
| INIT | Initialize session | status=running, skill_state=null | skill_state initialized |
|
||||
| MENU | Display menu | skill_state != null, mode=interactive | Wait for user input |
|
||||
| DEVELOP | Execute dev task | pending tasks > 0 | Update progress.md |
|
||||
| DEBUG | Hypothesis debug | needs debugging | Update understanding.md |
|
||||
| VALIDATE | Run tests | needs validation | Update validation.md |
|
||||
| COMPLETE | Finish loop | all done | status=completed |
|
||||
|
||||
## Termination Conditions
|
||||
|
||||
1. **API Paused**: `state.status === 'paused'` (Skill exits, wait for resume)
|
||||
2. **API Stopped**: `state.status === 'failed'` (Skill terminates)
|
||||
3. **Task Complete**: `NEXT_ACTION_NEEDED === 'COMPLETED'`
|
||||
4. **Iteration Limit**: `current_iteration >= max_iterations`
|
||||
5. **User Exit**: User selects 'exit' in interactive mode
|
||||
|
||||
## Error Recovery
|
||||
|
||||
| Error Type | Recovery Strategy |
|
||||
|------------|-------------------|
|
||||
| Agent timeout | send_input requesting convergence |
|
||||
| Action failed | Log error, continue or prompt user |
|
||||
| State corrupted | Rebuild from progress files |
|
||||
| Agent closed unexpectedly | Re-spawn with previous output in message |
|
||||
|
||||
## Codex Best Practices Applied
|
||||
|
||||
1. **Single Agent Pattern**: One agent handles entire loop lifecycle
|
||||
2. **Deep Interaction via send_input**: Multi-phase without context loss
|
||||
3. **Delayed close_agent**: Only after confirming no more interaction
|
||||
4. **Explicit wait()**: Always get results before proceeding
|
||||
5. **Role Path Passing**: Agent reads role file, no content embedding
|
||||
388
.codex/skills/ccw-loop/phases/state-schema.md
Normal file
388
.codex/skills/ccw-loop/phases/state-schema.md
Normal file
@@ -0,0 +1,388 @@
|
||||
# State Schema (Codex Version)
|
||||
|
||||
CCW Loop state structure definition for Codex subagent pattern.
|
||||
|
||||
## State File
|
||||
|
||||
**Location**: `.workflow/.loop/{loopId}.json` (unified location, API + Skill shared)
|
||||
|
||||
## Structure Definition
|
||||
|
||||
### Unified Loop State Interface
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Unified Loop State - API and Skill shared state structure
|
||||
* API (loop-v2-routes.ts) owns state control
|
||||
* Skill (ccw-loop) reads and updates this state via subagent
|
||||
*/
|
||||
interface LoopState {
|
||||
// =====================================================
|
||||
// API FIELDS (from loop-v2-routes.ts)
|
||||
// These fields are managed by API, Skill read-only
|
||||
// =====================================================
|
||||
|
||||
loop_id: string // Loop ID, e.g., "loop-v2-20260122-abc123"
|
||||
title: string // Loop title
|
||||
description: string // Loop description
|
||||
max_iterations: number // Maximum iteration count
|
||||
status: 'created' | 'running' | 'paused' | 'completed' | 'failed' | 'user_exit'
|
||||
current_iteration: number // Current iteration count
|
||||
created_at: string // Creation time (ISO8601)
|
||||
updated_at: string // Last update time (ISO8601)
|
||||
completed_at?: string // Completion time (ISO8601)
|
||||
failure_reason?: string // Failure reason
|
||||
|
||||
// =====================================================
|
||||
// SKILL EXTENSION FIELDS
|
||||
// These fields are managed by Skill executor agent
|
||||
// =====================================================
|
||||
|
||||
skill_state?: {
|
||||
// Current execution action
|
||||
current_action: 'init' | 'develop' | 'debug' | 'validate' | 'complete' | null
|
||||
last_action: string | null
|
||||
completed_actions: string[]
|
||||
mode: 'interactive' | 'auto'
|
||||
|
||||
// === Development Phase ===
|
||||
develop: {
|
||||
total: number
|
||||
completed: number
|
||||
current_task?: string
|
||||
tasks: DevelopTask[]
|
||||
last_progress_at: string | null
|
||||
}
|
||||
|
||||
// === Debug Phase ===
|
||||
debug: {
|
||||
active_bug?: string
|
||||
hypotheses_count: number
|
||||
hypotheses: Hypothesis[]
|
||||
confirmed_hypothesis: string | null
|
||||
iteration: number
|
||||
last_analysis_at: string | null
|
||||
}
|
||||
|
||||
// === Validation Phase ===
|
||||
validate: {
|
||||
pass_rate: number // Test pass rate (0-100)
|
||||
coverage: number // Coverage (0-100)
|
||||
test_results: TestResult[]
|
||||
passed: boolean
|
||||
failed_tests: string[]
|
||||
last_run_at: string | null
|
||||
}
|
||||
|
||||
// === Error Tracking ===
|
||||
errors: Array<{
|
||||
action: string
|
||||
message: string
|
||||
timestamp: string
|
||||
}>
|
||||
|
||||
// === Summary (after completion) ===
|
||||
summary?: {
|
||||
duration: number
|
||||
iterations: number
|
||||
develop: object
|
||||
debug: object
|
||||
validate: object
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface DevelopTask {
|
||||
id: string
|
||||
description: string
|
||||
tool: 'gemini' | 'qwen' | 'codex' | 'bash'
|
||||
mode: 'analysis' | 'write'
|
||||
status: 'pending' | 'in_progress' | 'completed' | 'failed'
|
||||
files_changed: string[]
|
||||
created_at: string
|
||||
completed_at: string | null
|
||||
}
|
||||
|
||||
interface Hypothesis {
|
||||
id: string // H1, H2, ...
|
||||
description: string
|
||||
testable_condition: string
|
||||
logging_point: string
|
||||
evidence_criteria: {
|
||||
confirm: string
|
||||
reject: string
|
||||
}
|
||||
likelihood: number // 1 = most likely
|
||||
status: 'pending' | 'confirmed' | 'rejected' | 'inconclusive'
|
||||
evidence: Record<string, any> | null
|
||||
verdict_reason: string | null
|
||||
}
|
||||
|
||||
interface TestResult {
|
||||
test_name: string
|
||||
suite: string
|
||||
status: 'passed' | 'failed' | 'skipped'
|
||||
duration_ms: number
|
||||
error_message: string | null
|
||||
stack_trace: string | null
|
||||
}
|
||||
```
|
||||
|
||||
## Initial State
|
||||
|
||||
### Created by API (Dashboard Trigger)
|
||||
|
||||
```json
|
||||
{
|
||||
"loop_id": "loop-v2-20260122-abc123",
|
||||
"title": "Implement user authentication",
|
||||
"description": "Add login/logout functionality",
|
||||
"max_iterations": 10,
|
||||
"status": "created",
|
||||
"current_iteration": 0,
|
||||
"created_at": "2026-01-22T10:00:00+08:00",
|
||||
"updated_at": "2026-01-22T10:00:00+08:00"
|
||||
}
|
||||
```
|
||||
|
||||
### After Skill Initialization (INIT action)
|
||||
|
||||
```json
|
||||
{
|
||||
"loop_id": "loop-v2-20260122-abc123",
|
||||
"title": "Implement user authentication",
|
||||
"description": "Add login/logout functionality",
|
||||
"max_iterations": 10,
|
||||
"status": "running",
|
||||
"current_iteration": 0,
|
||||
"created_at": "2026-01-22T10:00:00+08:00",
|
||||
"updated_at": "2026-01-22T10:00:05+08:00",
|
||||
|
||||
"skill_state": {
|
||||
"current_action": "init",
|
||||
"last_action": null,
|
||||
"completed_actions": [],
|
||||
"mode": "auto",
|
||||
|
||||
"develop": {
|
||||
"total": 3,
|
||||
"completed": 0,
|
||||
"current_task": null,
|
||||
"tasks": [
|
||||
{ "id": "task-001", "description": "Create auth component", "status": "pending" }
|
||||
],
|
||||
"last_progress_at": null
|
||||
},
|
||||
|
||||
"debug": {
|
||||
"active_bug": null,
|
||||
"hypotheses_count": 0,
|
||||
"hypotheses": [],
|
||||
"confirmed_hypothesis": null,
|
||||
"iteration": 0,
|
||||
"last_analysis_at": null
|
||||
},
|
||||
|
||||
"validate": {
|
||||
"pass_rate": 0,
|
||||
"coverage": 0,
|
||||
"test_results": [],
|
||||
"passed": false,
|
||||
"failed_tests": [],
|
||||
"last_run_at": null
|
||||
},
|
||||
|
||||
"errors": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Control Signal Checking (Codex Pattern)
|
||||
|
||||
Agent checks control signals at start of every action:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* Check API control signals
|
||||
* MUST be called at start of every action
|
||||
* @returns { continue: boolean, action: 'pause_exit' | 'stop_exit' | 'continue' }
|
||||
*/
|
||||
function checkControlSignals(loopId) {
|
||||
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||
|
||||
switch (state.status) {
|
||||
case 'paused':
|
||||
// API paused the loop, Skill should exit and wait for resume
|
||||
return { continue: false, action: 'pause_exit' }
|
||||
|
||||
case 'failed':
|
||||
// API stopped the loop (user manual stop)
|
||||
return { continue: false, action: 'stop_exit' }
|
||||
|
||||
case 'running':
|
||||
// Normal continue
|
||||
return { continue: true, action: 'continue' }
|
||||
|
||||
default:
|
||||
// Abnormal status
|
||||
return { continue: false, action: 'stop_exit' }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## State Transitions
|
||||
|
||||
### 1. Initialization (INIT action)
|
||||
|
||||
```javascript
|
||||
{
|
||||
status: 'created' -> 'running', // Or keep 'running' if API already set
|
||||
updated_at: timestamp,
|
||||
|
||||
skill_state: {
|
||||
current_action: 'init',
|
||||
mode: 'auto',
|
||||
develop: {
|
||||
tasks: [...parsed_tasks],
|
||||
total: N,
|
||||
completed: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Development (DEVELOP action)
|
||||
|
||||
```javascript
|
||||
{
|
||||
updated_at: timestamp,
|
||||
current_iteration: state.current_iteration + 1,
|
||||
|
||||
skill_state: {
|
||||
current_action: 'develop',
|
||||
last_action: 'DEVELOP',
|
||||
completed_actions: [..., 'DEVELOP'],
|
||||
develop: {
|
||||
current_task: 'task-xxx',
|
||||
completed: N+1,
|
||||
last_progress_at: timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Debugging (DEBUG action)
|
||||
|
||||
```javascript
|
||||
{
|
||||
updated_at: timestamp,
|
||||
current_iteration: state.current_iteration + 1,
|
||||
|
||||
skill_state: {
|
||||
current_action: 'debug',
|
||||
last_action: 'DEBUG',
|
||||
debug: {
|
||||
active_bug: '...',
|
||||
hypotheses_count: N,
|
||||
hypotheses: [...new_hypotheses],
|
||||
iteration: N+1,
|
||||
last_analysis_at: timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Validation (VALIDATE action)
|
||||
|
||||
```javascript
|
||||
{
|
||||
updated_at: timestamp,
|
||||
current_iteration: state.current_iteration + 1,
|
||||
|
||||
skill_state: {
|
||||
current_action: 'validate',
|
||||
last_action: 'VALIDATE',
|
||||
validate: {
|
||||
test_results: [...results],
|
||||
pass_rate: 95.5,
|
||||
coverage: 85.0,
|
||||
passed: true | false,
|
||||
failed_tests: ['test1', 'test2'],
|
||||
last_run_at: timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Completion (COMPLETE action)
|
||||
|
||||
```javascript
|
||||
{
|
||||
status: 'running' -> 'completed',
|
||||
completed_at: timestamp,
|
||||
updated_at: timestamp,
|
||||
|
||||
skill_state: {
|
||||
current_action: 'complete',
|
||||
last_action: 'COMPLETE',
|
||||
summary: { ... }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## File Sync
|
||||
|
||||
### Unified Location
|
||||
|
||||
State-to-file mapping:
|
||||
|
||||
| State Field | Sync File | Sync Timing |
|
||||
|-------------|-----------|-------------|
|
||||
| Entire LoopState | `.workflow/.loop/{loopId}.json` | Every state change (master) |
|
||||
| `skill_state.develop` | `.workflow/.loop/{loopId}.progress/develop.md` | After each dev operation |
|
||||
| `skill_state.debug` | `.workflow/.loop/{loopId}.progress/debug.md` | After each debug operation |
|
||||
| `skill_state.validate` | `.workflow/.loop/{loopId}.progress/validate.md` | After each validation |
|
||||
| Code changes log | `.workflow/.loop/{loopId}.progress/changes.log` | Each file modification (NDJSON) |
|
||||
| Debug log | `.workflow/.loop/{loopId}.progress/debug.log` | Each debug log (NDJSON) |
|
||||
|
||||
### File Structure
|
||||
|
||||
```
|
||||
.workflow/.loop/
|
||||
+-- loop-v2-20260122-abc123.json # Master state file (API + Skill)
|
||||
+-- loop-v2-20260122-abc123.tasks.jsonl # Task list (API managed)
|
||||
+-- loop-v2-20260122-abc123.progress/ # Skill progress files
|
||||
+-- develop.md # Development progress
|
||||
+-- debug.md # Debug understanding
|
||||
+-- validate.md # Validation report
|
||||
+-- changes.log # Code changes (NDJSON)
|
||||
+-- debug.log # Debug log (NDJSON)
|
||||
+-- summary.md # Completion summary
|
||||
```
|
||||
|
||||
## State Recovery
|
||||
|
||||
If master state file corrupted, rebuild skill_state from progress files:
|
||||
|
||||
```javascript
|
||||
function rebuildSkillStateFromProgress(loopId) {
|
||||
const progressDir = `.workflow/.loop/${loopId}.progress`
|
||||
|
||||
// Parse progress files to rebuild state
|
||||
const skill_state = {
|
||||
develop: parseProgressFile(`${progressDir}/develop.md`),
|
||||
debug: parseProgressFile(`${progressDir}/debug.md`),
|
||||
validate: parseProgressFile(`${progressDir}/validate.md`)
|
||||
}
|
||||
|
||||
return skill_state
|
||||
}
|
||||
```
|
||||
|
||||
## Codex Pattern Notes
|
||||
|
||||
1. **Agent reads state**: Agent reads `.workflow/.loop/{loopId}.json` at action start
|
||||
2. **Agent writes state**: Agent updates state after action completion
|
||||
3. **Orchestrator tracks iterations**: Main loop tracks `current_iteration`
|
||||
4. **Single agent context**: All state updates in same agent conversation via send_input
|
||||
5. **No context serialization loss**: State transitions happen in-memory within agent
|
||||
182
.codex/skills/ccw-loop/specs/action-catalog.md
Normal file
182
.codex/skills/ccw-loop/specs/action-catalog.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# Action Catalog (Codex Version)
|
||||
|
||||
CCW Loop available actions and their specifications.
|
||||
|
||||
## Available Actions
|
||||
|
||||
| Action | Purpose | Preconditions | Effects | Output |
|
||||
|--------|---------|---------------|---------|--------|
|
||||
| INIT | Initialize session | status=running, skill_state=null | skill_state initialized | progress/*.md created |
|
||||
| MENU | Display action menu | skill_state!=null, mode=interactive | Wait for user input | WAITING_INPUT |
|
||||
| DEVELOP | Execute dev task | pending tasks > 0 | Update progress.md | develop.md updated |
|
||||
| DEBUG | Hypothesis debug | needs debugging | Update understanding.md | debug.md updated |
|
||||
| VALIDATE | Run tests | needs validation | Update validation.md | validate.md updated |
|
||||
| COMPLETE | Finish loop | all done | status=completed | summary.md created |
|
||||
|
||||
## Action Flow (Codex Pattern)
|
||||
|
||||
```
|
||||
spawn_agent (ccw-loop-executor)
|
||||
|
|
||||
v
|
||||
+-------+
|
||||
| INIT | (if skill_state is null)
|
||||
+-------+
|
||||
|
|
||||
v
|
||||
+-------+ send_input
|
||||
| MENU | <------------- (user selection in interactive mode)
|
||||
+-------+
|
||||
|
|
||||
+---+---+---+---+
|
||||
| | | | |
|
||||
v v v v v
|
||||
DEV DBG VAL CMP EXIT
|
||||
|
|
||||
v
|
||||
wait() -> get result
|
||||
|
|
||||
v
|
||||
[Loop continues via send_input]
|
||||
|
|
||||
v
|
||||
close_agent()
|
||||
```
|
||||
|
||||
## Action Execution Pattern
|
||||
|
||||
### Single Agent Deep Interaction
|
||||
|
||||
All actions executed within same agent via `send_input`:
|
||||
|
||||
```javascript
|
||||
// Initial spawn
|
||||
const agent = spawn_agent({ message: role + initial_task })
|
||||
|
||||
// Execute INIT
|
||||
const initResult = wait({ ids: [agent] })
|
||||
|
||||
// Continue with DEVELOP via send_input
|
||||
send_input({ id: agent, message: 'Execute DEVELOP' })
|
||||
const devResult = wait({ ids: [agent] })
|
||||
|
||||
// Continue with VALIDATE via send_input
|
||||
send_input({ id: agent, message: 'Execute VALIDATE' })
|
||||
const valResult = wait({ ids: [agent] })
|
||||
|
||||
// Only close when done
|
||||
close_agent({ id: agent })
|
||||
```
|
||||
|
||||
### Action Output Format (Standardized)
|
||||
|
||||
Every action MUST output:
|
||||
|
||||
```
|
||||
ACTION_RESULT:
|
||||
- action: {ACTION_NAME}
|
||||
- status: success | failed | needs_input
|
||||
- message: {user-facing message}
|
||||
- state_updates: { ... }
|
||||
|
||||
FILES_UPDATED:
|
||||
- {file_path}: {description}
|
||||
|
||||
NEXT_ACTION_NEEDED: {NEXT_ACTION} | WAITING_INPUT | COMPLETED | PAUSED
|
||||
```
|
||||
|
||||
## Action Selection Logic
|
||||
|
||||
### Auto Mode
|
||||
|
||||
```javascript
|
||||
function selectNextAction(state) {
|
||||
const skillState = state.skill_state
|
||||
|
||||
// 1. Terminal conditions
|
||||
if (state.status === 'completed') return null
|
||||
if (state.status === 'failed') return null
|
||||
if (state.current_iteration >= state.max_iterations) return 'COMPLETE'
|
||||
|
||||
// 2. Initialization check
|
||||
if (!skillState) return 'INIT'
|
||||
|
||||
// 3. Auto selection based on state
|
||||
const hasPendingDevelop = skillState.develop.tasks.some(t => t.status === 'pending')
|
||||
|
||||
if (hasPendingDevelop) {
|
||||
return 'DEVELOP'
|
||||
}
|
||||
|
||||
if (skillState.last_action === 'DEVELOP') {
|
||||
const needsDebug = skillState.develop.completed < skillState.develop.total
|
||||
if (needsDebug) return 'DEBUG'
|
||||
}
|
||||
|
||||
if (skillState.last_action === 'DEBUG' || skillState.debug.confirmed_hypothesis) {
|
||||
return 'VALIDATE'
|
||||
}
|
||||
|
||||
if (skillState.last_action === 'VALIDATE') {
|
||||
if (!skillState.validate.passed) return 'DEVELOP'
|
||||
}
|
||||
|
||||
if (skillState.validate.passed && !hasPendingDevelop) {
|
||||
return 'COMPLETE'
|
||||
}
|
||||
|
||||
return 'DEVELOP'
|
||||
}
|
||||
```
|
||||
|
||||
### Interactive Mode
|
||||
|
||||
Returns `MENU` action, which displays options and waits for user input.
|
||||
|
||||
## Action Dependencies
|
||||
|
||||
| Action | Depends On | Leads To |
|
||||
|--------|------------|----------|
|
||||
| INIT | - | MENU or DEVELOP |
|
||||
| MENU | INIT | User selection |
|
||||
| DEVELOP | INIT | DEVELOP, DEBUG, VALIDATE |
|
||||
| DEBUG | INIT | DEVELOP, VALIDATE |
|
||||
| VALIDATE | DEVELOP or DEBUG | COMPLETE, DEBUG, DEVELOP |
|
||||
| COMPLETE | - | Terminal |
|
||||
|
||||
## Action Sequences
|
||||
|
||||
### Happy Path (Auto Mode)
|
||||
|
||||
```
|
||||
INIT -> DEVELOP -> DEVELOP -> DEVELOP -> VALIDATE (pass) -> COMPLETE
|
||||
```
|
||||
|
||||
### Debug Iteration Path
|
||||
|
||||
```
|
||||
INIT -> DEVELOP -> VALIDATE (fail) -> DEBUG -> DEBUG -> VALIDATE (pass) -> COMPLETE
|
||||
```
|
||||
|
||||
### Interactive Path
|
||||
|
||||
```
|
||||
INIT -> MENU -> (user: develop) -> DEVELOP -> MENU -> (user: validate) -> VALIDATE -> MENU -> (user: complete) -> COMPLETE
|
||||
```
|
||||
|
||||
## Error Recovery
|
||||
|
||||
| Error | Recovery |
|
||||
|-------|----------|
|
||||
| Action timeout | send_input requesting convergence |
|
||||
| Action failed | Log error, continue or retry |
|
||||
| Agent closed unexpectedly | Re-spawn with previous output |
|
||||
| State corrupted | Rebuild from progress files |
|
||||
|
||||
## Codex Best Practices
|
||||
|
||||
1. **Single agent for all actions**: No need to spawn new agent for each action
|
||||
2. **Deep interaction via send_input**: Continue conversation in same context
|
||||
3. **Delayed close_agent**: Only close after all actions complete
|
||||
4. **Structured output**: Always use ACTION_RESULT format for parsing
|
||||
5. **Control signal checking**: Check state.status before every action
|
||||
@@ -1,385 +0,0 @@
|
||||
# Parallel Dev Cycle Skill
|
||||
|
||||
Multi-agent parallel development cycle using Codex subagent pattern with continuous iteration support.
|
||||
|
||||
## Overview
|
||||
|
||||
This skill implements a **single-file-per-agent** development workflow:
|
||||
|
||||
- **RA**: `requirements.md` (all requirements + edge cases + history)
|
||||
- **EP**: `exploration.md`, `architecture.md`, `plan.json` (codebase exploration + architecture + structured tasks)
|
||||
- **CD**: `implementation.md` (progress + files + decisions + testing)
|
||||
- **VAS**: `summary.md` (validation + test results + recommendations)
|
||||
|
||||
Each file is **completely rewritten** on each iteration, with old versions auto-archived to `history/`.
|
||||
|
||||
## Installation
|
||||
|
||||
Files are in `.codex/skills/parallel-dev-cycle/`:
|
||||
|
||||
```
|
||||
.codex/skills/parallel-dev-cycle/
|
||||
├── SKILL.md # Main skill definition
|
||||
├── README.md # This file
|
||||
├── phases/
|
||||
│ ├── orchestrator.md # Multi-agent coordination
|
||||
│ ├── state-schema.md # Unified state structure
|
||||
│ └── agents/
|
||||
│ ├── requirements-analyst.md # RA role
|
||||
│ ├── exploration-planner.md # EP role
|
||||
│ ├── code-developer.md # CD role
|
||||
│ └── validation-archivist.md # VAS role
|
||||
└── specs/
|
||||
├── coordination-protocol.md # Agent communication
|
||||
└── versioning-strategy.md # Version management
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Launch New Cycle
|
||||
|
||||
```bash
|
||||
/parallel-dev-cycle TASK="Implement OAuth authentication"
|
||||
```
|
||||
|
||||
Creates:
|
||||
```
|
||||
.workflow/.cycle/cycle-v1-20260122-abc123.progress/
|
||||
├── ra/
|
||||
│ ├── requirements.md (v1.0.0)
|
||||
│ └── changes.log (NDJSON)
|
||||
├── ep/
|
||||
│ ├── exploration.md (v1.0.0)
|
||||
│ ├── architecture.md (v1.0.0)
|
||||
│ ├── plan.json (v1.0.0)
|
||||
│ └── changes.log (NDJSON)
|
||||
├── cd/
|
||||
│ ├── implementation.md (v1.0.0)
|
||||
│ └── changes.log (NDJSON)
|
||||
└── vas/
|
||||
├── summary.md (v1.0.0)
|
||||
└── changes.log (NDJSON)
|
||||
```
|
||||
|
||||
### Continue With Extension (XX-1 Pattern)
|
||||
|
||||
User adds requirement: "Also support Google OAuth"
|
||||
|
||||
```bash
|
||||
/parallel-dev-cycle --cycle-id=cycle-v1-20260122-abc123 --extend="Add Google OAuth"
|
||||
```
|
||||
|
||||
Automatically:
|
||||
1. Archives old `requirements.md (v1.0.0)` → `history/requirements-v1.0.0.md`
|
||||
2. Rewrites `requirements.md (v1.1.0)` - complete file replacement
|
||||
3. Appends change to `changes.log` (NDJSON audit trail)
|
||||
|
||||
### Next Iteration (XX-2)
|
||||
|
||||
```bash
|
||||
/parallel-dev-cycle --cycle-id=cycle-v1-20260122-abc123 --extend="Add GitHub provider"
|
||||
```
|
||||
|
||||
All files update to v1.2.0, previous versions archived.
|
||||
|
||||
## Execution Flow
|
||||
|
||||
### Phase 1: Parallel Agent Execution
|
||||
|
||||
```
|
||||
Time RA EP CD VAS
|
||||
──── ── ── ── ──
|
||||
0ms [spawned] [spawned] [spawned] [spawned]
|
||||
↓ ↓ ↓ ↓
|
||||
Analyzing Exploring Reading plan Waiting
|
||||
task codebase from EP...
|
||||
↓
|
||||
5min Outputs req. Outputs plan Requirements
|
||||
v1.0.0 ✓ v1.0.0 ✓ unclear - BLOCKED
|
||||
|
||||
10min Clarifies req Updates plan ✓ Ready
|
||||
v1.0.1 ✓ v1.0.1 ✓ Implementing...
|
||||
↓
|
||||
15min ✓ Complete ✓ Complete ✓ Code done [waiting for CD]
|
||||
|
||||
20min [starts tests]
|
||||
↓
|
||||
25min Outputs summary
|
||||
v1.0.0 ✓
|
||||
```
|
||||
|
||||
### Phase 2: Version Transition
|
||||
|
||||
When iteration completes, next extends to v1.1.0:
|
||||
|
||||
```
|
||||
Current State (v1.0.0)
|
||||
├── requirements.md (v1.0.0)
|
||||
├── plan.json (v1.0.0)
|
||||
├── implementation.md (v1.0.0)
|
||||
└── summary.md (v1.0.0)
|
||||
|
||||
User: "Add GitHub provider"
|
||||
↓
|
||||
Archive Old Write New
|
||||
├── history/requirements-v1.0.0.md → requirements.md (v1.1.0) - REWRITTEN
|
||||
├── history/plan-v1.0.0.json → plan.json (v1.1.0) - REWRITTEN
|
||||
├── history/impl-v1.0.0.md → implementation.md (v1.1.0) - REWRITTEN
|
||||
└── history/summary-v1.0.0.md → summary.md (v1.1.0) - REWRITTEN
|
||||
↓
|
||||
Append to changes.log (NDJSON)
|
||||
```
|
||||
|
||||
## Session Files
|
||||
|
||||
```
|
||||
.workflow/.cycle/{cycleId}.progress/
|
||||
|
||||
ra/ - Requirements Analyst
|
||||
├── requirements.md # v1.2.0 (current, complete rewrite)
|
||||
├── changes.log # NDJSON audit trail
|
||||
└── history/
|
||||
├── requirements-v1.0.0.md
|
||||
└── requirements-v1.1.0.md
|
||||
|
||||
ep/ - Exploration & Planning
|
||||
├── exploration.md # v1.2.0 (codebase exploration)
|
||||
├── architecture.md # v1.2.0 (architecture design)
|
||||
├── plan.json # v1.2.0 (structured task list, current)
|
||||
├── changes.log # NDJSON audit trail
|
||||
└── history/
|
||||
├── plan-v1.0.0.json
|
||||
└── plan-v1.1.0.json
|
||||
|
||||
cd/ - Code Developer
|
||||
├── implementation.md # v1.2.0 (current)
|
||||
├── changes.log # NDJSON audit trail
|
||||
└── history/
|
||||
├── implementation-v1.0.0.md
|
||||
└── implementation-v1.1.0.md
|
||||
|
||||
vas/ - Validation & Archival
|
||||
├── summary.md # v1.2.0 (current)
|
||||
├── changes.log # NDJSON audit trail
|
||||
└── history/
|
||||
├── summary-v1.0.0.md
|
||||
└── summary-v1.1.0.md
|
||||
```
|
||||
|
||||
## Versioning Strategy
|
||||
|
||||
### Semantic Versioning
|
||||
|
||||
- **1.0.0**: Initial cycle
|
||||
- **1.1.0**: User extends with new requirement
|
||||
- **1.2.0**: Another iteration with more requirements
|
||||
|
||||
### What Gets Versioned
|
||||
|
||||
✅ **Main Document File**
|
||||
- Completely rewritten each iteration
|
||||
- Auto-archived to `history/`
|
||||
- No inline version history (stays clean)
|
||||
|
||||
✅ **Changes.log (NDJSON)**
|
||||
- Append-only (never deleted)
|
||||
- Complete audit trail of all changes
|
||||
- Used to trace requirement origins
|
||||
|
||||
✅ **Historical Snapshots**
|
||||
- Auto-created in `history/` directory
|
||||
- Keep last N versions (default: 5)
|
||||
- For reference when needed
|
||||
|
||||
### Key Principle
|
||||
|
||||
> **主文档简洁清晰** ← Agent 只关注当前版本
|
||||
>
|
||||
> **完整历史记录** ← Changes.log 保留每个变更
|
||||
>
|
||||
> **版本快照归档** ← History/ 备份旧版本
|
||||
|
||||
## File Maintenance
|
||||
|
||||
### Each Agent
|
||||
|
||||
| Agent | File | Contains | Size |
|
||||
|-------|------|----------|------|
|
||||
| **RA** | requirements.md | All FR, NFR, edge cases, history summary | ~2-5KB |
|
||||
| **EP** | exploration.md + architecture.md + plan.json | Codebase exploration, architecture design, structured task list | ~5-10KB total |
|
||||
| **CD** | implementation.md | Completed tasks, files changed, decisions, tests | ~4-10KB |
|
||||
| **VAS** | summary.md | Test results, coverage, issues, recommendations | ~5-12KB |
|
||||
|
||||
### Changes.log (Shared)
|
||||
|
||||
NDJSON format - one line per change:
|
||||
|
||||
```jsonl
|
||||
{"timestamp":"2026-01-22T10:00:00+08:00","version":"1.0.0","agent":"ra","action":"create","change":"Initial requirements","iteration":1}
|
||||
{"timestamp":"2026-01-22T11:00:00+08:00","version":"1.1.0","agent":"ra","action":"update","change":"Added Google OAuth","iteration":2}
|
||||
{"timestamp":"2026-01-22T12:00:00+08:00","version":"1.2.0","agent":"ra","action":"update","change":"Added GitHub, MFA","iteration":3}
|
||||
```
|
||||
|
||||
## Accessing History
|
||||
|
||||
### Current Version
|
||||
|
||||
```bash
|
||||
# View latest requirements
|
||||
cat .workflow/.cycle/cycle-xxx.progress/ra/requirements.md
|
||||
|
||||
# Quick check - version is in header
|
||||
head -5 requirements.md # "# Requirements Specification - v1.2.0"
|
||||
```
|
||||
|
||||
### Version History
|
||||
|
||||
```bash
|
||||
# View previous version
|
||||
cat .workflow/.cycle/cycle-xxx.progress/ra/history/requirements-v1.1.0.md
|
||||
|
||||
# Audit trail - all changes
|
||||
cat .workflow/.cycle/cycle-xxx.progress/ra/changes.log | jq .
|
||||
|
||||
# Changes in specific iteration
|
||||
cat changes.log | jq 'select(.iteration==2)'
|
||||
|
||||
# Trace requirement history
|
||||
cat changes.log | jq 'select(.change | contains("OAuth"))'
|
||||
```
|
||||
|
||||
## Codex Pattern Implementation
|
||||
|
||||
### Multi-Agent Parallel
|
||||
|
||||
```javascript
|
||||
// Create 4 agents in parallel
|
||||
const agents = {
|
||||
ra: spawn_agent({ message: raRoleAndTask }),
|
||||
ep: spawn_agent({ message: epRoleAndTask }),
|
||||
cd: spawn_agent({ message: cdRoleAndTask }),
|
||||
vas: spawn_agent({ message: vasRoleAndTask })
|
||||
}
|
||||
|
||||
// Wait for all 4 in parallel
|
||||
const results = wait({ ids: [agents.ra, agents.ep, agents.cd, agents.vas] })
|
||||
```
|
||||
|
||||
### Role Path Passing
|
||||
|
||||
Each agent reads its own role definition:
|
||||
|
||||
```javascript
|
||||
spawn_agent({
|
||||
message: `
|
||||
## MANDATORY FIRST STEPS
|
||||
1. Read role: ~/.codex/agents/requirements-analyst.md
|
||||
2. Read: .workflow/project-tech.json
|
||||
3. Read: .workflow/project-guidelines.json
|
||||
|
||||
## TASK
|
||||
${taskDescription}
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
### Deep Interaction
|
||||
|
||||
Use `send_input` for iteration refinement:
|
||||
|
||||
```javascript
|
||||
// First output
|
||||
const initial = wait({ ids: [agent] })
|
||||
|
||||
// User feedback
|
||||
send_input({
|
||||
id: agent,
|
||||
message: `
|
||||
## Feedback
|
||||
|
||||
${feedback}
|
||||
|
||||
## Next Steps
|
||||
Update ${filename} based on feedback. Increment version.
|
||||
Output PHASE_RESULT when complete.
|
||||
`
|
||||
})
|
||||
|
||||
// Updated output
|
||||
const revised = wait({ ids: [agent] })
|
||||
|
||||
// Only close when done
|
||||
close_agent({ id: agent })
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Situation | Recovery |
|
||||
|-----------|----------|
|
||||
| Agent timeout | send_input requesting convergence or retry |
|
||||
| State corrupted | Rebuild from changes.log NDJSON |
|
||||
| Version mismatch | Agent checks version in state before reading |
|
||||
| Blocked dependency | Orchestrator sends updated file path |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Let agents rewrite** - Don't maintain incremental history in main doc
|
||||
2. **Trust changes.log** - NDJSON is the source of truth for history
|
||||
3. **Archive on version bump** - Automatic, no manual versioning needed
|
||||
4. **Keep files focused** - Each file should be readable in 5 minutes
|
||||
5. **Version header always present** - Makes version obvious at a glance
|
||||
|
||||
## Integration
|
||||
|
||||
This skill works standalone or integrated with:
|
||||
- Dashboard Loop Monitor (API triggers)
|
||||
- CCW workflow system
|
||||
- Custom orchestration
|
||||
|
||||
### API Trigger
|
||||
|
||||
```bash
|
||||
POST /api/cycles/start
|
||||
{
|
||||
"task": "Implement OAuth",
|
||||
"mode": "auto"
|
||||
}
|
||||
→ Returns cycle_id
|
||||
|
||||
GET /api/cycles/{cycle_id}/status
|
||||
→ Returns agents status and progress
|
||||
```
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```
|
||||
User Task
|
||||
↓
|
||||
Orchestrator (main coordinator)
|
||||
├─→ spawn_agent(RA)
|
||||
├─→ spawn_agent(EP)
|
||||
├─→ spawn_agent(CD)
|
||||
└─→ spawn_agent(VAS)
|
||||
↓
|
||||
wait({ ids: [all 4] })
|
||||
↓
|
||||
All write to:
|
||||
- requirements.md (v1.x.0)
|
||||
- exploration.md, architecture.md, plan.json (v1.x.0)
|
||||
- implementation.md (v1.x.0)
|
||||
- summary.md (v1.x.0)
|
||||
- changes.log (NDJSON append)
|
||||
↓
|
||||
[Automatic archival]
|
||||
- history/requirements-v1.{x-1}.0.md
|
||||
- history/plan-v1.{x-1}.0.json
|
||||
- etc...
|
||||
↓
|
||||
Orchestrator: Next iteration?
|
||||
- Yes: send_input with feedback
|
||||
- No: close_agent, report summary
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -1,28 +1,18 @@
|
||||
---
|
||||
name: Parallel Dev Cycle
|
||||
description: Multi-agent parallel development cycle with requirement analysis, exploration planning, code development, and validation. Supports continuous iteration with markdown progress documentation.
|
||||
argument-hint: TASK="<task description>" | --cycle-id=<id> [--extend="<extension>"] [--auto] [--parallel=<count>]
|
||||
name: parallel-dev-cycle
|
||||
description: Multi-agent parallel development cycle with requirement analysis, exploration planning, code development, and validation. Supports continuous iteration with markdown progress documentation. Triggers on "parallel-dev-cycle".
|
||||
allowed-tools: Task, AskUserQuestion, TodoWrite, Read, Write, Edit, Bash, Glob, Grep
|
||||
---
|
||||
|
||||
# Parallel Dev Cycle - Multi-Agent Development Workflow
|
||||
# Parallel Dev Cycle
|
||||
|
||||
Multi-agent parallel development cycle using Codex subagent pattern with four specialized workers:
|
||||
1. **Requirements Analysis & Extension** (RA) - Requirement analysis and self-enhancement
|
||||
2. **Exploration & Planning** (EP) - Exploration and planning
|
||||
2. **Exploration & Planning** (EP) - Codebase exploration and implementation planning
|
||||
3. **Code Development** (CD) - Code development with debug strategy support
|
||||
4. **Validation & Archival Summary** (VAS) - Validation and archival summary
|
||||
|
||||
Each agent **maintains one main document** (e.g., requirements.md, plan.json, implementation.md) that is completely rewritten per iteration, plus auxiliary logs (changes.log, debug-log.ndjson) that are append-only. Supports versioning, automatic archival, and complete history tracking.
|
||||
|
||||
## Arguments
|
||||
|
||||
| Arg | Required | Description |
|
||||
|-----|----------|-------------|
|
||||
| TASK | One of TASK or --cycle-id | Task description (for new cycle, mutually exclusive with --cycle-id) |
|
||||
| --cycle-id | One of TASK or --cycle-id | Existing cycle ID to continue (from API or previous session) |
|
||||
| --extend | No | Extension description (only valid with --cycle-id) |
|
||||
| --auto | No | Auto-cycle mode (run all phases sequentially) |
|
||||
| --parallel | No | Number of parallel agents (default: 4, max: 4) |
|
||||
Each agent **maintains one main document** (e.g., requirements.md, plan.json, implementation.md) that is completely rewritten per iteration, plus auxiliary logs (changes.log, debug-log.ndjson) that are append-only.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
@@ -70,93 +60,273 @@ Each agent **maintains one main document** (e.g., requirements.md, plan.json, im
|
||||
6. **File References**: Use short file paths instead of content passing
|
||||
7. **Self-Enhancement**: RA agent proactively extends requirements based on context
|
||||
|
||||
## Arguments
|
||||
|
||||
| Arg | Required | Description |
|
||||
|-----|----------|-------------|
|
||||
| TASK | One of TASK or --cycle-id | Task description (for new cycle, mutually exclusive with --cycle-id) |
|
||||
| --cycle-id | One of TASK or --cycle-id | Existing cycle ID to continue (from API or previous session) |
|
||||
| --extend | No | Extension description (only valid with --cycle-id) |
|
||||
| --auto | No | Auto-cycle mode (run all phases sequentially without user confirmation) |
|
||||
| --parallel | No | Number of parallel agents (default: 4, max: 4) |
|
||||
|
||||
## Auto Mode
|
||||
|
||||
When `--auto`: Run all phases sequentially without user confirmation between iterations. Use recommended defaults for all decisions. Automatically continue iteration loop until tests pass or max iterations reached.
|
||||
|
||||
## Execution Flow
|
||||
|
||||
```
|
||||
Input Parsing:
|
||||
└─ Parse arguments (TASK | --cycle-id + --extend)
|
||||
└─ Convert to structured context (cycleId, state, progressDir)
|
||||
|
||||
Phase 1: Session Initialization
|
||||
└─ Ref: phases/01-session-init.md
|
||||
├─ Create new cycle OR resume existing cycle
|
||||
├─ Initialize state file and directory structure
|
||||
└─ Output: cycleId, state, progressDir
|
||||
|
||||
Phase 2: Agent Execution (Parallel)
|
||||
└─ Ref: phases/02-agent-execution.md
|
||||
├─ Tasks attached: Spawn RA → Spawn EP → Spawn CD → Spawn VAS → Wait all
|
||||
├─ Spawn RA, EP, CD, VAS agents in parallel
|
||||
├─ Wait for all agents with timeout handling
|
||||
└─ Output: agentOutputs (4 agent results)
|
||||
|
||||
Phase 3: Result Aggregation & Iteration
|
||||
└─ Ref: phases/03-result-aggregation.md
|
||||
├─ Parse PHASE_RESULT from each agent
|
||||
├─ Detect issues (test failures, blockers)
|
||||
├─ Decision: Issues found AND iteration < max?
|
||||
│ ├─ Yes → Send feedback via send_input, loop back to Phase 2
|
||||
│ └─ No → Proceed to Phase 4
|
||||
└─ Output: parsedResults, iteration status
|
||||
|
||||
Phase 4: Completion & Summary
|
||||
└─ Ref: phases/04-completion-summary.md
|
||||
├─ Generate unified summary report
|
||||
├─ Update final state
|
||||
├─ Close all agents
|
||||
└─ Output: final cycle report with continuation instructions
|
||||
```
|
||||
|
||||
**Phase Reference Documents** (read on-demand when phase executes):
|
||||
|
||||
| Phase | Document | Purpose |
|
||||
|-------|----------|---------|
|
||||
| 1 | [phases/01-session-init.md](phases/01-session-init.md) | Session creation/resume and state initialization |
|
||||
| 2 | [phases/02-agent-execution.md](phases/02-agent-execution.md) | Parallel agent spawning and execution |
|
||||
| 3 | [phases/03-result-aggregation.md](phases/03-result-aggregation.md) | Result parsing, feedback generation, iteration handling |
|
||||
| 4 | [phases/04-completion-summary.md](phases/04-completion-summary.md) | Final summary generation and cleanup |
|
||||
|
||||
## Data Flow
|
||||
|
||||
```
|
||||
User Input (TASK | --cycle-id + --extend)
|
||||
↓
|
||||
[Parse Arguments]
|
||||
↓ cycleId, state, progressDir
|
||||
|
||||
Phase 1: Session Initialization
|
||||
↓ cycleId, state, progressDir (initialized/resumed)
|
||||
|
||||
Phase 2: Agent Execution
|
||||
↓ agentOutputs {ra, ep, cd, vas}
|
||||
|
||||
Phase 3: Result Aggregation
|
||||
↓ parsedResults, hasIssues, iteration count
|
||||
↓ [Loop back to Phase 2 if issues and iteration < max]
|
||||
|
||||
Phase 4: Completion & Summary
|
||||
↓ finalState, summaryReport
|
||||
|
||||
Return: cycle_id, iterations, final_state
|
||||
```
|
||||
|
||||
## Session Structure
|
||||
|
||||
```
|
||||
.workflow/.cycle/
|
||||
+-- {cycleId}.json # Master state file
|
||||
+-- {cycleId}.progress/
|
||||
+-- ra/
|
||||
| +-- requirements.md # Current version (complete rewrite)
|
||||
| +-- changes.log # NDJSON complete history (append-only)
|
||||
| └-- history/
|
||||
| +-- requirements-v1.0.0.md # Archived snapshot
|
||||
| +-- requirements-v1.1.0.md # Archived snapshot
|
||||
+-- ep/
|
||||
| +-- exploration.md # Codebase exploration report
|
||||
| +-- architecture.md # Architecture design
|
||||
| +-- plan.json # Structured task list (current version)
|
||||
| +-- changes.log # NDJSON complete history
|
||||
| └-- history/
|
||||
| +-- plan-v1.0.0.json
|
||||
| +-- plan-v1.1.0.json
|
||||
+-- cd/
|
||||
| +-- implementation.md # Current version
|
||||
| +-- debug-log.ndjson # Debug hypothesis tracking
|
||||
| +-- changes.log # NDJSON complete history
|
||||
| └-- history/
|
||||
| +-- implementation-v1.0.0.md
|
||||
| +-- implementation-v1.1.0.md
|
||||
+-- vas/
|
||||
| +-- summary.md # Current version
|
||||
| +-- changes.log # NDJSON complete history
|
||||
| └-- history/
|
||||
| +-- summary-v1.0.0.md
|
||||
| +-- summary-v1.1.0.md
|
||||
└-- coordination/
|
||||
+-- timeline.md # Execution timeline
|
||||
+-- decisions.log # Decision log
|
||||
├── {cycleId}.json # Master state file
|
||||
├── {cycleId}.progress/
|
||||
├── ra/
|
||||
│ ├── requirements.md # Current version (complete rewrite)
|
||||
│ ├── changes.log # NDJSON complete history (append-only)
|
||||
│ └── history/ # Archived snapshots
|
||||
├── ep/
|
||||
│ ├── exploration.md # Codebase exploration report
|
||||
│ ├── architecture.md # Architecture design
|
||||
│ ├── plan.json # Structured task list (current version)
|
||||
│ ├── changes.log # NDJSON complete history
|
||||
│ └── history/
|
||||
├── cd/
|
||||
│ ├── implementation.md # Current version
|
||||
│ ├── debug-log.ndjson # Debug hypothesis tracking
|
||||
│ ├── changes.log # NDJSON complete history
|
||||
│ └── history/
|
||||
├── vas/
|
||||
│ ├── summary.md # Current version
|
||||
│ ├── changes.log # NDJSON complete history
|
||||
│ └── history/
|
||||
└── coordination/
|
||||
├── timeline.md # Execution timeline
|
||||
└── decisions.log # Decision log
|
||||
```
|
||||
|
||||
## State Management
|
||||
|
||||
State schema is defined in [phases/state-schema.md](phases/state-schema.md). The master state file (`{cycleId}.json`) tracks:
|
||||
Master state file: `.workflow/.cycle/{cycleId}.json`
|
||||
|
||||
- Cycle metadata (id, title, status, iterations)
|
||||
- Agent states (status, output files, version)
|
||||
- Shared context (requirements, plan, changes, test results)
|
||||
- Coordination data (feedback log, decisions, blockers)
|
||||
|
||||
## Versioning Workflow
|
||||
|
||||
### Initial Version (v1.0.0)
|
||||
|
||||
```bash
|
||||
/parallel-dev-cycle TASK="Implement OAuth login"
|
||||
```json
|
||||
{
|
||||
"cycle_id": "cycle-v1-20260122T100000-abc123",
|
||||
"title": "Task title",
|
||||
"description": "Full task description",
|
||||
"status": "created | running | paused | completed | failed",
|
||||
"created_at": "ISO8601", "updated_at": "ISO8601",
|
||||
"max_iterations": 5, "current_iteration": 0,
|
||||
"agents": {
|
||||
"ra": { "status": "idle | running | completed | failed", "output_files": [] },
|
||||
"ep": { "status": "idle", "output_files": [] },
|
||||
"cd": { "status": "idle", "output_files": [] },
|
||||
"vas": { "status": "idle", "output_files": [] }
|
||||
},
|
||||
"current_phase": "init | ra | ep | cd | vas | aggregation | complete",
|
||||
"completed_phases": [],
|
||||
"requirements": null, "plan": null, "changes": [], "test_results": null,
|
||||
"coordination": { "feedback_log": [], "blockers": [] }
|
||||
}
|
||||
```
|
||||
|
||||
Generates:
|
||||
```
|
||||
requirements.md (v1.0.0)
|
||||
exploration.md (v1.0.0)
|
||||
architecture.md (v1.0.0)
|
||||
plan.json (v1.0.0)
|
||||
implementation.md (v1.0.0) - if applicable
|
||||
summary.md (v1.0.0) - if applicable
|
||||
**Recovery**: If state corrupted, rebuild from `.progress/` markdown files and changes.log.
|
||||
|
||||
## TodoWrite Pattern
|
||||
|
||||
### Phase-Level Tracking (Tasks Attached)
|
||||
|
||||
```json
|
||||
[
|
||||
{"content": "Phase 1: Session Initialization", "status": "completed"},
|
||||
{"content": "Phase 2: Agent Execution", "status": "in_progress"},
|
||||
{"content": " → Spawn RA Agent", "status": "completed"},
|
||||
{"content": " → Spawn EP Agent", "status": "completed"},
|
||||
{"content": " → Spawn CD Agent", "status": "in_progress"},
|
||||
{"content": " → Spawn VAS Agent", "status": "pending"},
|
||||
{"content": "Phase 3: Result Aggregation", "status": "pending"},
|
||||
{"content": "Phase 4: Completion & Summary", "status": "pending"}
|
||||
]
|
||||
```
|
||||
|
||||
### Iteration Versions (v1.1.0, v1.2.0)
|
||||
### Phase-Level Tracking (Collapsed)
|
||||
|
||||
```bash
|
||||
/parallel-dev-cycle --cycle-id=cycle-v1-xxx --extend="Add GitHub support"
|
||||
```json
|
||||
[
|
||||
{"content": "Phase 1: Session Initialization", "status": "completed"},
|
||||
{"content": "Phase 2: Agent Execution (4 agents completed)", "status": "completed"},
|
||||
{"content": "Phase 3: Result Aggregation", "status": "in_progress"},
|
||||
{"content": "Phase 4: Completion & Summary", "status": "pending"}
|
||||
]
|
||||
```
|
||||
|
||||
**Automatic handling**:
|
||||
1. Read current `requirements.md (v1.0.0)`
|
||||
2. Auto-archive to `history/requirements-v1.0.0.md`
|
||||
3. Recreate `requirements.md (v1.1.0)` - complete overwrite
|
||||
4. Append changes to `changes.log` (NDJSON)
|
||||
### Iteration Loop Tracking
|
||||
|
||||
## Changes.log Format (NDJSON)
|
||||
|
||||
Permanent audit log (append-only, never deleted):
|
||||
|
||||
```jsonl
|
||||
{"timestamp":"2026-01-22T10:00:00+08:00","version":"1.0.0","agent":"ra","action":"create","change":"Initial requirements","iteration":1}
|
||||
{"timestamp":"2026-01-22T11:00:00+08:00","version":"1.1.0","agent":"ra","action":"update","change":"Added Google OAuth requirement","iteration":2}
|
||||
{"timestamp":"2026-01-22T11:30:00+08:00","version":"1.0.0","agent":"ep","action":"create","change":"Initial implementation plan","iteration":1}
|
||||
```json
|
||||
[
|
||||
{"content": "Phase 1: Session Initialization", "status": "completed"},
|
||||
{"content": "Iteration 1: Agent Execution + Aggregation", "status": "completed"},
|
||||
{"content": "Iteration 2: Feedback → Re-execution → Aggregation", "status": "in_progress"},
|
||||
{"content": "Phase 4: Completion & Summary", "status": "pending"}
|
||||
]
|
||||
```
|
||||
|
||||
## Versioning
|
||||
|
||||
- **1.0.0**: Initial cycle → **1.x.0**: Each iteration (minor bump)
|
||||
- Each iteration: archive old → complete rewrite → append changes.log
|
||||
|
||||
```
|
||||
Archive: copy requirements.md → history/requirements-v1.0.0.md
|
||||
Rewrite: overwrite requirements.md with v1.1.0 (complete new content)
|
||||
Append: changes.log ← {"timestamp","version":"1.1.0","action":"update","description":"..."}
|
||||
```
|
||||
|
||||
| Agent Output | Rewrite (per iteration) | Append-only |
|
||||
|-------------|------------------------|-------------|
|
||||
| RA | requirements.md | changes.log |
|
||||
| EP | exploration.md, architecture.md, plan.json | changes.log |
|
||||
| CD | implementation.md, issues.md | changes.log, debug-log.ndjson |
|
||||
| VAS | summary.md, test-results.json | changes.log |
|
||||
|
||||
## Coordination Protocol
|
||||
|
||||
**Execution Order**: RA → EP → CD → VAS (dependency chain, all spawned in parallel but block on dependencies)
|
||||
|
||||
**Agent → Orchestrator**: Each agent outputs `PHASE_RESULT:` block:
|
||||
```
|
||||
PHASE_RESULT:
|
||||
- phase: ra | ep | cd | vas
|
||||
- status: success | failed | partial
|
||||
- files_written: [list]
|
||||
- summary: one-line summary
|
||||
- issues: []
|
||||
```
|
||||
|
||||
**Orchestrator → Agent**: Feedback via `send_input` (file refs + issue summary, never full content):
|
||||
```
|
||||
## FEEDBACK FROM [Source]
|
||||
[Issue summary with file:line references]
|
||||
## Reference
|
||||
- File: .progress/vas/test-results.json (v1.0.0)
|
||||
## Actions Required
|
||||
1. [Specific fix]
|
||||
```
|
||||
|
||||
**Rules**: Only orchestrator writes state file. Agents read state, write to own `.progress/{agent}/` directory only.
|
||||
|
||||
## Core Rules
|
||||
|
||||
1. **Start Immediately**: First action is TodoWrite initialization, then Phase 1 execution
|
||||
2. **Progressive Phase Loading**: Read phase docs ONLY when that phase is about to execute
|
||||
3. **Parse Every Output**: Extract PHASE_RESULT data from each agent for next phase
|
||||
4. **Auto-Continue**: After each phase, execute next pending phase automatically
|
||||
5. **Track Progress**: Update TodoWrite dynamically with attachment/collapse pattern
|
||||
6. **Single Writer**: Only orchestrator writes to master state file; agents report via PHASE_RESULT
|
||||
7. **File References**: Pass file paths between agents, not content
|
||||
8. **DO NOT STOP**: Continuous execution until all phases complete or max iterations reached
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error Type | Recovery |
|
||||
|------------|----------|
|
||||
| Agent timeout | send_input requesting convergence, then retry |
|
||||
| State corrupted | Rebuild from progress markdown files and changes.log |
|
||||
| Agent failed | Re-spawn agent with previous context |
|
||||
| Conflicting results | Orchestrator sends reconciliation request |
|
||||
| Missing files | RA/EP agents identify and request clarification |
|
||||
| Max iterations reached | Generate summary with remaining issues documented |
|
||||
|
||||
## Coordinator Checklist
|
||||
|
||||
### Before Each Phase
|
||||
|
||||
- [ ] Read phase reference document
|
||||
- [ ] Check current state for dependencies
|
||||
- [ ] Update TodoWrite with phase tasks
|
||||
|
||||
### After Each Phase
|
||||
|
||||
- [ ] Parse agent outputs (PHASE_RESULT)
|
||||
- [ ] Update master state file
|
||||
- [ ] Collapse TodoWrite sub-tasks
|
||||
- [ ] Determine next action (continue / iterate / complete)
|
||||
|
||||
## Reference Documents
|
||||
|
||||
| Document | Purpose |
|
||||
|----------|---------|
|
||||
| [roles/](roles/) | Agent role definitions (RA, EP, CD, VAS) |
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
@@ -172,23 +342,3 @@ Permanent audit log (append-only, never deleted):
|
||||
# Auto mode
|
||||
/parallel-dev-cycle --auto TASK="Add OAuth authentication"
|
||||
```
|
||||
|
||||
## Key Benefits
|
||||
|
||||
- **Simple**: Each agent maintains only 1 file + changes.log
|
||||
- **Efficient**: Version rewrite without complex version marking
|
||||
- **Traceable**: Complete history in `history/` and `changes.log`
|
||||
- **Fast**: Agent reads current version quickly (no history parsing needed)
|
||||
- **Auditable**: NDJSON changes.log fully traces every change
|
||||
- **Self-Enhancing**: RA agent proactively extends requirements
|
||||
- **Debug-Ready**: CD agent supports hypothesis-driven debugging
|
||||
|
||||
## Reference Documents
|
||||
|
||||
| Document | Purpose |
|
||||
|----------|---------|
|
||||
| [phases/orchestrator.md](phases/orchestrator.md) | Orchestrator logic |
|
||||
| [phases/state-schema.md](phases/state-schema.md) | State structure definition |
|
||||
| [phases/agents/](phases/agents/) | Four agent role definitions |
|
||||
| [specs/coordination-protocol.md](specs/coordination-protocol.md) | Communication protocol |
|
||||
| [specs/versioning-strategy.md](specs/versioning-strategy.md) | Version management |
|
||||
|
||||
159
.codex/skills/parallel-dev-cycle/phases/01-session-init.md
Normal file
159
.codex/skills/parallel-dev-cycle/phases/01-session-init.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# Phase 1: Session Initialization
|
||||
|
||||
Create or resume a development cycle, initialize state file and directory structure.
|
||||
|
||||
## Objective
|
||||
|
||||
- Parse user arguments (TASK, --cycle-id, --extend, --auto, --parallel)
|
||||
- Create new cycle with unique ID OR resume existing cycle
|
||||
- Initialize directory structure for all agents
|
||||
- Create master state file
|
||||
- Output: cycleId, state, progressDir
|
||||
|
||||
## Execution
|
||||
|
||||
### Step 1.1: Parse Arguments
|
||||
|
||||
```javascript
|
||||
const { cycleId: existingCycleId, task, mode = 'interactive', extension } = options
|
||||
|
||||
// Validate mutual exclusivity
|
||||
if (!existingCycleId && !task) {
|
||||
console.error('Either --cycle-id or task description is required')
|
||||
return { status: 'error', message: 'Missing cycleId or task' }
|
||||
}
|
||||
```
|
||||
|
||||
### Step 1.2: Utility Functions
|
||||
|
||||
```javascript
|
||||
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
|
||||
|
||||
function readCycleState(cycleId) {
|
||||
const stateFile = `.workflow/.cycle/${cycleId}.json`
|
||||
if (!fs.existsSync(stateFile)) {
|
||||
return null
|
||||
}
|
||||
return JSON.parse(Read(stateFile))
|
||||
}
|
||||
```
|
||||
|
||||
### Step 1.3: New Cycle Creation
|
||||
|
||||
When `TASK` is provided (no `--cycle-id`):
|
||||
|
||||
```javascript
|
||||
// Generate unique cycle ID
|
||||
const timestamp = getUtc8ISOString().replace(/[-:]/g, '').split('.')[0]
|
||||
const random = Math.random().toString(36).substring(2, 10)
|
||||
const cycleId = `cycle-v1-${timestamp}-${random}`
|
||||
|
||||
console.log(`Creating new cycle: ${cycleId}`)
|
||||
```
|
||||
|
||||
#### Create Directory Structure
|
||||
|
||||
```bash
|
||||
mkdir -p .workflow/.cycle/${cycleId}.progress/{ra,ep,cd,vas,coordination}
|
||||
mkdir -p .workflow/.cycle/${cycleId}.progress/ra/history
|
||||
mkdir -p .workflow/.cycle/${cycleId}.progress/ep/history
|
||||
mkdir -p .workflow/.cycle/${cycleId}.progress/cd/history
|
||||
mkdir -p .workflow/.cycle/${cycleId}.progress/vas/history
|
||||
```
|
||||
|
||||
#### Initialize State File
|
||||
|
||||
```javascript
|
||||
function createCycleState(cycleId, taskDescription) {
|
||||
const stateFile = `.workflow/.cycle/${cycleId}.json`
|
||||
const now = getUtc8ISOString()
|
||||
|
||||
const state = {
|
||||
// Metadata
|
||||
cycle_id: cycleId,
|
||||
title: taskDescription.substring(0, 100),
|
||||
description: taskDescription,
|
||||
max_iterations: 5,
|
||||
status: 'running',
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
|
||||
// Agent tracking
|
||||
agents: {
|
||||
ra: { status: 'idle', output_files: [] },
|
||||
ep: { status: 'idle', output_files: [] },
|
||||
cd: { status: 'idle', output_files: [] },
|
||||
vas: { status: 'idle', output_files: [] }
|
||||
},
|
||||
|
||||
// Phase tracking
|
||||
current_phase: 'init',
|
||||
completed_phases: [],
|
||||
current_iteration: 0,
|
||||
|
||||
// Shared context (populated by agents)
|
||||
requirements: null,
|
||||
exploration: null,
|
||||
plan: null,
|
||||
changes: [],
|
||||
test_results: null
|
||||
}
|
||||
|
||||
Write(stateFile, JSON.stringify(state, null, 2))
|
||||
return state
|
||||
}
|
||||
```
|
||||
|
||||
### Step 1.4: Resume Existing Cycle
|
||||
|
||||
When `--cycle-id` is provided:
|
||||
|
||||
```javascript
|
||||
const cycleId = existingCycleId
|
||||
const state = readCycleState(cycleId)
|
||||
|
||||
if (!state) {
|
||||
console.error(`Cycle not found: ${cycleId}`)
|
||||
return { status: 'error', message: 'Cycle not found' }
|
||||
}
|
||||
|
||||
console.log(`Resuming cycle: ${cycleId}`)
|
||||
|
||||
// Apply extension if provided
|
||||
if (extension) {
|
||||
console.log(`Extension: ${extension}`)
|
||||
state.description += `\n\n--- ITERATION ${state.current_iteration + 1} ---\n${extension}`
|
||||
}
|
||||
```
|
||||
|
||||
### Step 1.5: Control Signal Check
|
||||
|
||||
Before proceeding, verify cycle status allows continuation:
|
||||
|
||||
```javascript
|
||||
function checkControlSignals(cycleId) {
|
||||
const state = readCycleState(cycleId)
|
||||
|
||||
switch (state?.status) {
|
||||
case 'paused':
|
||||
return { continue: false, action: 'pause_exit' }
|
||||
case 'failed':
|
||||
return { continue: false, action: 'stop_exit' }
|
||||
case 'running':
|
||||
return { continue: true, action: 'continue' }
|
||||
default:
|
||||
return { continue: false, action: 'stop_exit' }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- **Variable**: `cycleId` - Unique cycle identifier
|
||||
- **Variable**: `state` - Initialized or resumed cycle state object
|
||||
- **Variable**: `progressDir` - `.workflow/.cycle/${cycleId}.progress`
|
||||
- **TodoWrite**: Mark Phase 1 completed, Phase 2 in_progress
|
||||
|
||||
## Next Phase
|
||||
|
||||
Return to orchestrator, then auto-continue to [Phase 2: Agent Execution](02-agent-execution.md).
|
||||
309
.codex/skills/parallel-dev-cycle/phases/02-agent-execution.md
Normal file
309
.codex/skills/parallel-dev-cycle/phases/02-agent-execution.md
Normal file
@@ -0,0 +1,309 @@
|
||||
# Phase 2: Agent Execution (Parallel)
|
||||
|
||||
Spawn four specialized agents in parallel and wait for all to complete with timeout handling.
|
||||
|
||||
## Objective
|
||||
|
||||
- Spawn RA, EP, CD, VAS agents simultaneously using Codex subagent pattern
|
||||
- Pass cycle context and role references to each agent
|
||||
- Wait for all agents with configurable timeout
|
||||
- Handle timeout with convergence request
|
||||
- Output: agentOutputs from all 4 agents
|
||||
|
||||
## Agent Role References
|
||||
|
||||
Each agent reads its detailed role definition at execution time:
|
||||
|
||||
| Agent | Role File | Main Output |
|
||||
|-------|-----------|-------------|
|
||||
| RA | [roles/requirements-analyst.md](../roles/requirements-analyst.md) | requirements.md |
|
||||
| EP | [roles/exploration-planner.md](../roles/exploration-planner.md) | exploration.md, architecture.md, plan.json |
|
||||
| CD | [roles/code-developer.md](../roles/code-developer.md) | implementation.md |
|
||||
| VAS | [roles/validation-archivist.md](../roles/validation-archivist.md) | summary.md |
|
||||
|
||||
## Execution
|
||||
|
||||
### Step 2.1: Spawn RA Agent (Requirements Analyst)
|
||||
|
||||
```javascript
|
||||
function spawnRAAgent(cycleId, state, progressDir) {
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/requirements-analyst.md
|
||||
2. Read: .workflow/project-tech.json (if exists)
|
||||
3. Read: .workflow/project-guidelines.json (if exists)
|
||||
4. Read: .workflow/.cycle/${cycleId}.progress/coordination/feedback.md (if exists)
|
||||
|
||||
---
|
||||
|
||||
## CYCLE CONTEXT
|
||||
|
||||
- **Cycle ID**: ${cycleId}
|
||||
- **Progress Dir**: ${progressDir}/ra/
|
||||
- **Current Iteration**: ${state.current_iteration}
|
||||
- **Task Description**: ${state.description}
|
||||
|
||||
## CURRENT REQUIREMENTS STATE
|
||||
|
||||
${state.requirements ? JSON.stringify(state.requirements, null, 2) : 'No previous requirements'}
|
||||
|
||||
## YOUR ROLE
|
||||
|
||||
Requirements Analyst - Analyze and refine requirements throughout the cycle.
|
||||
|
||||
## RESPONSIBILITIES
|
||||
|
||||
1. Analyze initial task description
|
||||
2. Generate comprehensive requirements specification
|
||||
3. Identify edge cases and implicit requirements
|
||||
4. Track requirement changes across iterations
|
||||
5. Maintain requirements.md and changes.log
|
||||
|
||||
## DELIVERABLES
|
||||
|
||||
Write files to ${progressDir}/ra/:
|
||||
- requirements.md: Full requirements specification
|
||||
- edge-cases.md: Edge case analysis
|
||||
- changes.log: NDJSON format change tracking
|
||||
|
||||
## OUTPUT FORMAT
|
||||
|
||||
\`\`\`
|
||||
PHASE_RESULT:
|
||||
- phase: ra
|
||||
- status: success | failed
|
||||
- files_written: [list]
|
||||
- summary: one-line summary
|
||||
- issues: []
|
||||
\`\`\`
|
||||
`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2.2: Spawn EP Agent (Exploration & Planning)
|
||||
|
||||
```javascript
|
||||
function spawnEPAgent(cycleId, state, progressDir) {
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/exploration-planner.md
|
||||
2. Read: .workflow/project-tech.json
|
||||
3. Read: .workflow/project-guidelines.json
|
||||
4. Read: ${progressDir}/ra/requirements.md
|
||||
|
||||
---
|
||||
|
||||
## CYCLE CONTEXT
|
||||
|
||||
- **Cycle ID**: ${cycleId}
|
||||
- **Progress Dir**: ${progressDir}/ep/
|
||||
- **Requirements**: See requirements.md
|
||||
- **Current Plan**: ${state.plan ? 'Existing' : 'None - first iteration'}
|
||||
|
||||
## YOUR ROLE
|
||||
|
||||
Exploration & Planning Agent - Explore architecture and generate implementation plan.
|
||||
|
||||
## RESPONSIBILITIES
|
||||
|
||||
1. Explore codebase architecture
|
||||
2. Map integration points
|
||||
3. Design implementation approach
|
||||
4. Generate plan.json with task breakdown
|
||||
5. Update or iterate on existing plan
|
||||
|
||||
## DELIVERABLES
|
||||
|
||||
Write files to ${progressDir}/ep/:
|
||||
- exploration.md: Codebase exploration findings
|
||||
- architecture.md: Architecture design
|
||||
- plan.json: Implementation plan (structured)
|
||||
|
||||
## OUTPUT FORMAT
|
||||
|
||||
\`\`\`
|
||||
PHASE_RESULT:
|
||||
- phase: ep
|
||||
- status: success | failed
|
||||
- files_written: [list]
|
||||
- summary: one-line summary
|
||||
- plan_version: X.Y.Z
|
||||
\`\`\`
|
||||
`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2.3: Spawn CD Agent (Code Developer)
|
||||
|
||||
```javascript
|
||||
function spawnCDAgent(cycleId, state, progressDir) {
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/code-developer.md
|
||||
2. Read: ${progressDir}/ep/plan.json
|
||||
3. Read: ${progressDir}/ra/requirements.md
|
||||
|
||||
---
|
||||
|
||||
## CYCLE CONTEXT
|
||||
|
||||
- **Cycle ID**: ${cycleId}
|
||||
- **Progress Dir**: ${progressDir}/cd/
|
||||
- **Plan Version**: ${state.plan?.version || 'N/A'}
|
||||
- **Previous Changes**: ${state.changes?.length || 0} files
|
||||
|
||||
## YOUR ROLE
|
||||
|
||||
Code Developer - Implement features based on plan and requirements.
|
||||
|
||||
## RESPONSIBILITIES
|
||||
|
||||
1. Implement features from plan
|
||||
2. Track code changes
|
||||
3. Handle integration issues
|
||||
4. Maintain code quality
|
||||
5. Report implementation progress and issues
|
||||
|
||||
## DELIVERABLES
|
||||
|
||||
Write files to ${progressDir}/cd/:
|
||||
- implementation.md: Implementation progress and decisions
|
||||
- changes.log: NDJSON format, each line: {file, action, timestamp}
|
||||
- issues.md: Development issues and blockers
|
||||
|
||||
## OUTPUT FORMAT
|
||||
|
||||
\`\`\`
|
||||
PHASE_RESULT:
|
||||
- phase: cd
|
||||
- status: success | failed | partial
|
||||
- files_changed: [count]
|
||||
- summary: one-line summary
|
||||
- blockers: []
|
||||
\`\`\`
|
||||
`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2.4: Spawn VAS Agent (Validation & Archival)
|
||||
|
||||
```javascript
|
||||
function spawnVASAgent(cycleId, state, progressDir) {
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/validation-archivist.md
|
||||
2. Read: ${progressDir}/cd/changes.log
|
||||
|
||||
---
|
||||
|
||||
## CYCLE CONTEXT
|
||||
|
||||
- **Cycle ID**: ${cycleId}
|
||||
- **Progress Dir**: ${progressDir}/vas/
|
||||
- **Changes Count**: ${state.changes?.length || 0}
|
||||
- **Iteration**: ${state.current_iteration}
|
||||
|
||||
## YOUR ROLE
|
||||
|
||||
Validation & Archival Specialist - Validate quality and create documentation.
|
||||
|
||||
## RESPONSIBILITIES
|
||||
|
||||
1. Run tests on implemented features
|
||||
2. Generate coverage reports
|
||||
3. Create archival documentation
|
||||
4. Summarize cycle results
|
||||
5. Generate version history
|
||||
|
||||
## DELIVERABLES
|
||||
|
||||
Write files to ${progressDir}/vas/:
|
||||
- validation.md: Test validation results
|
||||
- test-results.json: Detailed test results
|
||||
- coverage.md: Coverage report
|
||||
- summary.md: Cycle summary and recommendations
|
||||
|
||||
## OUTPUT FORMAT
|
||||
|
||||
\`\`\`
|
||||
PHASE_RESULT:
|
||||
- phase: vas
|
||||
- status: success | failed
|
||||
- test_pass_rate: X%
|
||||
- coverage: X%
|
||||
- issues: []
|
||||
\`\`\`
|
||||
`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2.5: Launch All Agents & Wait
|
||||
|
||||
```javascript
|
||||
// Spawn all 4 agents in parallel
|
||||
console.log('Spawning agents...')
|
||||
|
||||
const agents = {
|
||||
ra: spawnRAAgent(cycleId, state, progressDir),
|
||||
ep: spawnEPAgent(cycleId, state, progressDir),
|
||||
cd: spawnCDAgent(cycleId, state, progressDir),
|
||||
vas: spawnVASAgent(cycleId, state, progressDir)
|
||||
}
|
||||
|
||||
// Wait for all agents to complete
|
||||
console.log('Waiting for all agents...')
|
||||
const results = wait({
|
||||
ids: [agents.ra, agents.ep, agents.cd, agents.vas],
|
||||
timeout_ms: 1800000 // 30 minutes
|
||||
})
|
||||
```
|
||||
|
||||
### Step 2.6: Timeout Handling
|
||||
|
||||
```javascript
|
||||
if (results.timed_out) {
|
||||
console.log('Some agents timed out, sending convergence request...')
|
||||
Object.entries(agents).forEach(([name, id]) => {
|
||||
if (!results.status[id].completed) {
|
||||
send_input({
|
||||
id: id,
|
||||
message: `
|
||||
## TIMEOUT NOTIFICATION
|
||||
|
||||
Execution timeout reached. Please:
|
||||
1. Output current progress to markdown file
|
||||
2. Save all state updates
|
||||
3. Return completion status
|
||||
`
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- **Variable**: `agents` - Map of agent names to agent IDs
|
||||
- **Variable**: `results` - Wait results with completion status for each agent
|
||||
- **Variable**: `agentOutputs` - Collected outputs from all 4 agents
|
||||
- **TodoWrite**: Mark Phase 2 completed, Phase 3 in_progress
|
||||
|
||||
## Next Phase
|
||||
|
||||
Return to orchestrator, then auto-continue to [Phase 3: Result Aggregation & Iteration](03-result-aggregation.md).
|
||||
230
.codex/skills/parallel-dev-cycle/phases/03-result-aggregation.md
Normal file
230
.codex/skills/parallel-dev-cycle/phases/03-result-aggregation.md
Normal file
@@ -0,0 +1,230 @@
|
||||
# Phase 3: Result Aggregation & Iteration
|
||||
|
||||
Parse agent outputs, detect issues, generate feedback, and manage the iteration loop.
|
||||
|
||||
## Objective
|
||||
|
||||
- Parse PHASE_RESULT from each agent's output
|
||||
- Aggregate results into unified state
|
||||
- Detect issues (test failures, blockers)
|
||||
- Generate targeted feedback for affected agents
|
||||
- Manage iteration loop (continue or proceed to completion)
|
||||
- Output: parsedResults, iteration decision
|
||||
|
||||
## Execution
|
||||
|
||||
### Step 3.1: Collect Agent Outputs
|
||||
|
||||
```javascript
|
||||
// Collect outputs from all 4 agents
|
||||
const agentOutputs = {
|
||||
ra: results.status[agents.ra].completed,
|
||||
ep: results.status[agents.ep].completed,
|
||||
cd: results.status[agents.cd].completed,
|
||||
vas: results.status[agents.vas].completed
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3.2: Parse PHASE_RESULT
|
||||
|
||||
Each agent outputs a structured PHASE_RESULT block. Parse it to extract status and data:
|
||||
|
||||
```javascript
|
||||
function parseAgentOutputs(agentOutputs) {
|
||||
const results = {
|
||||
ra: parseOutput(agentOutputs.ra, 'ra'),
|
||||
ep: parseOutput(agentOutputs.ep, 'ep'),
|
||||
cd: parseOutput(agentOutputs.cd, 'cd'),
|
||||
vas: parseOutput(agentOutputs.vas, 'vas')
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
function parseOutput(output, agent) {
|
||||
const result = {
|
||||
agent: agent,
|
||||
status: 'unknown',
|
||||
data: {}
|
||||
}
|
||||
|
||||
// Parse PHASE_RESULT block
|
||||
const match = output.match(/PHASE_RESULT:\s*([\s\S]*?)(?:\n\n|$)/)
|
||||
if (match) {
|
||||
const lines = match[1].split('\n')
|
||||
for (const line of lines) {
|
||||
const m = line.match(/^-\s*(\w+):\s*(.+)$/)
|
||||
if (m) {
|
||||
result[m[1]] = m[2].trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3.3: Update State with Results
|
||||
|
||||
```javascript
|
||||
// Update agent states
|
||||
state.agents.ra.status = 'completed'
|
||||
state.agents.ep.status = 'completed'
|
||||
state.agents.cd.status = 'completed'
|
||||
state.agents.vas.status = 'completed'
|
||||
|
||||
// Update shared context from parsed results
|
||||
state.requirements = parsedResults.ra.requirements
|
||||
state.exploration = parsedResults.ep.exploration
|
||||
state.plan = parsedResults.ep.plan
|
||||
state.changes = parsedResults.cd.changes
|
||||
state.test_results = parsedResults.vas.test_results
|
||||
|
||||
state.completed_phases.push(...['ra', 'ep', 'cd', 'vas'])
|
||||
state.updated_at = getUtc8ISOString()
|
||||
|
||||
// Persist state
|
||||
Write(`.workflow/.cycle/${cycleId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
### Step 3.4: Issue Detection
|
||||
|
||||
```javascript
|
||||
const hasIssues = parsedResults.vas.test_results?.passed === false ||
|
||||
parsedResults.cd.issues?.length > 0
|
||||
|
||||
if (hasIssues && iteration < maxIterations) {
|
||||
console.log('Issues detected, preparing for next iteration...')
|
||||
// → Proceed to Step 3.5 (Feedback Generation)
|
||||
} else if (!hasIssues) {
|
||||
console.log('All phases completed successfully')
|
||||
// → Proceed to Phase 4
|
||||
} else if (iteration >= maxIterations) {
|
||||
console.log(`Reached maximum iterations (${maxIterations})`)
|
||||
// → Proceed to Phase 4 with issues documented
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3.5: Feedback Generation
|
||||
|
||||
Generate targeted feedback based on issue type:
|
||||
|
||||
```javascript
|
||||
function generateFeedback(parsedResults) {
|
||||
const feedback = {}
|
||||
|
||||
// Check VAS results → feedback to CD
|
||||
if (parsedResults.vas.test_pass_rate < 100) {
|
||||
feedback.cd = `
|
||||
## FEEDBACK FROM VALIDATION
|
||||
|
||||
Test pass rate: ${parsedResults.vas.test_pass_rate}%
|
||||
|
||||
## ISSUES TO FIX
|
||||
|
||||
${parsedResults.vas.data.issues || 'See test-results.json for details'}
|
||||
|
||||
## NEXT STEP
|
||||
|
||||
Fix failing tests and update implementation.md with resolution.
|
||||
`
|
||||
}
|
||||
|
||||
// Check CD blockers → feedback to RA
|
||||
if (parsedResults.cd.blockers?.length > 0) {
|
||||
feedback.ra = `
|
||||
## FEEDBACK FROM DEVELOPMENT
|
||||
|
||||
Blockers encountered:
|
||||
${parsedResults.cd.blockers.map(b => `- ${b}`).join('\n')}
|
||||
|
||||
## NEXT STEP
|
||||
|
||||
Clarify requirements or identify alternative approaches.
|
||||
Update requirements.md if needed.
|
||||
`
|
||||
}
|
||||
|
||||
return feedback
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3.6: Send Feedback via send_input
|
||||
|
||||
```javascript
|
||||
const feedback = generateFeedback(parsedResults)
|
||||
|
||||
// Send feedback to relevant agents
|
||||
if (feedback.ra) {
|
||||
send_input({
|
||||
id: agents.ra,
|
||||
message: feedback.ra
|
||||
})
|
||||
}
|
||||
|
||||
if (feedback.cd) {
|
||||
send_input({
|
||||
id: agents.cd,
|
||||
message: feedback.cd
|
||||
})
|
||||
}
|
||||
|
||||
// Wait for agents to process feedback and update
|
||||
const updatedResults = wait({
|
||||
ids: [agents.ra, agents.cd].filter(Boolean),
|
||||
timeout_ms: 900000 // 15 minutes for fixes
|
||||
})
|
||||
|
||||
console.log('Agents updated, continuing...')
|
||||
```
|
||||
|
||||
### Step 3.7: Iteration Loop Decision
|
||||
|
||||
```javascript
|
||||
// After feedback processing, decide next action:
|
||||
//
|
||||
// Option A: Issues remain AND iteration < max
|
||||
// → Loop back to Phase 2 (re-spawn or continue agents)
|
||||
//
|
||||
// Option B: No issues remaining
|
||||
// → Proceed to Phase 4 (Completion)
|
||||
//
|
||||
// Option C: Max iterations reached
|
||||
// → Proceed to Phase 4 with issues documented
|
||||
|
||||
if (hasIssues && iteration < maxIterations) {
|
||||
// Continue iteration loop
|
||||
iteration++
|
||||
state.current_iteration = iteration
|
||||
// → Back to Phase 2
|
||||
} else {
|
||||
// Exit loop → Phase 4
|
||||
continueLoop = false
|
||||
}
|
||||
```
|
||||
|
||||
## Iteration Flow Diagram
|
||||
|
||||
```
|
||||
Phase 2: Agent Execution
|
||||
↓
|
||||
Phase 3: Result Aggregation
|
||||
↓
|
||||
┌─ Issues detected?
|
||||
│ ├─ No → Phase 4 (Complete)
|
||||
│ └─ Yes
|
||||
│ ├─ iteration < max?
|
||||
│ │ ├─ Yes → Generate feedback → send_input → Wait → Back to Phase 2
|
||||
│ │ └─ No → Phase 4 (Complete with issues)
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- **Variable**: `parsedResults` - Parsed results from all 4 agents
|
||||
- **Variable**: `hasIssues` - Boolean indicating if issues were found
|
||||
- **Variable**: `continueLoop` - Boolean indicating if iteration should continue
|
||||
- **TodoWrite**: Mark Phase 3 completed, Phase 4 in_progress (or loop)
|
||||
|
||||
## Next Phase
|
||||
|
||||
If iteration continues: Return to Phase 2.
|
||||
If iteration completes: Return to orchestrator, then auto-continue to [Phase 4: Completion & Summary](04-completion-summary.md).
|
||||
109
.codex/skills/parallel-dev-cycle/phases/04-completion-summary.md
Normal file
109
.codex/skills/parallel-dev-cycle/phases/04-completion-summary.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Phase 4: Completion & Summary
|
||||
|
||||
Generate unified summary report, update final state, close all agents, and provide continuation instructions.
|
||||
|
||||
## Objective
|
||||
|
||||
- Generate comprehensive cycle summary report
|
||||
- Update master state file with final status
|
||||
- Close all agent sessions
|
||||
- Provide continuation instructions for future iterations
|
||||
- Output: final cycle report
|
||||
|
||||
## Execution
|
||||
|
||||
### Step 4.1: Generate Final Summary
|
||||
|
||||
```javascript
|
||||
function generateFinalSummary(cycleId, state) {
|
||||
const summaryFile = `.workflow/.cycle/${cycleId}.progress/coordination/summary.md`
|
||||
|
||||
const summary = `# Cycle Summary - ${cycleId}
|
||||
|
||||
## Metadata
|
||||
- Cycle ID: ${cycleId}
|
||||
- Started: ${state.created_at}
|
||||
- Completed: ${state.completed_at}
|
||||
- Iterations: ${state.current_iteration}
|
||||
- Status: ${state.status}
|
||||
|
||||
## Phase Results
|
||||
- Requirements Analysis: ✓ Completed
|
||||
- Exploration & Planning: ✓ Completed
|
||||
- Code Development: ✓ Completed
|
||||
- Validation & Archival: ✓ Completed
|
||||
|
||||
## Key Deliverables
|
||||
- Requirements: ${state.requirements ? '✓' : '✗'}
|
||||
- Architecture Plan: ${state.plan ? '✓' : '✗'}
|
||||
- Code Changes: ${state.changes?.length || 0} files
|
||||
- Test Results: ${state.test_results?.pass_rate || '0'}% passing
|
||||
|
||||
## Generated Files
|
||||
- .workflow/.cycle/${cycleId}.progress/ra/requirements.md
|
||||
- .workflow/.cycle/${cycleId}.progress/ep/plan.json
|
||||
- .workflow/.cycle/${cycleId}.progress/cd/changes.log
|
||||
- .workflow/.cycle/${cycleId}.progress/vas/summary.md
|
||||
|
||||
## Continuation Instructions
|
||||
|
||||
To extend this cycle:
|
||||
|
||||
\`\`\`bash
|
||||
/parallel-dev-cycle --cycle-id=${cycleId} --extend="New requirement or feedback"
|
||||
\`\`\`
|
||||
|
||||
This will spawn agents for iteration ${state.current_iteration + 1}.
|
||||
`
|
||||
|
||||
Write(summaryFile, summary)
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4.2: Update Final State
|
||||
|
||||
```javascript
|
||||
state.status = 'completed'
|
||||
state.completed_at = getUtc8ISOString()
|
||||
Write(`.workflow/.cycle/${cycleId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
### Step 4.3: Close All Agents
|
||||
|
||||
```javascript
|
||||
Object.values(agents).forEach(id => {
|
||||
try {
|
||||
close_agent({ id })
|
||||
} catch (e) {
|
||||
console.warn(`Failed to close agent ${id}`)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Step 4.4: Return Result
|
||||
|
||||
```javascript
|
||||
console.log('\n=== Parallel Dev Cycle Orchestrator Finished ===')
|
||||
|
||||
return {
|
||||
status: 'completed',
|
||||
cycle_id: cycleId,
|
||||
iterations: iteration,
|
||||
final_state: state
|
||||
}
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- **File**: `.workflow/.cycle/{cycleId}.progress/coordination/summary.md`
|
||||
- **File**: `.workflow/.cycle/{cycleId}.json` (final state)
|
||||
- **TodoWrite**: Mark Phase 4 completed (all tasks done)
|
||||
|
||||
## Completion
|
||||
|
||||
Parallel Dev Cycle has completed. The cycle report is at `.workflow/.cycle/{cycleId}.progress/coordination/summary.md`.
|
||||
|
||||
To continue iterating:
|
||||
```bash
|
||||
/parallel-dev-cycle --cycle-id={cycleId} --extend="Additional requirements or feedback"
|
||||
```
|
||||
@@ -1,696 +0,0 @@
|
||||
# Orchestrator - Multi-Agent Coordination (Codex Pattern)
|
||||
|
||||
Orchestrate parallel dev cycle using Codex subagent pattern with continuous iteration support.
|
||||
|
||||
## Role
|
||||
|
||||
Coordinate four specialized agents → Manage state → Support continuous iteration → Generate unified documentation.
|
||||
|
||||
## Codex Pattern Overview
|
||||
|
||||
```
|
||||
Main Orchestrator Flow:
|
||||
|
||||
┌─── spawn_agent (orchestrator role) ────────────────────────────┐
|
||||
│ │
|
||||
│ Phase 1: INIT (Check control signals) │
|
||||
│ ↓ │
|
||||
│ wait() → Parse cycle state │
|
||||
│ ↓ │
|
||||
│ Phase 2: AGENT ORCHESTRATION │
|
||||
│ ↓ │
|
||||
│ spawn_agent(RA) | spawn_agent(EP) │
|
||||
│ spawn_agent(CD) | spawn_agent(VAS) │
|
||||
│ ↓ │
|
||||
│ wait({ ids: [RA, EP, CD, VAS] }) → Collect all results │
|
||||
│ ↓ │
|
||||
│ Phase 3: ITERATION HANDLING │
|
||||
│ ↓ │
|
||||
│ [If extension needed] │
|
||||
│ send_input to affected agents │
|
||||
│ wait() for updated results │
|
||||
│ ↓ │
|
||||
│ Phase 4: AGGREGATION │
|
||||
│ ↓ │
|
||||
│ Merge all outputs → Generate unified documentation │
|
||||
│ ↓ │
|
||||
│ Update cycle state │
|
||||
│ ↓ │
|
||||
│ [Loop if more iterations] │
|
||||
│ ↓ │
|
||||
│ close_agent() when complete │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## State Management
|
||||
|
||||
### Read Cycle State
|
||||
|
||||
```javascript
|
||||
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
|
||||
|
||||
function readCycleState(cycleId) {
|
||||
const stateFile = `.workflow/.cycle/${cycleId}.json`
|
||||
if (!fs.existsSync(stateFile)) {
|
||||
return null
|
||||
}
|
||||
return JSON.parse(Read(stateFile))
|
||||
}
|
||||
```
|
||||
|
||||
### Create New Cycle State
|
||||
|
||||
```javascript
|
||||
function createCycleState(cycleId, taskDescription) {
|
||||
const stateFile = `.workflow/.cycle/${cycleId}.json`
|
||||
const now = getUtc8ISOString()
|
||||
|
||||
const state = {
|
||||
// Metadata
|
||||
cycle_id: cycleId,
|
||||
title: taskDescription.substring(0, 100),
|
||||
description: taskDescription,
|
||||
max_iterations: 5,
|
||||
status: 'running',
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
|
||||
// Agent tracking
|
||||
agents: {
|
||||
ra: { status: 'idle', output_files: [] },
|
||||
ep: { status: 'idle', output_files: [] },
|
||||
cd: { status: 'idle', output_files: [] },
|
||||
vas: { status: 'idle', output_files: [] }
|
||||
},
|
||||
|
||||
// Phase tracking
|
||||
current_phase: 'init',
|
||||
completed_phases: [],
|
||||
current_iteration: 0,
|
||||
|
||||
// Shared context (populated by agents)
|
||||
requirements: null,
|
||||
exploration: null,
|
||||
plan: null,
|
||||
changes: [],
|
||||
test_results: null
|
||||
}
|
||||
|
||||
// Create directories
|
||||
mkdir -p `.workflow/.cycle/${cycleId}.progress/{ra,ep,cd,vas,coordination}`
|
||||
|
||||
Write(stateFile, JSON.stringify(state, null, 2))
|
||||
return state
|
||||
}
|
||||
```
|
||||
|
||||
## Main Execution Flow (Codex Subagent)
|
||||
|
||||
```javascript
|
||||
async function runOrchestrator(options = {}) {
|
||||
const { cycleId: existingCycleId, task, mode = 'interactive', extension } = options
|
||||
|
||||
console.log('=== Parallel Dev Cycle Orchestrator Started ===')
|
||||
|
||||
// 1. Determine cycleId and initial state
|
||||
let cycleId
|
||||
let state
|
||||
|
||||
if (existingCycleId) {
|
||||
// Continue existing cycle
|
||||
cycleId = existingCycleId
|
||||
state = readCycleState(cycleId)
|
||||
|
||||
if (!state) {
|
||||
console.error(`Cycle not found: ${cycleId}`)
|
||||
return { status: 'error', message: 'Cycle not found' }
|
||||
}
|
||||
|
||||
console.log(`Resuming cycle: ${cycleId}`)
|
||||
if (extension) {
|
||||
console.log(`Extension: ${extension}`)
|
||||
state.description += `\n\n--- ITERATION ${state.current_iteration + 1} ---\n${extension}`
|
||||
}
|
||||
|
||||
} else if (task) {
|
||||
// Create new cycle
|
||||
const timestamp = getUtc8ISOString().replace(/[-:]/g, '').split('.')[0]
|
||||
const random = Math.random().toString(36).substring(2, 10)
|
||||
cycleId = `cycle-v1-${timestamp}-${random}`
|
||||
|
||||
console.log(`Creating new cycle: ${cycleId}`)
|
||||
state = createCycleState(cycleId, task)
|
||||
|
||||
} else {
|
||||
console.error('Either --cycle-id or task description is required')
|
||||
return { status: 'error', message: 'Missing cycleId or task' }
|
||||
}
|
||||
|
||||
const progressDir = `.workflow/.cycle/${cycleId}.progress`
|
||||
|
||||
// 2. Main orchestration loop
|
||||
let iteration = state.current_iteration || 0
|
||||
const maxIterations = state.max_iterations || 5
|
||||
let continueLoop = true
|
||||
|
||||
while (continueLoop && iteration < maxIterations) {
|
||||
iteration++
|
||||
state.current_iteration = iteration
|
||||
|
||||
console.log(`\n========== ITERATION ${iteration} ==========`)
|
||||
|
||||
// 3. Spawn four agents in parallel
|
||||
console.log('Spawning agents...')
|
||||
|
||||
const agents = {
|
||||
ra: spawnRAAgent(cycleId, state, progressDir),
|
||||
ep: spawnEPAgent(cycleId, state, progressDir),
|
||||
cd: spawnCDAgent(cycleId, state, progressDir),
|
||||
vas: spawnVASAgent(cycleId, state, progressDir)
|
||||
}
|
||||
|
||||
// 4. Wait for all agents to complete
|
||||
console.log('Waiting for all agents...')
|
||||
const results = wait({
|
||||
ids: [agents.ra, agents.ep, agents.cd, agents.vas],
|
||||
timeout_ms: 1800000 // 30 minutes
|
||||
})
|
||||
|
||||
if (results.timed_out) {
|
||||
console.log('Some agents timed out, sending convergence request...')
|
||||
Object.entries(agents).forEach(([name, id]) => {
|
||||
if (!results.status[id].completed) {
|
||||
send_input({
|
||||
id: id,
|
||||
message: `
|
||||
## TIMEOUT NOTIFICATION
|
||||
|
||||
Execution timeout reached. Please:
|
||||
1. Output current progress to markdown file
|
||||
2. Save all state updates
|
||||
3. Return completion status
|
||||
`
|
||||
})
|
||||
}
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// 5. Collect all agent outputs
|
||||
const agentOutputs = {
|
||||
ra: results.status[agents.ra].completed,
|
||||
ep: results.status[agents.ep].completed,
|
||||
cd: results.status[agents.cd].completed,
|
||||
vas: results.status[agents.vas].completed
|
||||
}
|
||||
|
||||
// 6. Parse and aggregate results
|
||||
const parsedResults = parseAgentOutputs(agentOutputs)
|
||||
|
||||
// Update state with agent results
|
||||
state.agents.ra.status = 'completed'
|
||||
state.agents.ep.status = 'completed'
|
||||
state.agents.cd.status = 'completed'
|
||||
state.agents.vas.status = 'completed'
|
||||
|
||||
state.requirements = parsedResults.ra.requirements
|
||||
state.exploration = parsedResults.ep.exploration
|
||||
state.plan = parsedResults.ep.plan
|
||||
state.changes = parsedResults.cd.changes
|
||||
state.test_results = parsedResults.vas.test_results
|
||||
|
||||
state.completed_phases.push(...['ra', 'ep', 'cd', 'vas'])
|
||||
state.updated_at = getUtc8ISOString()
|
||||
|
||||
// Save state
|
||||
Write(`.workflow/.cycle/${cycleId}.json`, JSON.stringify(state, null, 2))
|
||||
|
||||
// 7. Check for issues and determine next iteration
|
||||
const hasIssues = parsedResults.vas.test_results?.passed === false ||
|
||||
parsedResults.cd.issues?.length > 0
|
||||
|
||||
if (hasIssues && iteration < maxIterations) {
|
||||
console.log('Issues detected, preparing for next iteration...')
|
||||
|
||||
// Generate feedback for agents
|
||||
const feedback = generateFeedback(parsedResults)
|
||||
|
||||
// Send feedback to relevant agents
|
||||
if (feedback.ra) {
|
||||
send_input({
|
||||
id: agents.ra,
|
||||
message: feedback.ra
|
||||
})
|
||||
}
|
||||
|
||||
if (feedback.cd) {
|
||||
send_input({
|
||||
id: agents.cd,
|
||||
message: feedback.cd
|
||||
})
|
||||
}
|
||||
|
||||
// Wait for updates
|
||||
const updatedResults = wait({
|
||||
ids: [agents.ra, agents.cd].filter(Boolean),
|
||||
timeout_ms: 900000
|
||||
})
|
||||
|
||||
console.log('Agents updated, continuing...')
|
||||
|
||||
} else if (!hasIssues) {
|
||||
console.log('All phases completed successfully')
|
||||
continueLoop = false
|
||||
|
||||
} else if (iteration >= maxIterations) {
|
||||
console.log(`Reached maximum iterations (${maxIterations})`)
|
||||
continueLoop = false
|
||||
}
|
||||
}
|
||||
|
||||
// 8. Generate unified summary
|
||||
console.log('Generating final summary...')
|
||||
generateFinalSummary(cycleId, state)
|
||||
|
||||
// 9. Update final state
|
||||
state.status = 'completed'
|
||||
state.completed_at = getUtc8ISOString()
|
||||
Write(`.workflow/.cycle/${cycleId}.json`, JSON.stringify(state, null, 2))
|
||||
|
||||
// 10. Cleanup
|
||||
Object.values(agents).forEach(id => {
|
||||
try {
|
||||
close_agent({ id })
|
||||
} catch (e) {
|
||||
console.warn(`Failed to close agent ${id}`)
|
||||
}
|
||||
})
|
||||
|
||||
console.log('\n=== Parallel Dev Cycle Orchestrator Finished ===')
|
||||
|
||||
return {
|
||||
status: 'completed',
|
||||
cycle_id: cycleId,
|
||||
iterations: iteration,
|
||||
final_state: state
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Agent Spawning Functions
|
||||
|
||||
### Spawn RA Agent
|
||||
|
||||
```javascript
|
||||
function spawnRAAgent(cycleId, state, progressDir) {
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/requirements-analyst.md
|
||||
2. Read: .workflow/project-tech.json (if exists)
|
||||
3. Read: .workflow/project-guidelines.json (if exists)
|
||||
4. Read: .workflow/.cycle/${cycleId}.progress/coordination/feedback.md (if exists)
|
||||
|
||||
---
|
||||
|
||||
## CYCLE CONTEXT
|
||||
|
||||
- **Cycle ID**: ${cycleId}
|
||||
- **Progress Dir**: ${progressDir}/ra/
|
||||
- **Current Iteration**: ${state.current_iteration}
|
||||
- **Task Description**: ${state.description}
|
||||
|
||||
## CURRENT REQUIREMENTS STATE
|
||||
|
||||
${state.requirements ? JSON.stringify(state.requirements, null, 2) : 'No previous requirements'}
|
||||
|
||||
## YOUR ROLE
|
||||
|
||||
Requirements Analyst - Analyze and refine requirements throughout the cycle.
|
||||
|
||||
## RESPONSIBILITIES
|
||||
|
||||
1. Analyze initial task description
|
||||
2. Generate comprehensive requirements specification
|
||||
3. Identify edge cases and implicit requirements
|
||||
4. Track requirement changes across iterations
|
||||
5. Maintain requirements.md and changes.log
|
||||
|
||||
## DELIVERABLES
|
||||
|
||||
Write files to ${progressDir}/ra/:
|
||||
- requirements.md: Full requirements specification
|
||||
- edge-cases.md: Edge case analysis
|
||||
- changes.log: NDJSON format change tracking
|
||||
|
||||
## OUTPUT FORMAT
|
||||
|
||||
\`\`\`
|
||||
PHASE_RESULT:
|
||||
- phase: ra
|
||||
- status: success | failed
|
||||
- files_written: [list]
|
||||
- summary: one-line summary
|
||||
- issues: []
|
||||
\`\`\`
|
||||
`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Spawn EP Agent
|
||||
|
||||
```javascript
|
||||
function spawnEPAgent(cycleId, state, progressDir) {
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/exploration-planner.md
|
||||
2. Read: .workflow/project-tech.json
|
||||
3. Read: .workflow/project-guidelines.json
|
||||
4. Read: ${progressDir}/ra/requirements.md
|
||||
|
||||
---
|
||||
|
||||
## CYCLE CONTEXT
|
||||
|
||||
- **Cycle ID**: ${cycleId}
|
||||
- **Progress Dir**: ${progressDir}/ep/
|
||||
- **Requirements**: See requirements.md
|
||||
- **Current Plan**: ${state.plan ? 'Existing' : 'None - first iteration'}
|
||||
|
||||
## YOUR ROLE
|
||||
|
||||
Exploration & Planning Agent - Explore architecture and generate implementation plan.
|
||||
|
||||
## RESPONSIBILITIES
|
||||
|
||||
1. Explore codebase architecture
|
||||
2. Map integration points
|
||||
3. Design implementation approach
|
||||
4. Generate plan.json with task breakdown
|
||||
5. Update or iterate on existing plan
|
||||
|
||||
## DELIVERABLES
|
||||
|
||||
Write files to ${progressDir}/ep/:
|
||||
- exploration.md: Codebase exploration findings
|
||||
- architecture.md: Architecture design
|
||||
- plan.json: Implementation plan (structured)
|
||||
|
||||
## OUTPUT FORMAT
|
||||
|
||||
\`\`\`
|
||||
PHASE_RESULT:
|
||||
- phase: ep
|
||||
- status: success | failed
|
||||
- files_written: [list]
|
||||
- summary: one-line summary
|
||||
- plan_version: X.Y.Z
|
||||
\`\`\`
|
||||
`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Spawn CD Agent
|
||||
|
||||
```javascript
|
||||
function spawnCDAgent(cycleId, state, progressDir) {
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/code-developer.md
|
||||
2. Read: ${progressDir}/ep/plan.json
|
||||
3. Read: ${progressDir}/ra/requirements.md
|
||||
|
||||
---
|
||||
|
||||
## CYCLE CONTEXT
|
||||
|
||||
- **Cycle ID**: ${cycleId}
|
||||
- **Progress Dir**: ${progressDir}/cd/
|
||||
- **Plan Version**: ${state.plan?.version || 'N/A'}
|
||||
- **Previous Changes**: ${state.changes?.length || 0} files
|
||||
|
||||
## YOUR ROLE
|
||||
|
||||
Code Developer - Implement features based on plan and requirements.
|
||||
|
||||
## RESPONSIBILITIES
|
||||
|
||||
1. Implement features from plan
|
||||
2. Track code changes
|
||||
3. Handle integration issues
|
||||
4. Maintain code quality
|
||||
5. Report implementation progress and issues
|
||||
|
||||
## DELIVERABLES
|
||||
|
||||
Write files to ${progressDir}/cd/:
|
||||
- implementation.md: Implementation progress and decisions
|
||||
- changes.log: NDJSON format, each line: {file, action, timestamp}
|
||||
- issues.md: Development issues and blockers
|
||||
|
||||
## OUTPUT FORMAT
|
||||
|
||||
\`\`\`
|
||||
PHASE_RESULT:
|
||||
- phase: cd
|
||||
- status: success | failed | partial
|
||||
- files_changed: [count]
|
||||
- summary: one-line summary
|
||||
- blockers: []
|
||||
\`\`\`
|
||||
`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Spawn VAS Agent
|
||||
|
||||
```javascript
|
||||
function spawnVASAgent(cycleId, state, progressDir) {
|
||||
return spawn_agent({
|
||||
message: `
|
||||
## TASK ASSIGNMENT
|
||||
|
||||
### MANDATORY FIRST STEPS (Agent Execute)
|
||||
1. **Read role definition**: ~/.codex/agents/validation-archivist.md
|
||||
2. Read: ${progressDir}/cd/changes.log
|
||||
|
||||
---
|
||||
|
||||
## CYCLE CONTEXT
|
||||
|
||||
- **Cycle ID**: ${cycleId}
|
||||
- **Progress Dir**: ${progressDir}/vas/
|
||||
- **Changes Count**: ${state.changes?.length || 0}
|
||||
- **Iteration**: ${state.current_iteration}
|
||||
|
||||
## YOUR ROLE
|
||||
|
||||
Validation & Archival Specialist - Validate quality and create documentation.
|
||||
|
||||
## RESPONSIBILITIES
|
||||
|
||||
1. Run tests on implemented features
|
||||
2. Generate coverage reports
|
||||
3. Create archival documentation
|
||||
4. Summarize cycle results
|
||||
5. Generate version history
|
||||
|
||||
## DELIVERABLES
|
||||
|
||||
Write files to ${progressDir}/vas/:
|
||||
- validation.md: Test validation results
|
||||
- test-results.json: Detailed test results
|
||||
- coverage.md: Coverage report
|
||||
- summary.md: Cycle summary and recommendations
|
||||
|
||||
## OUTPUT FORMAT
|
||||
|
||||
\`\`\`
|
||||
PHASE_RESULT:
|
||||
- phase: vas
|
||||
- status: success | failed
|
||||
- test_pass_rate: X%
|
||||
- coverage: X%
|
||||
- issues: []
|
||||
\`\`\`
|
||||
`
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Result Parsing
|
||||
|
||||
```javascript
|
||||
function parseAgentOutputs(agentOutputs) {
|
||||
const results = {
|
||||
ra: parseOutput(agentOutputs.ra, 'ra'),
|
||||
ep: parseOutput(agentOutputs.ep, 'ep'),
|
||||
cd: parseOutput(agentOutputs.cd, 'cd'),
|
||||
vas: parseOutput(agentOutputs.vas, 'vas')
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
function parseOutput(output, agent) {
|
||||
const result = {
|
||||
agent: agent,
|
||||
status: 'unknown',
|
||||
data: {}
|
||||
}
|
||||
|
||||
// Parse PHASE_RESULT block
|
||||
const match = output.match(/PHASE_RESULT:\s*([\s\S]*?)(?:\n\n|$)/)
|
||||
if (match) {
|
||||
const lines = match[1].split('\n')
|
||||
for (const line of lines) {
|
||||
const m = line.match(/^-\s*(\w+):\s*(.+)$/)
|
||||
if (m) {
|
||||
result[m[1]] = m[2].trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
## Feedback Generation
|
||||
|
||||
```javascript
|
||||
function generateFeedback(parsedResults) {
|
||||
const feedback = {}
|
||||
|
||||
// Check VAS results
|
||||
if (parsedResults.vas.test_pass_rate < 100) {
|
||||
feedback.cd = `
|
||||
## FEEDBACK FROM VALIDATION
|
||||
|
||||
Test pass rate: ${parsedResults.vas.test_pass_rate}%
|
||||
|
||||
## ISSUES TO FIX
|
||||
|
||||
${parsedResults.vas.data.issues || 'See test-results.json for details'}
|
||||
|
||||
## NEXT STEP
|
||||
|
||||
Fix failing tests and update implementation.md with resolution.
|
||||
`
|
||||
}
|
||||
|
||||
// Check CD blockers
|
||||
if (parsedResults.cd.blockers?.length > 0) {
|
||||
feedback.ra = `
|
||||
## FEEDBACK FROM DEVELOPMENT
|
||||
|
||||
Blockers encountered:
|
||||
${parsedResults.cd.blockers.map(b => `- ${b}`).join('\n')}
|
||||
|
||||
## NEXT STEP
|
||||
|
||||
Clarify requirements or identify alternative approaches.
|
||||
Update requirements.md if needed.
|
||||
`
|
||||
}
|
||||
|
||||
return feedback
|
||||
}
|
||||
```
|
||||
|
||||
## Summary Generation
|
||||
|
||||
```javascript
|
||||
function generateFinalSummary(cycleId, state) {
|
||||
const summaryFile = `.workflow/.cycle/${cycleId}.progress/coordination/summary.md`
|
||||
|
||||
const summary = `# Cycle Summary - ${cycleId}
|
||||
|
||||
## Metadata
|
||||
- Cycle ID: ${cycleId}
|
||||
- Started: ${state.created_at}
|
||||
- Completed: ${state.completed_at}
|
||||
- Iterations: ${state.current_iteration}
|
||||
- Status: ${state.status}
|
||||
|
||||
## Phase Results
|
||||
- Requirements Analysis: ✓ Completed
|
||||
- Exploration & Planning: ✓ Completed
|
||||
- Code Development: ✓ Completed
|
||||
- Validation & Archival: ✓ Completed
|
||||
|
||||
## Key Deliverables
|
||||
- Requirements: ${state.requirements ? '✓' : '✗'}
|
||||
- Architecture Plan: ${state.plan ? '✓' : '✗'}
|
||||
- Code Changes: ${state.changes?.length || 0} files
|
||||
- Test Results: ${state.test_results?.pass_rate || '0'}% passing
|
||||
|
||||
## Generated Files
|
||||
- .workflow/.cycle/${cycleId}.progress/ra/requirements.md
|
||||
- .workflow/.cycle/${cycleId}.progress/ep/plan.json
|
||||
- .workflow/.cycle/${cycleId}.progress/cd/changes.log
|
||||
- .workflow/.cycle/${cycleId}.progress/vas/summary.md
|
||||
|
||||
## Continuation Instructions
|
||||
|
||||
To extend this cycle:
|
||||
|
||||
\`\`\`bash
|
||||
/parallel-dev-cycle --cycle-id=${cycleId} --extend="New requirement or feedback"
|
||||
\`\`\`
|
||||
|
||||
This will spawn agents for iteration ${state.current_iteration + 1}.
|
||||
`
|
||||
|
||||
Write(summaryFile, summary)
|
||||
}
|
||||
```
|
||||
|
||||
## Control Signal Checking
|
||||
|
||||
```javascript
|
||||
function checkControlSignals(cycleId) {
|
||||
const state = readCycleState(cycleId)
|
||||
|
||||
switch (state?.status) {
|
||||
case 'paused':
|
||||
return { continue: false, action: 'pause_exit' }
|
||||
case 'failed':
|
||||
return { continue: false, action: 'stop_exit' }
|
||||
case 'running':
|
||||
return { continue: true, action: 'continue' }
|
||||
default:
|
||||
return { continue: false, action: 'stop_exit' }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Recovery Strategies
|
||||
|
||||
| Error Type | Recovery |
|
||||
|------------|----------|
|
||||
| Agent timeout | send_input requesting convergence |
|
||||
| State corrupted | Rebuild from progress markdown files |
|
||||
| Agent failed | Re-spawn agent with previous context |
|
||||
| Conflicting results | Orchestrator sends reconciliation request |
|
||||
| Missing files | RA/EP agents identify and request clarification |
|
||||
|
||||
## Codex Best Practices Applied
|
||||
|
||||
1. **Single Orchestrator**: One main agent manages all phases
|
||||
2. **Parallel Workers**: Four specialized agents execute simultaneously
|
||||
3. **Batch wait()**: Wait for all agents with `wait({ ids: [...] })`
|
||||
4. **Deep Interaction**: Use send_input for iteration and refinement
|
||||
5. **Delayed close_agent**: Only after all phases and iterations complete
|
||||
6. **Role Path Passing**: Each agent reads its own role definition
|
||||
7. **Persistent Context**: Cycle state shared across all agents
|
||||
@@ -1,436 +0,0 @@
|
||||
# State Schema - Parallel Dev Cycle
|
||||
|
||||
Unified cycle state structure for multi-agent coordination and iteration support.
|
||||
|
||||
## State File Location
|
||||
|
||||
**Location**: `.workflow/.cycle/{cycleId}.json` (unified state, all agents access)
|
||||
|
||||
**Format**: JSON
|
||||
|
||||
## Cycle State Interface
|
||||
|
||||
```typescript
|
||||
interface CycleState {
|
||||
// =====================================================
|
||||
// CORE METADATA
|
||||
// =====================================================
|
||||
|
||||
cycle_id: string // Unique cycle identifier
|
||||
title: string // Task title (first 100 chars)
|
||||
description: string // Full task description
|
||||
task_history: string[] // All task descriptions across iterations
|
||||
|
||||
// =====================================================
|
||||
// STATUS & TIMING
|
||||
// =====================================================
|
||||
|
||||
status: 'created' | 'running' | 'paused' | 'completed' | 'failed'
|
||||
created_at: string // ISO8601 format
|
||||
updated_at: string // ISO8601 format
|
||||
completed_at?: string // ISO8601 format
|
||||
|
||||
max_iterations: number // Maximum iteration limit
|
||||
current_iteration: number // Current iteration count
|
||||
failure_reason?: string // If failed, why
|
||||
|
||||
// =====================================================
|
||||
// MULTI-AGENT TRACKING
|
||||
// =====================================================
|
||||
|
||||
agents: {
|
||||
ra: AgentState // Requirements Analyst
|
||||
ep: AgentState // Exploration Planner
|
||||
cd: AgentState // Code Developer
|
||||
vas: AgentState // Validation Archivist
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// PHASE TRACKING
|
||||
// =====================================================
|
||||
|
||||
current_phase: 'init' | 'ra' | 'ep' | 'cd' | 'vas' | 'aggregation' | 'complete'
|
||||
completed_phases: string[]
|
||||
phase_errors: Array<{
|
||||
phase: string
|
||||
error: string
|
||||
timestamp: string
|
||||
}>
|
||||
|
||||
// =====================================================
|
||||
// SHARED CONTEXT (Populated by agents)
|
||||
// =====================================================
|
||||
|
||||
requirements?: {
|
||||
version: string // e.g., "1.0.0", "1.1.0"
|
||||
specification: string // Full spec from requirements.md
|
||||
edge_cases: string[]
|
||||
last_updated: string
|
||||
}
|
||||
|
||||
exploration?: {
|
||||
version: string
|
||||
architecture_summary: string
|
||||
integration_points: string[]
|
||||
identified_risks: string[]
|
||||
last_updated: string
|
||||
}
|
||||
|
||||
plan?: {
|
||||
version: string
|
||||
tasks: PlanTask[]
|
||||
total_estimated_effort: string
|
||||
critical_path: string[]
|
||||
last_updated: string
|
||||
}
|
||||
|
||||
changes?: {
|
||||
total_files: number
|
||||
changes: ChangeLog[]
|
||||
iteration_markers: Record<number, string> // Iteration timestamps
|
||||
}
|
||||
|
||||
test_results?: {
|
||||
version: string
|
||||
pass_rate: number // 0-100
|
||||
coverage: number // 0-100
|
||||
failed_tests: string[]
|
||||
total_tests: number
|
||||
last_run: string
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// ITERATION TRACKING
|
||||
// =====================================================
|
||||
|
||||
iterations: IterationRecord[]
|
||||
|
||||
// =====================================================
|
||||
// COORDINATION DATA
|
||||
// =====================================================
|
||||
|
||||
coordination: {
|
||||
feedback_log: FeedbackEntry[]
|
||||
pending_decisions: Decision[]
|
||||
blockers: Blocker[]
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// SUPPORTING TYPES
|
||||
// =====================================================
|
||||
|
||||
interface AgentState {
|
||||
status: 'idle' | 'running' | 'waiting' | 'completed' | 'failed'
|
||||
started_at?: string
|
||||
completed_at?: string
|
||||
output_files: string[]
|
||||
last_message?: string
|
||||
error?: string
|
||||
iterations_completed: number
|
||||
}
|
||||
|
||||
interface PlanTask {
|
||||
id: string // e.g., "TASK-001"
|
||||
description: string
|
||||
effort: 'small' | 'medium' | 'large'
|
||||
depends_on: string[]
|
||||
status: 'pending' | 'in_progress' | 'completed' | 'blocked'
|
||||
assigned_to?: string // Agent name
|
||||
files: string[]
|
||||
}
|
||||
|
||||
interface ChangeLog {
|
||||
timestamp: string
|
||||
file: string
|
||||
action: 'create' | 'modify' | 'delete'
|
||||
iteration: number
|
||||
agent: string // which agent made change
|
||||
description: string
|
||||
}
|
||||
|
||||
interface IterationRecord {
|
||||
number: number
|
||||
extension?: string // User feedback/extension for this iteration
|
||||
started_at: string
|
||||
completed_at: string
|
||||
agent_results: Record<string, {
|
||||
status: string
|
||||
files_modified: number
|
||||
}>
|
||||
issues_found: string[]
|
||||
resolved: boolean
|
||||
}
|
||||
|
||||
interface FeedbackEntry {
|
||||
timestamp: string
|
||||
source: string // Agent or 'user'
|
||||
target: string // Recipient agent
|
||||
content: string
|
||||
type: 'requirement_update' | 'bug_report' | 'issue_fix' | 'clarification'
|
||||
}
|
||||
|
||||
interface Decision {
|
||||
id: string
|
||||
description: string
|
||||
options: string[]
|
||||
made_by?: string
|
||||
chosen_option?: string
|
||||
status: 'pending' | 'made' | 'implemented'
|
||||
}
|
||||
|
||||
interface Blocker {
|
||||
id: string
|
||||
description: string
|
||||
reported_by: string
|
||||
status: 'open' | 'resolved' | 'workaround'
|
||||
resolution?: string
|
||||
}
|
||||
```
|
||||
|
||||
## Initial State (New Cycle)
|
||||
|
||||
When creating a new cycle:
|
||||
|
||||
```json
|
||||
{
|
||||
"cycle_id": "cycle-v1-20260122T100000-abc123",
|
||||
"title": "Implement OAuth authentication",
|
||||
"description": "Add OAuth2 login support with Google and GitHub providers",
|
||||
"task_history": [
|
||||
"Implement OAuth authentication"
|
||||
],
|
||||
"status": "created",
|
||||
"created_at": "2026-01-22T10:00:00+08:00",
|
||||
"updated_at": "2026-01-22T10:00:00+08:00",
|
||||
"max_iterations": 5,
|
||||
"current_iteration": 0,
|
||||
"agents": {
|
||||
"ra": { "status": "idle", "output_files": [], "iterations_completed": 0 },
|
||||
"ep": { "status": "idle", "output_files": [], "iterations_completed": 0 },
|
||||
"cd": { "status": "idle", "output_files": [], "iterations_completed": 0 },
|
||||
"vas": { "status": "idle", "output_files": [], "iterations_completed": 0 }
|
||||
},
|
||||
"current_phase": "init",
|
||||
"completed_phases": [],
|
||||
"phase_errors": [],
|
||||
"iterations": [],
|
||||
"coordination": {
|
||||
"feedback_log": [],
|
||||
"pending_decisions": [],
|
||||
"blockers": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## State Transitions
|
||||
|
||||
### Iteration 1: Initial Execution
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "running",
|
||||
"current_iteration": 1,
|
||||
"current_phase": "ra",
|
||||
"agents": {
|
||||
"ra": { "status": "running", "started_at": "2026-01-22T10:05:00+08:00" },
|
||||
"ep": { "status": "idle" },
|
||||
"cd": { "status": "idle" },
|
||||
"vas": { "status": "idle" }
|
||||
},
|
||||
"requirements": {
|
||||
"version": "1.0.0",
|
||||
"specification": "...",
|
||||
"edge_cases": ["OAuth timeout handling", "PKCE validation"],
|
||||
"last_updated": "2026-01-22T10:15:00+08:00"
|
||||
},
|
||||
"iterations": [{
|
||||
"number": 1,
|
||||
"started_at": "2026-01-22T10:00:00+08:00",
|
||||
"agent_results": {
|
||||
"ra": { "status": "completed", "files_modified": 3 },
|
||||
"ep": { "status": "completed", "files_modified": 2 },
|
||||
"cd": { "status": "partial", "files_modified": 5 },
|
||||
"vas": { "status": "pending", "files_modified": 0 }
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### After Phase Completion
|
||||
|
||||
```json
|
||||
{
|
||||
"current_phase": "aggregation",
|
||||
"completed_phases": ["ra", "ep", "cd", "vas"],
|
||||
"plan": {
|
||||
"version": "1.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "TASK-001",
|
||||
"description": "Setup OAuth application credentials",
|
||||
"effort": "small",
|
||||
"status": "completed",
|
||||
"files": ["src/config/oauth.ts"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"changes": {
|
||||
"total_files": 12,
|
||||
"iteration_markers": {
|
||||
"1": "2026-01-22T10:30:00+08:00"
|
||||
}
|
||||
},
|
||||
"test_results": {
|
||||
"version": "1.0.0",
|
||||
"pass_rate": 85,
|
||||
"coverage": 78,
|
||||
"failed_tests": ["test: OAuth timeout retry"],
|
||||
"total_tests": 20
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Iteration 2: User Extension
|
||||
|
||||
User provides feedback: "Also add multi-factor authentication"
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "running",
|
||||
"current_iteration": 2,
|
||||
"task_history": [
|
||||
"Implement OAuth authentication",
|
||||
"Also add multi-factor authentication"
|
||||
],
|
||||
"description": "Add OAuth2 login support with Google and GitHub providers\n\n--- ITERATION 2 ---\nAlso add multi-factor authentication",
|
||||
"agents": {
|
||||
"ra": { "status": "running", "iterations_completed": 1 },
|
||||
"ep": { "status": "idle", "iterations_completed": 1 },
|
||||
"cd": { "status": "idle", "iterations_completed": 1 },
|
||||
"vas": { "status": "idle", "iterations_completed": 1 }
|
||||
},
|
||||
"requirements": {
|
||||
"version": "1.1.0",
|
||||
"specification": "...",
|
||||
"last_updated": "2026-01-22T11:00:00+08:00"
|
||||
},
|
||||
"iterations": [
|
||||
{ "number": 1, "completed_at": "..." },
|
||||
{
|
||||
"number": 2,
|
||||
"extension": "Also add multi-factor authentication",
|
||||
"started_at": "2026-01-22T10:45:00+08:00",
|
||||
"agent_results": {}
|
||||
}
|
||||
],
|
||||
"coordination": {
|
||||
"feedback_log": [{
|
||||
"timestamp": "2026-01-22T10:45:00+08:00",
|
||||
"source": "user",
|
||||
"target": "ra",
|
||||
"content": "Add multi-factor authentication to requirements",
|
||||
"type": "requirement_update"
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Version Tracking
|
||||
|
||||
Each component tracks its version:
|
||||
|
||||
- **Requirements**: `1.0.0` → `1.1.0` → `1.2.0` (each iteration)
|
||||
- **Plan**: `1.0.0` → `1.1.0` (updated based on requirements)
|
||||
- **Code**: Changes appended with iteration markers
|
||||
- **Tests**: Results tracked per iteration
|
||||
|
||||
## File Sync Protocol
|
||||
|
||||
State changes trigger file writes:
|
||||
|
||||
| State Change | File Sync |
|
||||
|--------------|-----------|
|
||||
| `requirements` updated | `.progress/ra/requirements.md` + version bump |
|
||||
| `plan` updated | `.progress/ep/plan.json` + version bump |
|
||||
| `changes` appended | `.progress/cd/changes.log` + iteration marker |
|
||||
| `test_results` updated | `.progress/vas/test-results.json` + version bump |
|
||||
| Full iteration done | `.progress/coordination/timeline.md` appended |
|
||||
|
||||
## Control Signal Checking
|
||||
|
||||
Agents check status before each action:
|
||||
|
||||
```javascript
|
||||
function checkControlSignals(cycleId) {
|
||||
const state = JSON.parse(Read(`.workflow/.cycle/${cycleId}.json`))
|
||||
|
||||
if (state.status === 'paused') {
|
||||
return { continue: false, action: 'pause' }
|
||||
}
|
||||
if (state.status === 'failed') {
|
||||
return { continue: false, action: 'stop' }
|
||||
}
|
||||
if (state.status === 'running') {
|
||||
return { continue: true, action: 'continue' }
|
||||
}
|
||||
|
||||
return { continue: false, action: 'unknown' }
|
||||
}
|
||||
```
|
||||
|
||||
## State Persistence
|
||||
|
||||
### Write Operations
|
||||
|
||||
After each agent completes or phase transitions:
|
||||
|
||||
```javascript
|
||||
Write(
|
||||
`.workflow/.cycle/${cycleId}.json`,
|
||||
JSON.stringify(state, null, 2)
|
||||
)
|
||||
```
|
||||
|
||||
### Read Operations
|
||||
|
||||
Agents always read fresh state before executing:
|
||||
|
||||
```javascript
|
||||
const currentState = JSON.parse(
|
||||
Read(`.workflow/.cycle/${cycleId}.json`)
|
||||
)
|
||||
```
|
||||
|
||||
## State Rebuild (Recovery)
|
||||
|
||||
If master state corrupted, rebuild from markdown files:
|
||||
|
||||
```javascript
|
||||
function rebuildState(cycleId) {
|
||||
const progressDir = `.workflow/.cycle/${cycleId}.progress`
|
||||
|
||||
// Read markdown files
|
||||
const raMarkdown = Read(`${progressDir}/ra/requirements.md`)
|
||||
const epMarkdown = Read(`${progressDir}/ep/plan.json`)
|
||||
const cdChanges = Read(`${progressDir}/cd/changes.log`)
|
||||
const vasResults = Read(`${progressDir}/vas/test-results.json`)
|
||||
|
||||
// Reconstruct state from files
|
||||
return {
|
||||
requirements: parseMarkdown(raMarkdown),
|
||||
plan: JSON.parse(epMarkdown),
|
||||
changes: parseNDJSON(cdChanges),
|
||||
test_results: JSON.parse(vasResults)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Immutable Reads**: Never modify state during read
|
||||
2. **Version Bumps**: Increment version on each iteration
|
||||
3. **Timestamp Accuracy**: Use UTC+8 consistently
|
||||
4. **Append-Only Logs**: Never delete history
|
||||
5. **Atomic Writes**: Write complete state, not partial updates
|
||||
6. **Coordination Tracking**: Log all inter-agent communication
|
||||
@@ -1,423 +0,0 @@
|
||||
# Agent Communication Optimization
|
||||
|
||||
优化 agent 通信机制:使用简短的产出文件引用而不是内容传递。
|
||||
|
||||
## 背景
|
||||
|
||||
在多 agent 系统中,传递完整的文件内容会导致:
|
||||
- 消息体积过大
|
||||
- 上下文使用量增加
|
||||
- 通信效率低下
|
||||
- 容易引入上下文断层
|
||||
|
||||
**优化方案**: 使用文件路径引用,让 agent 自动读取需要的文件。
|
||||
|
||||
## 优化原则
|
||||
|
||||
### 原则 1: 文件引用而非内容传递
|
||||
|
||||
❌ **错误做法**(传递内容):
|
||||
```javascript
|
||||
send_input({
|
||||
id: agents.cd,
|
||||
message: `
|
||||
Requirements:
|
||||
${requirements_content} // 完整内容 - 浪费空间
|
||||
|
||||
Plan:
|
||||
${plan_json} // 完整 JSON - 重复信息
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
✅ **正确做法**(引用文件):
|
||||
```javascript
|
||||
send_input({
|
||||
id: agents.cd,
|
||||
message: `
|
||||
## Feedback from Validation
|
||||
|
||||
Test failures found. Review these outputs:
|
||||
|
||||
## Reference
|
||||
- Requirements: .workflow/.cycle/${cycleId}.progress/ra/requirements.md (v1.0.0)
|
||||
- Plan: .workflow/.cycle/${cycleId}.progress/ep/plan.json (v1.0.0)
|
||||
- Test Results: .workflow/.cycle/${cycleId}.progress/vas/test-results.json
|
||||
|
||||
## Issues Found
|
||||
${summary_of_issues} // 只传递摘要
|
||||
|
||||
## Actions Required
|
||||
1. Fix OAuth token refresh (test line 45)
|
||||
2. Update implementation.md with fixes
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
### 原则 2: 摘要而非全文
|
||||
|
||||
❌ **错误**:
|
||||
```javascript
|
||||
// 传递所有文件内容
|
||||
RA输出: "requirements.md (2000 lines) + edge-cases.md (1000 lines) + changes.log (500 lines)"
|
||||
|
||||
EP读取: 全文解析所有内容(浪费token)
|
||||
```
|
||||
|
||||
✅ **正确**:
|
||||
```javascript
|
||||
// 只传递关键摘要
|
||||
RA输出:
|
||||
- 10个功能需求
|
||||
- 5个非功能需求
|
||||
- 8个边界场景
|
||||
- 文件路径用于完整查看
|
||||
|
||||
EP读取: 读取摘要 + 需要时查看完整文件(高效)
|
||||
```
|
||||
|
||||
### 原则 3: 文件版本跟踪
|
||||
|
||||
每个引用必须包含版本:
|
||||
|
||||
```javascript
|
||||
send_input({
|
||||
id: agents.cd,
|
||||
message: `
|
||||
Requirements: .workflow/.cycle/${cycleId}.progress/ra/requirements.md (v1.1.0)
|
||||
^^^^^^^ 版本号
|
||||
|
||||
Plan: .workflow/.cycle/${cycleId}.progress/ep/plan.json (v1.0.0)
|
||||
^^^^^^^ 版本号
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
**好处**:
|
||||
- 避免使用过期信息
|
||||
- 自动检测版本不匹配
|
||||
- 支持多版本迭代
|
||||
|
||||
## 实现模式
|
||||
|
||||
### Pattern 1: 通知 + 引用
|
||||
|
||||
Agent 向其他 agent 通知输出,而非传递内容:
|
||||
|
||||
```javascript
|
||||
// RA 输出摘要
|
||||
const raSummary = {
|
||||
requirements_count: 10,
|
||||
edge_cases_count: 8,
|
||||
version: "1.0.0",
|
||||
output_file: ".workflow/.cycle/${cycleId}.progress/ra/requirements.md",
|
||||
key_requirements: [
|
||||
"FR-001: OAuth authentication",
|
||||
"FR-002: Multi-provider support",
|
||||
"..." // 只列出标题,不传递完整内容
|
||||
]
|
||||
}
|
||||
|
||||
// 更新状态,让其他 agent 读取
|
||||
state.requirements = {
|
||||
version: raSummary.version,
|
||||
output_file: raSummary.output_file,
|
||||
summary: raSummary.key_requirements
|
||||
}
|
||||
|
||||
// EP agent 从状态读取
|
||||
const requiredDetails = state.requirements
|
||||
const outputFile = requiredDetails.output_file
|
||||
const requirements = JSON.parse(Read(outputFile)) // EP 自己读取完整文件
|
||||
```
|
||||
|
||||
### Pattern 2: 反馈通知
|
||||
|
||||
Orchestrator 发送反馈时只传递摘要和行号:
|
||||
|
||||
```javascript
|
||||
// ❌ 错误:传递完整测试结果
|
||||
send_input({
|
||||
id: agents.cd,
|
||||
message: `
|
||||
Test Results:
|
||||
${entire_test_results_json} // 完整 JSON - 太大
|
||||
`
|
||||
})
|
||||
|
||||
// ✅ 正确:引用文件 + 问题摘要
|
||||
send_input({
|
||||
id: agents.cd,
|
||||
message: `
|
||||
## Test Failures
|
||||
|
||||
Full results: .workflow/.cycle/${cycleId}.progress/vas/test-results.json (v1.0.0)
|
||||
|
||||
## Quick Summary
|
||||
- Failed: oauth-refresh (line 45, expected token refresh)
|
||||
- Failed: concurrent-login (line 78, race condition)
|
||||
|
||||
## Fix Instructions
|
||||
1. Review test cases at referenced lines
|
||||
2. Fix implementation
|
||||
3. Re-run tests
|
||||
4. Update implementation.md
|
||||
|
||||
Reference previous file paths if you need full details.
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
### Pattern 3: 依赖链路
|
||||
|
||||
Agent 通过文件引用获取依赖:
|
||||
|
||||
```javascript
|
||||
// EP agent: 从状态读取 RA 输出路径
|
||||
const raOutputPath = state.requirements?.output_file
|
||||
if (raOutputPath && exists(raOutputPath)) {
|
||||
const requirements = Read(raOutputPath)
|
||||
// 使用 requirements 生成计划
|
||||
}
|
||||
|
||||
// CD agent: 从状态读取 EP 输出路径
|
||||
const epPlanPath = state.plan?.output_file
|
||||
if (epPlanPath && exists(epPlanPath)) {
|
||||
const plan = JSON.parse(Read(epPlanPath))
|
||||
// 根据 plan 实现功能
|
||||
}
|
||||
|
||||
// VAS agent: 从状态读取 CD 输出路径
|
||||
const cdChangesPath = state.changes?.output_file
|
||||
if (cdChangesPath && exists(cdChangesPath)) {
|
||||
const changes = readNDJSON(cdChangesPath)
|
||||
// 根据 changes 生成测试
|
||||
}
|
||||
```
|
||||
|
||||
## 状态文件引用结构
|
||||
|
||||
优化后的状态文件应该包含文件路径而不是内容:
|
||||
|
||||
```json
|
||||
{
|
||||
"cycle_id": "cycle-v1-20260122-abc123",
|
||||
|
||||
"requirements": {
|
||||
"version": "1.0.0",
|
||||
"output_files": {
|
||||
"specification": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/ra/requirements.md",
|
||||
"edge_cases": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/ra/edge-cases.md",
|
||||
"changes_log": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/ra/changes.log"
|
||||
},
|
||||
"summary": {
|
||||
"functional_requirements": 10,
|
||||
"edge_cases": 8,
|
||||
"constraints": 5
|
||||
}
|
||||
},
|
||||
|
||||
"exploration": {
|
||||
"version": "1.0.0",
|
||||
"output_files": {
|
||||
"exploration": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/ep/exploration.md",
|
||||
"architecture": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/ep/architecture.md"
|
||||
},
|
||||
"summary": {
|
||||
"key_components": ["Auth Module", "User Service"],
|
||||
"integration_points": 5,
|
||||
"identified_risks": 3
|
||||
}
|
||||
},
|
||||
|
||||
"plan": {
|
||||
"version": "1.0.0",
|
||||
"output_file": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/ep/plan.json",
|
||||
"summary": {
|
||||
"total_tasks": 8,
|
||||
"critical_path": ["TASK-001", "TASK-003", "TASK-004"],
|
||||
"estimated_hours": 16
|
||||
}
|
||||
},
|
||||
|
||||
"implementation": {
|
||||
"version": "1.0.0",
|
||||
"output_files": {
|
||||
"progress": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/cd/implementation.md",
|
||||
"changes": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/cd/changes.log",
|
||||
"issues": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/cd/issues.md"
|
||||
},
|
||||
"summary": {
|
||||
"tasks_completed": 3,
|
||||
"files_modified": 5,
|
||||
"blockers": 0
|
||||
}
|
||||
},
|
||||
|
||||
"validation": {
|
||||
"version": "1.0.0",
|
||||
"output_files": {
|
||||
"validation": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/vas/validation.md",
|
||||
"test_results": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/vas/test-results.json",
|
||||
"coverage": ".workflow/.cycle/cycle-v1-20260122-abc123.progress/vas/coverage.md"
|
||||
},
|
||||
"summary": {
|
||||
"pass_rate": 92,
|
||||
"coverage": 87,
|
||||
"failures": 4
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Agent 通信模板优化
|
||||
|
||||
### 优化前: 完整内容传递
|
||||
|
||||
```javascript
|
||||
send_input({
|
||||
id: agents.cd,
|
||||
message: `
|
||||
## Requirements (Complete Content)
|
||||
|
||||
${fs.readFileSync(requirementsFile, 'utf8')} // 2000+ lines
|
||||
|
||||
## Plan (Complete JSON)
|
||||
|
||||
${fs.readFileSync(planFile, 'utf8')} // 1000+ lines
|
||||
|
||||
## Test Results (Complete)
|
||||
|
||||
${fs.readFileSync(testResultsFile, 'utf8')} // 500+ lines
|
||||
|
||||
## Your Task
|
||||
|
||||
Fix the implementation...
|
||||
` // 总消息体: 4000+ 行
|
||||
})
|
||||
```
|
||||
|
||||
### 优化后: 文件引用 + 摘要
|
||||
|
||||
```javascript
|
||||
send_input({
|
||||
id: agents.cd,
|
||||
message: `
|
||||
## Test Failures - Action Required
|
||||
|
||||
Full Test Report: .workflow/.cycle/${cycleId}.progress/vas/test-results.json (v1.0.0)
|
||||
|
||||
## Summary of Failures
|
||||
- oauth-refresh: Expected token refresh, got error (test line 45)
|
||||
- concurrent-login: Race condition in session writes (test line 78)
|
||||
|
||||
## Implementation Reference
|
||||
- Current Code: .workflow/.cycle/${cycleId}.progress/cd/implementation.md (v1.0.0)
|
||||
- Code Changes: .workflow/.cycle/${cycleId}.progress/cd/changes.log (v1.0.0)
|
||||
|
||||
## Action Required
|
||||
1. Review failing tests in referenced test results file
|
||||
2. Fix root causes (race condition, token handling)
|
||||
3. Update implementation.md with fixes
|
||||
4. Re-run tests
|
||||
|
||||
## Context
|
||||
- Requirement: .workflow/.cycle/${cycleId}.progress/ra/requirements.md (v1.0.0)
|
||||
- Plan: .workflow/.cycle/${cycleId}.progress/ep/plan.json (v1.0.0)
|
||||
|
||||
Output PHASE_RESULT when complete.
|
||||
` // 总消息体: <500 行,高效传递
|
||||
})
|
||||
```
|
||||
|
||||
## 版本控制最佳实践
|
||||
|
||||
### 版本不匹配检测
|
||||
|
||||
```javascript
|
||||
function validateVersionConsistency(state) {
|
||||
const versions = {
|
||||
ra: state.requirements?.version,
|
||||
ep: state.plan?.version,
|
||||
cd: state.implementation?.version,
|
||||
vas: state.validation?.version
|
||||
}
|
||||
|
||||
// 检查版本一致性
|
||||
const allVersions = Object.values(versions).filter(v => v)
|
||||
const unique = new Set(allVersions)
|
||||
|
||||
if (unique.size > 1) {
|
||||
console.warn('Version mismatch detected:')
|
||||
console.warn(versions)
|
||||
// 返回版本差异,让 orchestrator 决定是否继续
|
||||
}
|
||||
|
||||
return unique.size === 1
|
||||
}
|
||||
```
|
||||
|
||||
### 文件存在性检查
|
||||
|
||||
```javascript
|
||||
function validateReferences(state, cycleId) {
|
||||
const checks = []
|
||||
|
||||
// 检查所有引用的文件是否存在
|
||||
for (const [agent, data] of Object.entries(state)) {
|
||||
if (data?.output_files) {
|
||||
for (const [name, path] of Object.entries(data.output_files)) {
|
||||
if (!fs.existsSync(path)) {
|
||||
checks.push({
|
||||
agent: agent,
|
||||
file: name,
|
||||
path: path,
|
||||
status: 'missing'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return checks
|
||||
}
|
||||
```
|
||||
|
||||
## 好处总结
|
||||
|
||||
| 方面 | 改进 |
|
||||
|------|------|
|
||||
| 消息体积 | 减少 80-90% |
|
||||
| Token 使用 | 减少 60-70% |
|
||||
| 读取速度 | 无需解析冗余内容 |
|
||||
| 版本控制 | 清晰的版本跟踪 |
|
||||
| 上下文清晰 | 不会混淆版本 |
|
||||
| 可维护性 | 文件变更不需要修改消息 |
|
||||
|
||||
## 迁移建议
|
||||
|
||||
### 第一步: 更新状态结构
|
||||
|
||||
```json
|
||||
// 从这样:
|
||||
"requirements": "完整内容"
|
||||
|
||||
// 改为这样:
|
||||
"requirements": {
|
||||
"version": "1.0.0",
|
||||
"output_file": "path/to/file",
|
||||
"summary": {...}
|
||||
}
|
||||
```
|
||||
|
||||
### 第二步: 更新通信模板
|
||||
|
||||
所有 `send_input` 消息改为引用路径。
|
||||
|
||||
### 第三步: Agent 自动读取
|
||||
|
||||
Agent 从引用路径自动读取所需文件。
|
||||
|
||||
### 第四步: 测试版本检测
|
||||
|
||||
确保版本不匹配时有警告。
|
||||
@@ -1,406 +0,0 @@
|
||||
# Coordination Protocol - Multi-Agent Communication
|
||||
|
||||
Inter-agent communication protocols and patterns for parallel-dev-cycle skill.
|
||||
|
||||
## Overview
|
||||
|
||||
The coordination protocol enables four parallel agents (RA, EP, CD, VAS) to communicate efficiently while maintaining clear responsibilities and avoiding conflicts.
|
||||
|
||||
## Communication Channels
|
||||
|
||||
### 1. Shared State File (Primary)
|
||||
|
||||
**Location**: `.workflow/.cycle/{cycleId}.json`
|
||||
|
||||
**Access Pattern**:
|
||||
- **Agents**: READ ONLY - check dependencies and status
|
||||
- **Orchestrator**: READ-WRITE - updates state after each phase
|
||||
|
||||
```javascript
|
||||
// Every agent: Read state to check dependencies
|
||||
const state = JSON.parse(Read(`.workflow/.cycle/${cycleId}.json`))
|
||||
const canProceed = checkDependencies(state)
|
||||
|
||||
// Agent outputs PHASE_RESULT (reports to orchestrator, NOT writes directly)
|
||||
console.log("PHASE_RESULT: ...")
|
||||
|
||||
// Only Orchestrator writes to state file after receiving PHASE_RESULT
|
||||
// Write(`.workflow/.cycle/${cycleId}.json`, JSON.stringify(updatedState, null, 2))
|
||||
```
|
||||
|
||||
**Protocol**:
|
||||
- Only orchestrator writes to state file (no concurrent writes, no lock needed)
|
||||
- Agents read state to understand dependencies
|
||||
- Timestamp all orchestrator updates with ISO8601 format
|
||||
- Never delete existing data, only append
|
||||
|
||||
### 2. Progress Markdown Files (Async Log)
|
||||
|
||||
**Location**: `.workflow/.cycle/{cycleId}.progress/{agent}/`
|
||||
|
||||
Each agent writes progress to dedicated markdown files:
|
||||
|
||||
| Agent | Main Documents (Rewrite) | Logs (Append-Only) |
|
||||
|-------|--------------------------|-------------------|
|
||||
| RA | requirements.md | changes.log |
|
||||
| EP | exploration.md, architecture.md, plan.json | changes.log |
|
||||
| CD | implementation.md, issues.md | changes.log, debug-log.ndjson |
|
||||
| VAS | validation.md, summary.md, test-results.json | changes.log |
|
||||
|
||||
**Protocol**:
|
||||
- **Main documents**: Complete rewrite per iteration, archived to `history/`
|
||||
- **Log files**: Append-only (changes.log, debug-log.ndjson) - never delete
|
||||
- **Version synchronization**: All main documents share same version (e.g., all v1.1.0 in iteration 2)
|
||||
- Include timestamp on each update
|
||||
|
||||
### 3. Orchestrator send_input (Synchronous)
|
||||
|
||||
**When**: Orchestrator needs to send feedback or corrections
|
||||
|
||||
```javascript
|
||||
// Example: CD agent receives test failure feedback
|
||||
send_input({
|
||||
id: agents.cd,
|
||||
message: `
|
||||
## FEEDBACK FROM VALIDATION
|
||||
|
||||
Test failures detected: ${failures}
|
||||
|
||||
## REQUIRED ACTION
|
||||
|
||||
Fix the following:
|
||||
${actionItems}
|
||||
|
||||
## NEXT STEP
|
||||
Update implementation.md with fixes, then re-run tests.
|
||||
Output PHASE_RESULT when complete.
|
||||
`
|
||||
})
|
||||
```
|
||||
|
||||
**Protocol**:
|
||||
- Only orchestrator initiates send_input
|
||||
- Clear action items and expected output
|
||||
- Single message per iteration (no rapid-fire sends)
|
||||
|
||||
### 4. Coordination Log
|
||||
|
||||
**Location**: `.workflow/.cycle/{cycleId}.progress/coordination/`
|
||||
|
||||
Centralized log for inter-agent decisions and communication:
|
||||
|
||||
**feedback.md**:
|
||||
```markdown
|
||||
# Feedback & Coordination Log - Version X.Y.Z
|
||||
|
||||
## Timeline
|
||||
- [10:00:00] Orchestrator: Created cycle
|
||||
- [10:05:00] RA: Requirements analysis started
|
||||
- [10:10:00] RA: Requirements completed, v1.0.0
|
||||
- [10:10:01] EP: Starting exploration (depends on RA output)
|
||||
- [10:15:00] EP: Architecture designed, plan.json v1.0.0
|
||||
- [10:15:01] CD: Starting implementation (depends on EP plan)
|
||||
- [10:30:00] CD: Implementation progressing, found blocker
|
||||
- [10:31:00] RA: Clarified requirement after CD blocker
|
||||
- [10:31:01] CD: Continuing with clarification
|
||||
- [10:40:00] CD: Implementation complete
|
||||
- [10:40:01] VAS: Starting validation
|
||||
- [10:45:00] VAS: Testing complete, found failures
|
||||
- [10:45:01] Orchestrator: Sending feedback to CD
|
||||
- [10:46:00] CD: Fixed issues
|
||||
- [10:50:00] VAS: Re-validation, all passing
|
||||
- [10:50:01] Orchestrator: Cycle complete
|
||||
|
||||
## Decision Records
|
||||
- [10:31:00] RA Clarification: OAuth optional vs required?
|
||||
- Decision: Optional (can use password)
|
||||
- Rationale: More flexible for users
|
||||
- Impact: Affects FR-003 implementation
|
||||
|
||||
## Blockers & Resolutions
|
||||
- [10:30:00] Blocker: Database migration for existing users
|
||||
- Reported by: CD
|
||||
- Resolution: Set oauth_id = null for existing users
|
||||
- Status: Resolved
|
||||
|
||||
## Cross-Agent Dependencies
|
||||
- EP depends on: RA requirements (v1.0.0)
|
||||
- CD depends on: EP plan (v1.0.0)
|
||||
- VAS depends on: CD code changes
|
||||
```
|
||||
|
||||
## Message Formats
|
||||
|
||||
### Agent Status Update
|
||||
|
||||
Each agent updates state with its status:
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"ra": {
|
||||
"status": "completed",
|
||||
"started_at": "2026-01-22T10:05:00+08:00",
|
||||
"completed_at": "2026-01-22T10:15:00+08:00",
|
||||
"output_files": [
|
||||
".workflow/.cycle/cycle-xxx.progress/ra/requirements.md",
|
||||
".workflow/.cycle/cycle-xxx.progress/ra/edge-cases.md",
|
||||
".workflow/.cycle/cycle-xxx.progress/ra/changes.log"
|
||||
],
|
||||
"iterations_completed": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Feedback Message Format
|
||||
|
||||
When orchestrator sends feedback via send_input:
|
||||
|
||||
```text
|
||||
## FEEDBACK FROM [Agent Name]
|
||||
|
||||
[Summary of findings or issues]
|
||||
|
||||
## REFERENCED OUTPUT
|
||||
File: [path to agent output]
|
||||
Version: [X.Y.Z]
|
||||
|
||||
## REQUIRED ACTION
|
||||
|
||||
1. [Action 1 with specific details]
|
||||
2. [Action 2 with specific details]
|
||||
|
||||
## SUCCESS CRITERIA
|
||||
|
||||
- [ ] Item 1
|
||||
- [ ] Item 2
|
||||
|
||||
## NEXT STEP
|
||||
[What agent should do next]
|
||||
Output PHASE_RESULT when complete.
|
||||
|
||||
## CONTEXT
|
||||
|
||||
Previous iteration: [N]
|
||||
Current iteration: [N+1]
|
||||
```
|
||||
|
||||
### Phase Result Format
|
||||
|
||||
Every agent outputs PHASE_RESULT:
|
||||
|
||||
```text
|
||||
PHASE_RESULT:
|
||||
- phase: [ra|ep|cd|vas]
|
||||
- status: success | failed | partial
|
||||
- files_written: [list of files]
|
||||
- summary: [one-line summary]
|
||||
- [agent-specific fields]
|
||||
- issues: [list of issues if any]
|
||||
|
||||
PHASE_DETAILS:
|
||||
[Additional details or metrics]
|
||||
```
|
||||
|
||||
## Dependency Resolution
|
||||
|
||||
**Execution Model**: All four agents are spawned in parallel, but execution blocks based on dependencies. Orchestrator manages dependency resolution via shared state.
|
||||
|
||||
### Build Order (Default)
|
||||
|
||||
```
|
||||
RA (Requirements) → EP (Planning) → CD (Development) → VAS (Validation)
|
||||
↓ ↓ ↓ ↓
|
||||
Block EP Block CD Block VAS Block completion
|
||||
```
|
||||
|
||||
**Explanation**:
|
||||
- All agents spawned simultaneously
|
||||
- Each agent checks dependencies in shared state before proceeding
|
||||
- Blocked agents wait for dependency completion
|
||||
- Orchestrator uses `send_input` to notify dependent agents when ready
|
||||
|
||||
### Parallel Opportunities
|
||||
|
||||
Some phases can run in parallel:
|
||||
|
||||
```
|
||||
RA + FrontendCode (independent)
|
||||
EP + RA (not blocking)
|
||||
CD.Task1 + CD.Task2 (if no dependencies)
|
||||
```
|
||||
|
||||
### Dependency Tracking
|
||||
|
||||
State file tracks dependencies:
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"ep": {
|
||||
"depends_on": ["ra"],
|
||||
"ready": true, // RA completed
|
||||
"can_start": true
|
||||
},
|
||||
"cd": {
|
||||
"depends_on": ["ep"],
|
||||
"ready": true, // EP completed
|
||||
"can_start": true
|
||||
},
|
||||
"vas": {
|
||||
"depends_on": ["cd"],
|
||||
"ready": false, // CD not yet complete
|
||||
"can_start": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Iteration Flow with Communication
|
||||
|
||||
### Iteration 1: Initial Execution
|
||||
|
||||
```
|
||||
Time Agent Action State Update
|
||||
──────────────────────────────────────────────────────
|
||||
10:00 Init Create cycle status: running
|
||||
10:05 RA Start analysis agents.ra.status: running
|
||||
10:10 RA Complete (v1.0.0) agents.ra.status: completed
|
||||
10:10 EP Start planning agents.ep.status: running
|
||||
(depends on RA completion)
|
||||
10:15 EP Complete (v1.0.0) agents.ep.status: completed
|
||||
10:15 CD Start development agents.cd.status: running
|
||||
(depends on EP completion)
|
||||
10:30 CD Found blocker coordination.blockers.add()
|
||||
10:31 RA Clarify blocker requirements.v1.1.0 created
|
||||
10:35 CD Continue (with fix) agents.cd.status: running
|
||||
10:40 CD Complete agents.cd.status: completed
|
||||
10:40 VAS Start validation agents.vas.status: running
|
||||
(depends on CD completion)
|
||||
10:45 VAS Tests failing coordination.feedback_log.add()
|
||||
10:45 Orch Send feedback agents.cd.message: "Fix these tests"
|
||||
10:46 CD Resume (send_input) agents.cd.status: running
|
||||
10:48 CD Fix complete agents.cd.status: completed
|
||||
10:50 VAS Re-validate agents.vas.status: running
|
||||
10:55 VAS All pass agents.vas.status: completed
|
||||
11:00 Orch Complete cycle status: completed
|
||||
```
|
||||
|
||||
## Conflict Resolution
|
||||
|
||||
### Conflict Type 1: Unclear Requirement
|
||||
|
||||
**Scenario**: CD needs clarification on FR-X
|
||||
|
||||
**Resolution Flow**:
|
||||
1. CD reports blocker in issues.md
|
||||
2. Orchestrator extracts blocker
|
||||
3. Orchestrator sends message to RA
|
||||
4. RA updates requirements with clarification
|
||||
5. RA outputs new requirements.md (v1.1.0)
|
||||
6. Orchestrator sends message to CD with clarification
|
||||
7. CD resumes and continues
|
||||
|
||||
### Conflict Type 2: Test Failure
|
||||
|
||||
**Scenario**: VAS finds test failures
|
||||
|
||||
**Resolution Flow**:
|
||||
1. VAS reports failures in validation.md
|
||||
2. VAS outputs test-results.json with details
|
||||
3. Orchestrator extracts failure details
|
||||
4. Orchestrator categorizes failures
|
||||
5. If blocker: Orchestrator sends to CD/RA for fixes
|
||||
6. CD/RA fix and report completion
|
||||
7. Orchestrator sends CD/VAS to retry
|
||||
8. VAS re-validates
|
||||
|
||||
### Conflict Type 3: Plan Mismatch
|
||||
|
||||
**Scenario**: CD realizes plan tasks are incomplete
|
||||
|
||||
**Resolution Flow**:
|
||||
1. CD reports in issues.md
|
||||
2. Orchestrator extracts issue
|
||||
3. Orchestrator sends to EP to revise plan
|
||||
4. EP updates plan.json (v1.1.0)
|
||||
5. EP adds new tasks or dependencies
|
||||
6. Orchestrator sends to CD with updated plan
|
||||
7. CD implements remaining tasks
|
||||
|
||||
## Escalation Path
|
||||
|
||||
For issues that block resolution:
|
||||
|
||||
```
|
||||
Agent Issue
|
||||
↓
|
||||
Agent reports blocker
|
||||
↓
|
||||
Orchestrator analyzes
|
||||
↓
|
||||
Can fix automatically?
|
||||
├─ Yes: send_input to agent with fix
|
||||
└─ No: Escalate to user
|
||||
↓
|
||||
User provides guidance
|
||||
↓
|
||||
Orchestrator applies guidance
|
||||
↓
|
||||
Resume agents
|
||||
```
|
||||
|
||||
## Communication Best Practices
|
||||
|
||||
1. **Clear Timestamps**: All events timestamped ISO8601 format
|
||||
2. **Structured Messages**: Use consistent format for feedback
|
||||
3. **Version Tracking**: Always include version numbers
|
||||
4. **Audit Trail**: Maintain complete log of decisions
|
||||
5. **No Direct Agent Communication**: All communication via orchestrator
|
||||
6. **Document Decisions**: Record why decisions were made
|
||||
7. **Append-Only Logs**: Never delete history
|
||||
|
||||
## State Consistency Rules
|
||||
|
||||
1. **Single Writer Per Field**: Only one agent updates each field
|
||||
- RA writes: requirements, edge_cases
|
||||
- EP writes: exploration, plan
|
||||
- CD writes: changes, implementation
|
||||
- VAS writes: test_results, summary
|
||||
|
||||
2. **Read-Write Serialization**: Orchestrator ensures no conflicts
|
||||
|
||||
3. **Version Synchronization**: All versions increment together
|
||||
- v1.0.0 → v1.1.0 (all docs updated)
|
||||
|
||||
4. **Timestamp Consistency**: All timestamps in state file UTC+8
|
||||
|
||||
## Monitoring & Debugging
|
||||
|
||||
### State Inspection
|
||||
|
||||
```javascript
|
||||
// Check agent status
|
||||
const state = JSON.parse(Read(`.workflow/.cycle/${cycleId}.json`))
|
||||
console.log(state.agents) // See status of all agents
|
||||
|
||||
// Check for blockers
|
||||
console.log(state.coordination.blockers)
|
||||
|
||||
// Check feedback history
|
||||
console.log(state.coordination.feedback_log)
|
||||
```
|
||||
|
||||
### Log Analysis
|
||||
|
||||
```bash
|
||||
# Check RA progress
|
||||
tail .workflow/.cycle/cycle-xxx.progress/ra/changes.log
|
||||
|
||||
# Check CD changes
|
||||
grep "TASK-001" .workflow/.cycle/cycle-xxx.progress/cd/changes.log
|
||||
|
||||
# Check coordination timeline
|
||||
tail -50 .workflow/.cycle/cycle-xxx.progress/coordination/feedback.md
|
||||
```
|
||||
@@ -1,331 +0,0 @@
|
||||
# Document Versioning Strategy
|
||||
|
||||
Document version management strategy: Complete Rewrite + Archive History
|
||||
|
||||
## Recommended Approach: Complete Rewrite + Archive History
|
||||
|
||||
For each iteration, **completely rewrite** the main document, and automatically archive the old version to the `history/` directory.
|
||||
|
||||
### File Structure
|
||||
|
||||
```
|
||||
.workflow/.cycle/cycle-v1-20260122-abc123.progress/
|
||||
├── ra/
|
||||
│ ├── requirements.md # v1.2.0 (current version, complete rewrite)
|
||||
│ ├── edge-cases.md # v1.2.0 (current version, complete rewrite)
|
||||
│ ├── changes.log # NDJSON complete change history (append-only)
|
||||
│ └── history/
|
||||
│ ├── requirements-v1.0.0.md (archived)
|
||||
│ ├── requirements-v1.1.0.md (archived)
|
||||
│ ├── edge-cases-v1.0.0.md (archived)
|
||||
│ └── edge-cases-v1.1.0.md (archived)
|
||||
├── ep/
|
||||
│ ├── exploration.md # v1.2.0 (current)
|
||||
│ ├── architecture.md # v1.2.0 (current)
|
||||
│ ├── plan.json # v1.2.0 (current)
|
||||
│ └── history/
|
||||
│ ├── plan-v1.0.0.json
|
||||
│ └── plan-v1.1.0.json
|
||||
├── cd/
|
||||
│ ├── implementation.md # v1.2.0 (current)
|
||||
│ ├── changes.log # NDJSON complete history
|
||||
│ ├── debug-log.ndjson # Debug hypothesis tracking
|
||||
│ ├── issues.md # Current unresolved issues
|
||||
│ └── history/
|
||||
│ ├── implementation-v1.0.0.md
|
||||
│ └── implementation-v1.1.0.md
|
||||
└── vas/
|
||||
├── validation.md # v1.2.0 (current)
|
||||
├── test-results.json # v1.2.0 (current)
|
||||
├── summary.md # v1.2.0 (current)
|
||||
└── history/
|
||||
├── validation-v1.0.0.md
|
||||
└── test-results-v1.0.0.json
|
||||
```
|
||||
|
||||
## Optimized Document Template
|
||||
|
||||
### Requirements.md (Complete Rewrite Version)
|
||||
|
||||
```markdown
|
||||
# Requirements Specification - v1.2.0
|
||||
|
||||
## Document Metadata
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Version | 1.2.0 |
|
||||
| Previous | 1.1.0 (Added Google OAuth) |
|
||||
| Changes | Added MFA, GitHub provider |
|
||||
| Date | 2026-01-23T10:00:00+08:00 |
|
||||
| Cycle | cycle-v1-20260122-abc123 |
|
||||
| Iteration | 3 |
|
||||
|
||||
---
|
||||
|
||||
## Functional Requirements
|
||||
|
||||
### FR-001: OAuth Authentication
|
||||
**Description**: Users can log in using OAuth providers.
|
||||
|
||||
**Supported Providers**: Google, GitHub
|
||||
|
||||
**Priority**: High
|
||||
|
||||
**Status**: ✓ Implemented (v1.0.0), Enhanced (v1.1.0, v1.2.0)
|
||||
|
||||
**Success Criteria**:
|
||||
- User can click provider button
|
||||
- Redirect to provider
|
||||
- Return with valid token
|
||||
- Session created
|
||||
|
||||
---
|
||||
|
||||
### FR-002: Multi-Provider Support
|
||||
**Description**: System supports multiple OAuth providers simultaneously.
|
||||
|
||||
**Providers**:
|
||||
- Google (v1.1.0)
|
||||
- GitHub (v1.2.0)
|
||||
|
||||
**Priority**: High
|
||||
|
||||
**Status**: ✓ Implemented
|
||||
|
||||
---
|
||||
|
||||
### FR-003: Multi-Factor Authentication
|
||||
**Description**: Optional MFA for enhanced security.
|
||||
|
||||
**Method**: TOTP (Time-based One-Time Password)
|
||||
|
||||
**Priority**: Medium
|
||||
|
||||
**Status**: 🆕 New in v1.2.0
|
||||
|
||||
**Success Criteria**:
|
||||
- User can enable MFA in settings
|
||||
- TOTP QR code generated
|
||||
- Verification on login
|
||||
|
||||
---
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
### NFR-001: Performance
|
||||
Response time < 500ms for all OAuth flows.
|
||||
|
||||
**Status**: ✓ Met (v1.0.0)
|
||||
|
||||
---
|
||||
|
||||
## Edge Cases
|
||||
|
||||
### EC-001: OAuth Provider Timeout
|
||||
**Scenario**: Provider doesn't respond in 5 seconds
|
||||
|
||||
**Expected**: Display error, offer retry
|
||||
|
||||
**Status**: ✓ Handled
|
||||
|
||||
---
|
||||
|
||||
### EC-002: Invalid MFA Code (NEW v1.2.0)
|
||||
**Scenario**: User enters incorrect TOTP code
|
||||
|
||||
**Expected**: Display error, max 3 attempts, lock after
|
||||
|
||||
**Status**: 🔄 To be implemented
|
||||
|
||||
---
|
||||
|
||||
## Constraints
|
||||
- Must use existing JWT session management
|
||||
- No new database servers
|
||||
- Compatible with existing user table
|
||||
|
||||
---
|
||||
|
||||
## Assumptions
|
||||
- Users have access to authenticator app for MFA
|
||||
- OAuth providers are always available
|
||||
|
||||
---
|
||||
|
||||
## Version History Summary
|
||||
|
||||
| Version | Date | Summary |
|
||||
|---------|------|---------|
|
||||
| 1.0.0 | 2026-01-22 | Initial OAuth login (Google only implicit) |
|
||||
| 1.1.0 | 2026-01-22 | + Explicit Google OAuth support |
|
||||
| 1.2.0 | 2026-01-23 | + GitHub provider, + MFA (current) |
|
||||
|
||||
**Detailed History**: See `history/` directory and `changes.log`
|
||||
```
|
||||
|
||||
### Changes.log (NDJSON - Complete History)
|
||||
|
||||
```jsonl
|
||||
{"timestamp":"2026-01-22T10:00:00+08:00","iteration":1,"version":"1.0.0","action":"create","type":"requirement","id":"FR-001","description":"Initial OAuth requirement"}
|
||||
{"timestamp":"2026-01-22T10:05:00+08:00","iteration":1,"version":"1.0.0","action":"create","type":"requirement","id":"NFR-001","description":"Performance requirement"}
|
||||
{"timestamp":"2026-01-22T11:00:00+08:00","iteration":2,"version":"1.1.0","action":"update","type":"requirement","id":"FR-001","description":"Clarified Google OAuth support"}
|
||||
{"timestamp":"2026-01-22T11:05:00+08:00","iteration":2,"version":"1.1.0","action":"create","type":"requirement","id":"FR-002","description":"Multi-provider support"}
|
||||
{"timestamp":"2026-01-23T10:00:00+08:00","iteration":3,"version":"1.2.0","action":"create","type":"requirement","id":"FR-003","description":"MFA requirement"}
|
||||
{"timestamp":"2026-01-23T10:05:00+08:00","iteration":3,"version":"1.2.0","action":"update","type":"requirement","id":"FR-002","description":"Added GitHub provider"}
|
||||
```
|
||||
|
||||
## Implementation Flow
|
||||
|
||||
### Agent Workflow (RA Example)
|
||||
|
||||
```javascript
|
||||
// ==================== RA Agent Iteration Flow ====================
|
||||
|
||||
// Read current state
|
||||
const state = JSON.parse(Read(`.workflow/.cycle/${cycleId}.json`))
|
||||
const currentVersion = state.requirements?.version || "0.0.0"
|
||||
const iteration = state.current_iteration
|
||||
|
||||
// If iteration (old version exists)
|
||||
if (currentVersion !== "0.0.0") {
|
||||
// 1. Archive old version
|
||||
const oldFile = `.workflow/.cycle/${cycleId}.progress/ra/requirements.md`
|
||||
const archiveFile = `.workflow/.cycle/${cycleId}.progress/ra/history/requirements-v${currentVersion}.md`
|
||||
|
||||
Copy(oldFile, archiveFile) // Archive
|
||||
|
||||
// 2. Read old version (optional, for context understanding)
|
||||
const oldRequirements = Read(oldFile)
|
||||
|
||||
// 3. Read change history
|
||||
const changesLog = readNDJSON(`.workflow/.cycle/${cycleId}.progress/ra/changes.log`)
|
||||
}
|
||||
|
||||
// 4. Generate new version number
|
||||
const newVersion = bumpVersion(currentVersion, 'minor') // 1.1.0 -> 1.2.0
|
||||
|
||||
// 5. Generate new document (complete rewrite)
|
||||
const newRequirements = generateRequirements({
|
||||
version: newVersion,
|
||||
previousVersion: currentVersion,
|
||||
previousSummary: "Added Google OAuth support",
|
||||
currentChanges: "Added MFA and GitHub provider",
|
||||
iteration: iteration,
|
||||
taskDescription: state.description,
|
||||
changesLog: changesLog // For understanding history
|
||||
})
|
||||
|
||||
// 6. Write new document (overwrite old)
|
||||
Write(`.workflow/.cycle/${cycleId}.progress/ra/requirements.md`, newRequirements)
|
||||
|
||||
// 7. Append change to changes.log
|
||||
appendNDJSON(`.workflow/.cycle/${cycleId}.progress/ra/changes.log`, {
|
||||
timestamp: getUtc8ISOString(),
|
||||
iteration: iteration,
|
||||
version: newVersion,
|
||||
action: "create",
|
||||
type: "requirement",
|
||||
id: "FR-003",
|
||||
description: "Added MFA requirement"
|
||||
})
|
||||
|
||||
// 8. Update state
|
||||
state.requirements = {
|
||||
version: newVersion,
|
||||
output_file: `.workflow/.cycle/${cycleId}.progress/ra/requirements.md`,
|
||||
summary: {
|
||||
functional_requirements: 3,
|
||||
edge_cases: 2,
|
||||
constraints: 3
|
||||
}
|
||||
}
|
||||
|
||||
Write(`.workflow/.cycle/${cycleId}.json`, JSON.stringify(state, null, 2))
|
||||
```
|
||||
|
||||
## Advantages Comparison
|
||||
|
||||
| Aspect | Incremental Update | Complete Rewrite + Archive |
|
||||
|--------|-------------------|---------------------------|
|
||||
| **Document Conciseness** | ❌ Gets longer | ✅ Always concise |
|
||||
| **Agent Parsing** | ❌ Must parse history | ✅ Only read current version |
|
||||
| **Maintenance Complexity** | ❌ High (version marking) | ✅ Low (direct rewrite) |
|
||||
| **File Size** | ❌ Bloats | ✅ Fixed |
|
||||
| **History Tracking** | ✅ In main document | ✅ In history/ + changes.log |
|
||||
| **Human Readability** | ❌ Must skip history | ✅ Direct current view |
|
||||
| **Token Usage** | ❌ More (read complete history) | ✅ Less (only read current) |
|
||||
|
||||
## Archive Strategy
|
||||
|
||||
### Auto-Archive Trigger
|
||||
|
||||
```javascript
|
||||
function shouldArchive(currentVersion, state) {
|
||||
// Archive on each version update
|
||||
return currentVersion !== state.requirements?.version
|
||||
}
|
||||
|
||||
function archiveOldVersion(cycleId, agent, filename, currentVersion) {
|
||||
const currentFile = `.workflow/.cycle/${cycleId}.progress/${agent}/${filename}`
|
||||
const archiveDir = `.workflow/.cycle/${cycleId}.progress/${agent}/history`
|
||||
const archiveFile = `${archiveDir}/${filename.replace('.', `-v${currentVersion}.`)}`
|
||||
|
||||
// Ensure archive directory exists
|
||||
mkdir -p ${archiveDir}
|
||||
|
||||
// Copy (not move, keep current file until new version written)
|
||||
Copy(currentFile, archiveFile)
|
||||
|
||||
console.log(`Archived ${filename} v${currentVersion} to history/`)
|
||||
}
|
||||
```
|
||||
|
||||
### Cleanup Strategy (Optional)
|
||||
|
||||
Keep most recent N versions, delete older archives:
|
||||
|
||||
```javascript
|
||||
function cleanupArchives(cycleId, agent, keepVersions = 3) {
|
||||
const historyDir = `.workflow/.cycle/${cycleId}.progress/${agent}/history`
|
||||
const archives = listFiles(historyDir)
|
||||
|
||||
// Sort by version number
|
||||
archives.sort((a, b) => compareVersions(extractVersion(a), extractVersion(b)))
|
||||
|
||||
// Delete oldest versions (keep most recent N)
|
||||
if (archives.length > keepVersions) {
|
||||
const toDelete = archives.slice(0, archives.length - keepVersions)
|
||||
toDelete.forEach(file => Delete(`${historyDir}/${file}`))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Importance of Changes.log
|
||||
|
||||
Although main document is completely rewritten, **changes.log (NDJSON) permanently preserves complete history**:
|
||||
|
||||
```bash
|
||||
# View all changes
|
||||
cat .workflow/.cycle/cycle-xxx.progress/ra/changes.log | jq .
|
||||
|
||||
# View history of specific requirement
|
||||
cat .workflow/.cycle/cycle-xxx.progress/ra/changes.log | jq 'select(.id=="FR-001")'
|
||||
|
||||
# View changes by iteration
|
||||
cat .workflow/.cycle/cycle-xxx.progress/ra/changes.log | jq 'select(.iteration==2)'
|
||||
```
|
||||
|
||||
This way:
|
||||
- **Main Document**: Clear and concise (current state)
|
||||
- **Changes.log**: Complete traceability (all history)
|
||||
- **History/**: Snapshot backups (view on demand)
|
||||
|
||||
## Recommended Implementation
|
||||
|
||||
1. ✅ Adopt "Complete Rewrite" strategy
|
||||
2. ✅ Main document only keeps "previous version summary"
|
||||
3. ✅ Auto-archive to `history/` directory
|
||||
4. ✅ Changes.log (NDJSON) preserves complete history
|
||||
5. ✅ Optional: Keep most recent 3-5 historical versions
|
||||
|
||||
This approach keeps documents concise (agent-friendly) while preserving complete history (audit-friendly).
|
||||
Reference in New Issue
Block a user