feat(skills): update 12 team skills to v3 design patterns

- Update all 12 team-* SKILL.md files with v3 structure:
  - Replace JS pseudocode with text decision tables
  - Add Role Registry with Compact column
  - Add COMPACT PROTECTION blocks
  - Add Cadence Control sections
  - Add Wisdom Accumulation sections
  - Add Task Metadata Registry
  - Add Orchestration Mode user commands

- Update 58 role files (SKILL.md + roles/*):
  - Flat-file skills: team-brainstorm, team-issue, team-testing,
    team-uidesign, team-planex, team-iterdev
  - Folder-based skills: team-review, team-roadmap-dev, team-frontend,
    team-quality-assurance, team-tech-debt, team-ultra-analyze

- Preserve special architectures:
  - team-planex: 2-member (planner + executor only)
  - team-tech-debt: Stop-Wait strategy (run_in_background:false)
  - team-iterdev: 7 behavior protocol tables in coordinator

- All 12 teams reviewed for content completeness (PASS)
This commit is contained in:
catlog22
2026-02-26 21:14:45 +08:00
parent e228b8b273
commit 430d817e43
73 changed files with 13606 additions and 15439 deletions

View File

@@ -6,157 +6,145 @@ allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), Task
# Team Brainstorm
头脑风暴团队技能。通过 Generator-Critic 循环、共享记忆和动态管道选择,实现多角度创意发散、挑战验证和收敛筛选。所有团队成员通过 `--role=xxx` 路由到角色执行逻辑。
Unified team skill: multi-angle brainstorming via Generator-Critic loops, shared memory, and dynamic pipeline selection. All team members invoke with `--role=xxx` to route to role-specific execution.
## Architecture Overview
## Architecture
```
┌───────────────────────────────────────────────────┐
│ Skill(skill="team-brainstorm", args="--role=xxx")
│ Skill(skill="team-brainstorm")
│ args="<topic>" or args="--role=xxx" │
└───────────────────┬───────────────────────────────┘
│ Role Router
┌───────────┬───┼───────────┬───────────┐
↓ ↓
┌──────────┐┌───────┐┌──────────┐┌──────────┐┌─────────┐
│coordinator││ideator││challenger││synthesizer││evaluator│
│ roles/ ││roles/ ││ roles/ ││ roles/ ││ roles/ │
└──────────┘└───────┘└──────────┘└──────────┘└─────────┘
┌──── --role present? ────┐
│ NO │ YES
↓ ↓
Orchestration Mode Role Dispatch
(auto → coordinator) (route to role.md)
┌────┴────┬───────────┬───────────┬───────────┐
↓ ↓ ↓ ↓ ↓
┌──────────┐┌─────────┐┌──────────┐┌──────────┐┌─────────┐
│coordinator││ ideator ││challenger││synthesizer││evaluator│
│ ││ IDEA-* ││CHALLENGE-*││ SYNTH-* ││ EVAL-* │
└──────────┘└─────────┘└──────────┘└──────────┘└─────────┘
```
## Role Router
### Input Parsing
Parse `$ARGUMENTS` to extract `--role`:
Parse `$ARGUMENTS` to extract `--role`. If absent → Orchestration Mode (auto route to coordinator).
```javascript
const args = "$ARGUMENTS"
const roleMatch = args.match(/--role[=\s]+(\w+)/)
### Role Registry
if (!roleMatch) {
throw new Error("Missing --role argument. Available roles: coordinator, ideator, challenger, synthesizer, evaluator")
}
| Role | File | Task Prefix | Type | Compact |
|------|------|-------------|------|---------|
| coordinator | [roles/coordinator.md](roles/coordinator.md) | (none) | orchestrator | **⚠️ 压缩后必须重读** |
| ideator | [roles/ideator.md](roles/ideator.md) | IDEA-* | pipeline | 压缩后必须重读 |
| challenger | [roles/challenger.md](roles/challenger.md) | CHALLENGE-* | pipeline | 压缩后必须重读 |
| synthesizer | [roles/synthesizer.md](roles/synthesizer.md) | SYNTH-* | pipeline | 压缩后必须重读 |
| evaluator | [roles/evaluator.md](roles/evaluator.md) | EVAL-* | pipeline | 压缩后必须重读 |
const role = roleMatch[1]
const teamName = args.match(/--team[=\s]+([\w-]+)/)?.[1] || "brainstorm"
const agentName = args.match(/--agent-name[=\s]+([\w-]+)/)?.[1] || role
> **⚠️ COMPACT PROTECTION**: 角色文件是执行文档,不是参考资料。当 context compression 发生后,角色指令仅剩摘要时,**必须立即 `Read` 对应 role.md 重新加载后再继续执行**。不得基于摘要执行任何 Phase。
### Dispatch
1. Extract `--role` from arguments
2. If no `--role` → route to coordinator (Orchestration Mode)
3. Look up role in registry → Read the role file → Execute its phases
### Orchestration Mode
When invoked without `--role`, coordinator auto-starts. User just provides topic description.
**Invocation**: `Skill(skill="team-brainstorm", args="<topic-description>")`
**Lifecycle**:
```
User provides topic description
→ coordinator Phase 1-3: Topic clarification → TeamCreate → Create task chain
→ coordinator Phase 4: spawn first batch workers (background) → STOP
→ Worker executes → SendMessage callback → coordinator advances next step
→ Loop until pipeline complete → Phase 5 report
```
### Role Dispatch
**User Commands** (wake paused coordinator):
```javascript
const VALID_ROLES = {
"coordinator": { file: "roles/coordinator.md", prefix: null },
"ideator": { file: "roles/ideator.md", prefix: "IDEA" },
"challenger": { file: "roles/challenger.md", prefix: "CHALLENGE" },
"synthesizer": { file: "roles/synthesizer.md", prefix: "SYNTH" },
"evaluator": { file: "roles/evaluator.md", prefix: "EVAL" }
}
| Command | Action |
|---------|--------|
| `check` / `status` | Output execution status graph, no advancement |
| `resume` / `continue` | Check worker states, advance next step |
if (!VALID_ROLES[role]) {
throw new Error(`Unknown role: ${role}. Available: ${Object.keys(VALID_ROLES).join(', ')}`)
}
// Read and execute role-specific logic
Read(VALID_ROLES[role].file)
// → Execute the 5-phase process defined in that file
```
### Available Roles
| Role | Task Prefix | Responsibility | Role File |
|------|-------------|----------------|-----------|
| `coordinator` | N/A | 话题澄清、复杂度评估、管道选择、收敛监控 | [roles/coordinator.md](roles/coordinator.md) |
| `ideator` | IDEA-* | 多角度创意生成、概念探索、发散思维 | [roles/ideator.md](roles/ideator.md) |
| `challenger` | CHALLENGE-* | 魔鬼代言人、假设挑战、可行性质疑 | [roles/challenger.md](roles/challenger.md) |
| `synthesizer` | SYNTH-* | 跨想法整合、主题提取、冲突解决 | [roles/synthesizer.md](roles/synthesizer.md) |
| `evaluator` | EVAL-* | 评分排序、优先级推荐、最终筛选 | [roles/evaluator.md](roles/evaluator.md) |
---
## Shared Infrastructure
The following templates apply to all worker roles. Each role.md only needs to write **Phase 2-4** role-specific logic.
### Worker Phase 1: Task Discovery (shared by all workers)
Every worker executes the same task discovery flow on startup:
1. Call `TaskList()` to get all tasks
2. Filter: subject matches this role's prefix + owner is this role + status is pending + blockedBy is empty
3. No tasks → idle wait
4. Has tasks → `TaskGet` for details → `TaskUpdate` mark in_progress
**Resume Artifact Check** (prevent duplicate output after resume):
- Check whether this task's output artifact already exists
- Artifact complete → skip to Phase 5 report completion
- Artifact incomplete or missing → normal Phase 2-4 execution
### Worker Phase 5: Report (shared by all workers)
Standard reporting flow after task completion:
1. **Message Bus**: Call `mcp__ccw-tools__team_msg` to log message
- Parameters: operation="log", team="brainstorm", from=<role>, to="coordinator", type=<message-type>, summary="[<role>] <summary>", ref=<artifact-path>
- **CLI fallback**: When MCP unavailable → `ccw team log --team brainstorm --from <role> --to coordinator --type <type> --summary "[<role>] ..." --json`
2. **SendMessage**: Send result to coordinator (content and summary both prefixed with `[<role>]`)
3. **TaskUpdate**: Mark task completed
4. **Loop**: Return to Phase 1 to check next task
### Wisdom Accumulation (all roles)
Cross-task knowledge accumulation. Coordinator creates `wisdom/` directory at session initialization.
**Directory**:
```
<session-folder>/wisdom/
├── learnings.md # Patterns and insights
├── decisions.md # Architecture and design decisions
├── conventions.md # Codebase conventions
└── issues.md # Known risks and issues
```
**Worker Load** (Phase 2): Extract `Session: <path>` from task description, read wisdom directory files.
**Worker Contribute** (Phase 4/5): Write this task's discoveries to corresponding wisdom files.
### Role Isolation Rules
**核心原则**: 每个角色仅能执行自己职责范围内的工作。
| Allowed | Forbidden |
|---------|-----------|
| Process tasks with own prefix | Process tasks with other role prefixes |
| SendMessage to coordinator | Communicate directly with other workers |
| Read/write shared-memory.json (own fields) | Create tasks for other roles |
| Delegate to commands/ files | Modify resources outside own responsibility |
#### Output Tagging强制
Coordinator additional restrictions: Do not generate ideas directly, do not evaluate/challenge ideas, do not execute analysis/synthesis, do not bypass workers.
所有角色的输出必须带 `[role_name]` 标识前缀:
### Output Tagging
```javascript
// SendMessage — content 和 summary 都必须带标识
SendMessage({
content: `## [${role}] ...`,
summary: `[${role}] ...`
})
// team_msg — summary 必须带标识
mcp__ccw-tools__team_msg({
summary: `[${role}] ...`
})
```
#### Coordinator 隔离
| 允许 | 禁止 |
|------|------|
| 需求澄清 (AskUserQuestion) | ❌ 直接生成创意 |
| 创建任务链 (TaskCreate) | ❌ 直接评估/挑战想法 |
| 分发任务给 worker | ❌ 直接执行分析/综合 |
| 监控进度 (消息总线) | ❌ 绕过 worker 自行完成任务 |
| 汇报结果给用户 | ❌ 修改源代码或产物文件 |
#### Worker 隔离
| 允许 | 禁止 |
|------|------|
| 处理自己前缀的任务 | ❌ 处理其他角色前缀的任务 |
| SendMessage 给 coordinator | ❌ 直接与其他 worker 通信 |
| 读取 shared-memory.json | ❌ 为其他角色创建任务 (TaskCreate) |
| 写入 shared-memory.json (自己的字段) | ❌ 修改不属于本职责的资源 |
### Team Configuration
```javascript
const TEAM_CONFIG = {
name: "brainstorm",
sessionDir: ".workflow/.team/BRS-{slug}-{date}/",
sharedMemory: "shared-memory.json"
}
```
### Shared Memory (创新模式)
所有角色在 Phase 2 读取、Phase 5 写入 `shared-memory.json`
```javascript
// Phase 2: 读取共享记忆
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// Phase 5: 写入共享记忆(仅更新自己负责的字段)
// ideator → sharedMemory.generated_ideas
// challenger → sharedMemory.critique_insights
// synthesizer → sharedMemory.synthesis_themes
// evaluator → sharedMemory.evaluation_scores
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
```
All outputs must carry `[role_name]` prefix in both SendMessage content/summary and team_msg summary.
### Message Bus (All Roles)
Every SendMessage **before**, must call `mcp__ccw-tools__team_msg` to log:
```javascript
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: role,
to: "coordinator",
type: "<type>",
summary: `[${role}] <summary>`,
ref: "<file_path>"
})
```
**Parameters**: operation="log", team="brainstorm", from=<role>, to="coordinator", type=<message-type>, summary="[<role>] <summary>", ref=<artifact-path>
**CLI fallback**: When MCP unavailable → `ccw team log --team brainstorm --from <role> --to coordinator --type <type> --summary "[<role>] ..." --json`
**Message types by role**:
@@ -168,36 +156,26 @@ mcp__ccw-tools__team_msg({
| synthesizer | `synthesis_ready`, `error` |
| evaluator | `evaluation_ready`, `error` |
### CLI Fallback
### Shared Memory
When `mcp__ccw-tools__team_msg` MCP is unavailable:
All roles read in Phase 2 and write in Phase 5 to `shared-memory.json`:
```javascript
Bash(`ccw team log --team "${teamName}" --from "${role}" --to "coordinator" --type "<type>" --summary "<summary>" --json`)
```
| Role | Field |
|------|-------|
| ideator | `generated_ideas` |
| challenger | `critique_insights` |
| synthesizer | `synthesis_themes` |
| evaluator | `evaluation_scores` |
### Task Lifecycle (All Worker Roles)
### Team Configuration
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith(`${VALID_ROLES[role].prefix}-`) &&
t.owner === agentName && // Use agentName (e.g., 'ideator-1') instead of role
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return // idle
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
| Setting | Value |
|---------|-------|
| Team name | brainstorm |
| Session directory | `.workflow/.team/BRS-<slug>-<date>/` |
| Shared memory | `shared-memory.json` in session dir |
// Phase 2-4: Role-specific (see roles/{role}.md)
// Phase 5: Report + Loop — 所有输出必须带 [role] 标识
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: role, to: "coordinator", type: "...", summary: `[${role}] ...` })
SendMessage({ type: "message", recipient: "coordinator", content: `## [${role}] ...`, summary: `[${role}] ...` })
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task → back to Phase 1
```
---
## Three-Pipeline Architecture
@@ -214,19 +192,193 @@ Full (Fan-out + Generator-Critic):
### Generator-Critic Loop
ideator challenger 循环最多2轮
ideator <-> challenger loop, max 2 rounds:
```
IDEA → CHALLENGE → (if critique.severity >= HIGH) → IDEA-fix → CHALLENGE-2 → SYNTH
(if critique.severity < HIGH) → SYNTH
```
### Cadence Control
**Beat model**: Event-driven, each beat = coordinator wake → process → spawn → STOP. Brainstorm beat: generate → challenge → synthesize → evaluate.
```
Beat Cycle (single beat)
═══════════════════════════════════════════════════════════
Event Coordinator Workers
───────────────────────────────────────────────────────────
callback/resume ──→ ┌─ handleCallback ─┐
│ mark completed │
│ check pipeline │
├─ handleSpawnNext ─┤
│ find ready tasks │
│ spawn workers ───┼──→ [Worker A] Phase 1-5
│ (parallel OK) ──┼──→ [Worker B] Phase 1-5
└─ STOP (idle) ─────┘ │
callback ←─────────────────────────────────────────┘
(next beat) SendMessage + TaskUpdate(completed)
═══════════════════════════════════════════════════════════
```
**Pipeline beat views**:
```
Quick (3 beats, strictly serial)
──────────────────────────────────────────────────────────
Beat 1 2 3
│ │ │
IDEA → CHALLENGE ──→ SYNTH
▲ ▲
pipeline pipeline
start done
IDEA=ideator CHALLENGE=challenger SYNTH=synthesizer
Deep (5-6 beats, with Generator-Critic loop)
──────────────────────────────────────────────────────────
Beat 1 2 3 4 5 6
│ │ │ │ │ │
IDEA → CHALLENGE → (GC loop?) → IDEA-fix → SYNTH → EVAL
severity check
(< HIGH → skip to SYNTH)
Full (4-7 beats, fan-out + Generator-Critic)
──────────────────────────────────────────────────────────
Beat 1 2 3-4 5 6
┌────┴────┐ │ │ │ │
IDEA-1 ∥ IDEA-2 ∥ IDEA-3 → CHALLENGE → (GC loop) → SYNTH → EVAL
▲ ▲
parallel pipeline
window done
```
**Checkpoints**:
| Trigger | Location | Behavior |
|---------|----------|----------|
| Generator-Critic loop | After CHALLENGE-* | If severity >= HIGH → create IDEA-fix task; else proceed to SYNTH |
| GC loop limit | Max 2 rounds | Exceeds limit → force convergence to SYNTH |
| Pipeline stall | No ready + no running | Check missing tasks, report to user |
**Stall Detection** (coordinator `handleCheck` executes):
| Check | Condition | Resolution |
|-------|-----------|------------|
| Worker no response | in_progress task no callback | Report waiting task list, suggest user `resume` |
| Pipeline deadlock | no ready + no running + has pending | Check blockedBy dependency chain, report blocking point |
| GC loop exceeded | ideator/challenger iteration > 2 rounds | Terminate loop, force convergence to synthesizer |
### Task Metadata Registry
| Task ID | Role | Phase | Dependencies | Description |
|---------|------|-------|-------------|-------------|
| IDEA-001 | ideator | generate | (none) | Multi-angle idea generation |
| IDEA-002 | ideator | generate | (none) | Parallel angle (Full pipeline only) |
| IDEA-003 | ideator | generate | (none) | Parallel angle (Full pipeline only) |
| CHALLENGE-001 | challenger | challenge | IDEA-001 (or all IDEA-*) | Devil's advocate critique and feasibility challenge |
| IDEA-004 | ideator | gc-fix | CHALLENGE-001 | Revision based on critique (GC loop, if triggered) |
| CHALLENGE-002 | challenger | gc-fix | IDEA-004 | Re-critique of revised ideas (GC loop round 2) |
| SYNTH-001 | synthesizer | synthesize | last CHALLENGE-* | Cross-idea integration, theme extraction, conflict resolution |
| EVAL-001 | evaluator | evaluate | SYNTH-001 | Scoring, ranking, priority recommendation, final selection |
---
## Coordinator Spawn Template
When coordinator spawns workers, use background mode (Spawn-and-Stop).
**Standard spawn** (single agent per role): For Quick/Deep pipeline, spawn one ideator. Challenger, synthesizer, and evaluator are always single agents.
**Parallel spawn** (Full pipeline): For Full pipeline with N idea angles, spawn N ideator agents in parallel (`ideator-1`, `ideator-2`, ...) with `run_in_background: true`. Each parallel ideator only processes tasks where owner matches its agent name. After all parallel ideators complete, proceed with single challenger for batch critique.
**Spawn template**:
```
Task({
subagent_type: "general-purpose",
description: "Spawn <role> worker",
team_name: "brainstorm",
name: "<role>",
run_in_background: true,
prompt: `You are team "brainstorm" <ROLE>.
## Primary Directive
All your work must be executed through Skill to load role definition:
Skill(skill="team-brainstorm", args="--role=<role>")
Current topic: <topic-description>
Session: <session-folder>
## Role Guidelines
- Only process <PREFIX>-* tasks, do not execute other role work
- All output prefixed with [<role>] identifier
- Only communicate with coordinator
- Do not use TaskCreate for other roles
- Call mcp__ccw-tools__team_msg before every SendMessage
## Workflow
1. Call Skill -> load role definition and execution logic
2. Follow role.md 5-Phase flow
3. team_msg + SendMessage results to coordinator
4. TaskUpdate completed -> check next task`
})
```
**Parallel ideator spawn** (Full pipeline with N angles):
> When Full pipeline has N parallel IDEA tasks assigned to ideator role, spawn N distinct agents named `ideator-1`, `ideator-2`, etc. Each agent only processes tasks where owner matches its agent name.
| Condition | Action |
|-----------|--------|
| Full pipeline with N idea angles (N > 1) | Spawn N agents: `ideator-1`, `ideator-2`, ... `ideator-N` with `run_in_background: true` |
| Quick/Deep pipeline (single ideator) | Standard spawn: single `ideator` agent |
```
Task({
subagent_type: "general-purpose",
description: "Spawn ideator-<N> worker",
team_name: "brainstorm",
name: "ideator-<N>",
run_in_background: true,
prompt: `You are team "brainstorm" IDEATOR (ideator-<N>).
Your agent name is "ideator-<N>", use this name for task discovery owner matching.
## Primary Directive
Skill(skill="team-brainstorm", args="--role=ideator --agent-name=ideator-<N>")
Current topic: <topic-description>
Session: <session-folder>
## Role Guidelines
- Only process tasks where owner === "ideator-<N>" with IDEA-* prefix
- All output prefixed with [ideator] identifier
## Workflow
1. TaskList -> find tasks where owner === "ideator-<N>" with IDEA-* prefix
2. Skill -> execute role definition
3. team_msg + SendMessage results to coordinator
4. TaskUpdate completed -> check next task`
})
```
**Dispatch must match agent names**: When dispatching parallel IDEA tasks, coordinator sets each task's owner to the corresponding instance name (`ideator-1`, `ideator-2`, etc.). In role.md, task discovery uses `--agent-name` for owner matching.
---
## Unified Session Directory
```
.workflow/.team/BRS-{slug}-{YYYY-MM-DD}/
.workflow/.team/BRS-<slug>-<YYYY-MM-DD>/
├── team-session.json # Session state
├── shared-memory.json # 累积: generated_ideas / critique_insights / synthesis_themes / evaluation_scores
├── shared-memory.json # Cumulative: generated_ideas / critique_insights / synthesis_themes / evaluation_scores
├── wisdom/ # Cross-task knowledge
│ ├── learnings.md
│ ├── decisions.md
│ ├── conventions.md
│ └── issues.md
├── ideas/ # Ideator output
│ ├── idea-001.md
│ ├── idea-002.md
@@ -240,159 +392,13 @@ IDEA → CHALLENGE → (if critique.severity >= HIGH) → IDEA-fix → CHALLENGE
└── evaluation-001.md
```
## Coordinator Spawn Template
```javascript
TeamCreate({ team_name: teamName })
// Ideator — conditional parallel spawn for Full pipeline (multiple angles)
const isFullPipeline = selectedPipeline === 'full'
const ideaAngles = selectedAngles || []
if (isFullPipeline && ideaAngles.length > 1) {
// Full pipeline: spawn N ideators for N parallel angle tasks
for (let i = 0; i < ideaAngles.length; i++) {
const agentName = `ideator-${i + 1}`
Task({
subagent_type: "general-purpose",
description: `Spawn ${agentName} worker`,
team_name: teamName,
name: agentName,
prompt: `你是 team "${teamName}" 的 IDEATOR (${agentName})。
你的 agent 名称是 "${agentName}",任务发现时用此名称匹配 owner。
当你收到 IDEA-* 任务时,调用 Skill(skill="team-brainstorm", args="--role=ideator --agent-name=${agentName}") 执行。
当前话题: ${taskDescription}
约束: ${constraints}
## 角色准则(强制)
- 你只能处理 owner 为 "${agentName}" 的 IDEA-* 前缀任务
- 所有输出SendMessage、team_msg必须带 [ideator] 标识前缀
- 仅与 coordinator 通信,不得直接联系其他 worker
- 不得使用 TaskCreate 为其他角色创建任务
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 owner === "${agentName}" 的 IDEA-* 任务
2. Skill(skill="team-brainstorm", args="--role=ideator --agent-name=${agentName}") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [ideator] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
}
} else {
// Quick/Deep pipeline: single ideator
Task({
subagent_type: "general-purpose",
description: `Spawn ideator worker`,
team_name: teamName,
name: "ideator",
prompt: `你是 team "${teamName}" 的 IDEATOR。
当你收到 IDEA-* 任务时,调用 Skill(skill="team-brainstorm", args="--role=ideator") 执行。
当前话题: ${taskDescription}
约束: ${constraints}
## 角色准则(强制)
- 你只能处理 IDEA-* 前缀的任务,不得执行其他角色的工作
- 所有输出SendMessage、team_msg必须带 [ideator] 标识前缀
- 仅与 coordinator 通信,不得直接联系其他 worker
- 不得使用 TaskCreate 为其他角色创建任务
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 IDEA-* 任务
2. Skill(skill="team-brainstorm", args="--role=ideator") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [ideator] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
}
// Challenger
Task({
subagent_type: "general-purpose",
description: `Spawn challenger worker`,
team_name: teamName,
name: "challenger",
prompt: `你是 team "${teamName}" 的 CHALLENGER。
当你收到 CHALLENGE-* 任务时,调用 Skill(skill="team-brainstorm", args="--role=challenger") 执行。
当前话题: ${taskDescription}
## 角色准则(强制)
- 你只能处理 CHALLENGE-* 前缀的任务
- 所有输出必须带 [challenger] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 CHALLENGE-* 任务
2. Skill(skill="team-brainstorm", args="--role=challenger") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [challenger] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
// Synthesizer
Task({
subagent_type: "general-purpose",
description: `Spawn synthesizer worker`,
team_name: teamName,
name: "synthesizer",
prompt: `你是 team "${teamName}" 的 SYNTHESIZER。
当你收到 SYNTH-* 任务时,调用 Skill(skill="team-brainstorm", args="--role=synthesizer") 执行。
当前话题: ${taskDescription}
## 角色准则(强制)
- 你只能处理 SYNTH-* 前缀的任务
- 所有输出必须带 [synthesizer] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 SYNTH-* 任务
2. Skill(skill="team-brainstorm", args="--role=synthesizer") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [synthesizer] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
// Evaluator
Task({
subagent_type: "general-purpose",
description: `Spawn evaluator worker`,
team_name: teamName,
name: "evaluator",
prompt: `你是 team "${teamName}" 的 EVALUATOR。
当你收到 EVAL-* 任务时,调用 Skill(skill="team-brainstorm", args="--role=evaluator") 执行。
当前话题: ${taskDescription}
## 角色准则(强制)
- 你只能处理 EVAL-* 前缀的任务
- 所有输出必须带 [evaluator] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 EVAL-* 任务
2. Skill(skill="team-brainstorm", args="--role=evaluator") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [evaluator] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
```
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown --role value | Error with available role list |
| Missing --role arg | Error with usage hint |
| Role file not found | Error with expected path (roles/{name}.md) |
| Missing --role arg | Orchestration Mode → auto route to coordinator |
| Role file not found | Error with expected path (roles/<name>.md) |
| Task prefix conflict | Log warning, proceed |
| Generator-Critic loop exceeds 2 rounds | Force convergence → SYNTH |
| No ideas generated | Coordinator prompts with seed questions |

View File

@@ -1,16 +1,14 @@
# Role: challenger
# Challenger Role
魔鬼代言人角色。负责假设挑战、可行性质疑、风险识别。作为 Generator-Critic 循环中的 Critic 角色。
## Role Identity
## Identity
- **Name**: `challenger`
- **Name**: `challenger` | **Tag**: `[challenger]`
- **Task Prefix**: `CHALLENGE-*`
- **Responsibility**: Read-only analysis (批判性分析)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[challenger]`
- **Responsibility**: Read-only analysis (critical analysis)
## Role Boundaries
## Boundaries
### MUST
@@ -22,181 +20,141 @@
### MUST NOT
- 生成创意、综合想法或评估排序
- 直接与其他 worker 角色通信
- 为其他角色创建任务
- 修改 shared-memory.json 中不属于自己的字段
- 生成创意、综合想法或评估排序
- 直接与其他 worker 角色通信
- 为其他角色创建任务
- 修改 shared-memory.json 中不属于自己的字段
- 在输出中省略 `[challenger]` 标识
---
## Toolbox
### Tool Capabilities
| Tool | Type | Used By | Purpose |
|------|------|---------|---------|
| `TaskList` | Built-in | Phase 1 | Discover pending CHALLENGE-* tasks |
| `TaskGet` | Built-in | Phase 1 | Get task details |
| `TaskUpdate` | Built-in | Phase 1/5 | Update task status |
| `Read` | Built-in | Phase 2 | Read shared-memory.json, idea files |
| `Write` | Built-in | Phase 3/5 | Write critique files, update shared memory |
| `Glob` | Built-in | Phase 2 | Find idea files |
| `SendMessage` | Built-in | Phase 5 | Report to coordinator |
| `mcp__ccw-tools__team_msg` | MCP | Phase 5 | Log communication |
---
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `critique_ready` | challenger coordinator | Critique completed | 挑战分析完成 |
| `error` | challenger coordinator | Processing failure | 错误上报 |
| `critique_ready` | challenger -> coordinator | Critique completed | Critical analysis complete |
| `error` | challenger -> coordinator | Processing failure | Error report |
## Message Bus
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: <team-name>,
from: "challenger",
to: "coordinator",
type: "critique_ready",
summary: "[challenger] Critique complete: <critical>C/<high>H/<medium>M/<low>L -- Signal: <signal>",
ref: <output-path>
})
```
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team <team-name> --from challenger --to coordinator --type critique_ready --summary \"[challenger] Critique complete\" --ref <output-path> --json")
```
---
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('CHALLENGE-') &&
t.owner === 'challenger' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
Standard task discovery flow: TaskList -> filter by prefix `CHALLENGE-*` + owner match + pending + unblocked -> TaskGet -> TaskUpdate in_progress.
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
| Input | Source | Required |
|-------|--------|----------|
| Session folder | Task description (Session: line) | Yes |
| Ideas | ideas/*.md files | Yes |
| Previous critiques | shared-memory.json.critique_insights | No (avoid repeating) |
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
**Loading steps**:
// Read all idea files referenced in task
const ideaFiles = Glob({ pattern: `${sessionFolder}/ideas/*.md` })
const ideas = ideaFiles.map(f => Read(f))
// Read previous critiques for context (avoid repeating)
const prevCritiques = sharedMemory.critique_insights || []
```
1. Extract session path from task description (match "Session: <path>")
2. Glob idea files from session folder
3. Read all idea files for analysis
4. Read shared-memory.json.critique_insights to avoid repeating
### Phase 3: Critical Analysis
```javascript
// For each idea, apply 4 challenge dimensions:
// 1. Assumption Validity — 核心假设是否成立?有什么反例?
// 2. Feasibility — 技术/资源/时间上是否可行?
// 3. Risk Assessment — 最坏情况是什么?有什么隐藏风险?
// 4. Competitive Analysis — 已有更好的替代方案吗?
**Challenge Dimensions** (apply to each idea):
// Severity classification:
// LOW — Minor concern, does not invalidate the idea
// MEDIUM — Notable weakness, needs consideration
// HIGH — Significant flaw, requires revision
// CRITICAL — Fundamental issue, idea may need replacement
| Dimension | Focus |
|-----------|-------|
| Assumption Validity | Does the core assumption hold? Any counter-examples? |
| Feasibility | Technical/resource/time feasibility? |
| Risk Assessment | Worst case scenario? Hidden risks? |
| Competitive Analysis | Better alternatives already exist? |
const challengeNum = task.subject.match(/CHALLENGE-(\d+)/)?.[1] || '001'
const outputPath = `${sessionFolder}/critiques/critique-${challengeNum}.md`
**Severity Classification**:
const critiqueContent = `# Critique — Round ${challengeNum}
| Severity | Criteria |
|----------|----------|
| CRITICAL | Fundamental issue, idea may need replacement |
| HIGH | Significant flaw, requires revision |
| MEDIUM | Notable weakness, needs consideration |
| LOW | Minor concern, does not invalidate the idea |
**Ideas Reviewed**: ${ideas.length} files
**Challenge Dimensions**: Assumption Validity, Feasibility, Risk, Competition
**Generator-Critic Signal**:
## Challenges
| Condition | Signal |
|-----------|--------|
| Any CRITICAL or HIGH severity | REVISION_NEEDED -> ideator must revise |
| All MEDIUM or lower | CONVERGED -> ready for synthesis |
${challenges.map((c, i) => `### Idea: ${c.ideaTitle}
**Severity**: ${c.severity}
| Dimension | Finding |
|-----------|---------|
| Assumption Validity | ${c.assumption} |
| Feasibility | ${c.feasibility} |
| Risk Assessment | ${c.risk} |
| Competitive Analysis | ${c.competition} |
**Key Challenge**: ${c.keyChallenge}
**Suggested Direction**: ${c.suggestion}
`).join('\n')}
## Summary
| Severity | Count |
|----------|-------|
| CRITICAL | ${challenges.filter(c => c.severity === 'CRITICAL').length} |
| HIGH | ${challenges.filter(c => c.severity === 'HIGH').length} |
| MEDIUM | ${challenges.filter(c => c.severity === 'MEDIUM').length} |
| LOW | ${challenges.filter(c => c.severity === 'LOW').length} |
**Generator-Critic Signal**: ${
challenges.some(c => c.severity === 'CRITICAL' || c.severity === 'HIGH')
? 'REVISION_NEEDED — Critical/High issues require ideator revision'
: 'CONVERGED — No critical issues, ready for synthesis'
}
`
Write(outputPath, critiqueContent)
```
**Output file structure**:
- File: `<session>/critiques/critique-<num>.md`
- Sections: Ideas Reviewed, Challenge Dimensions, Per-idea challenges with severity table, Summary table with counts, GC Signal
### Phase 4: Severity Summary
```javascript
// Aggregate severity counts for coordinator decision
const severitySummary = {
critical: challenges.filter(c => c.severity === 'CRITICAL').length,
high: challenges.filter(c => c.severity === 'HIGH').length,
medium: challenges.filter(c => c.severity === 'MEDIUM').length,
low: challenges.filter(c => c.severity === 'LOW').length,
signal: (challenges.some(c => c.severity === 'CRITICAL' || c.severity === 'HIGH'))
? 'REVISION_NEEDED' : 'CONVERGED'
}
```
**Aggregation**:
1. Count challenges by severity level
2. Determine signal based on presence of CRITICAL/HIGH
| Metric | Source |
|--------|--------|
| critical count | challenges with severity CRITICAL |
| high count | challenges with severity HIGH |
| medium count | challenges with severity MEDIUM |
| low count | challenges with severity LOW |
| signal | REVISION_NEEDED if critical+high > 0, else CONVERGED |
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
// Update shared memory
sharedMemory.critique_insights = [
...sharedMemory.critique_insights,
...challenges.map(c => ({
idea: c.ideaTitle,
severity: c.severity,
key_challenge: c.keyChallenge,
round: parseInt(challengeNum)
}))
]
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "challenger",
to: "coordinator",
type: "critique_ready",
summary: `[challenger] Critique complete: ${severitySummary.critical}C/${severitySummary.high}H/${severitySummary.medium}M/${severitySummary.low}L — Signal: ${severitySummary.signal}`,
ref: outputPath
})
Standard report flow: team_msg log -> SendMessage with `[challenger]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [challenger] Critique Results
**Shared Memory Update**:
1. Append challenges to shared-memory.json.critique_insights
2. Each entry: idea, severity, key_challenge, round
**Task**: ${task.subject}
**Signal**: ${severitySummary.signal}
**Severity**: ${severitySummary.critical} Critical, ${severitySummary.high} High, ${severitySummary.medium} Medium, ${severitySummary.low} Low
**Output**: ${outputPath}
${severitySummary.signal === 'REVISION_NEEDED'
? '### Requires Revision\n' + challenges.filter(c => ['CRITICAL', 'HIGH'].includes(c.severity)).map(c => `- **${c.ideaTitle}** (${c.severity}): ${c.keyChallenge}`).join('\n')
: '### All Clear — Ready for Synthesis'}`,
summary: `[challenger] Critique: ${severitySummary.signal}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('CHALLENGE-') &&
t.owner === 'challenger' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (nextTasks.length > 0) {
// back to Phase 1
}
```
---
## Error Handling
@@ -206,3 +164,4 @@ if (nextTasks.length > 0) {
| Ideas file not found | Notify coordinator |
| All ideas trivially good | Mark all LOW, signal CONVERGED |
| Cannot assess feasibility | Mark MEDIUM with note, suggest deeper analysis |
| Critical issue beyond scope | SendMessage error to coordinator |

View File

@@ -1,315 +1,257 @@
# Role: coordinator
# Coordinator Role
头脑风暴团队协调者。负责话题澄清、复杂度评估、管道选择、Generator-Critic 循环控制和收敛监控。
## Role Identity
## Identity
- **Name**: `coordinator`
- **Task Prefix**: N/A (coordinator creates tasks, doesn't receive them)
- **Responsibility**: Orchestration
- **Communication**: SendMessage to all teammates
- **Output Tag**: `[coordinator]`
- **Name**: `coordinator` | **Tag**: `[coordinator]`
- **Responsibility**: Parse requirements -> Create team -> Dispatch tasks -> Monitor progress -> Report results
## Role Boundaries
## Boundaries
### MUST
- 所有输出SendMessage、team_msg、日志必须带 `[coordinator]` 标识
- 仅负责话题澄清、任务创建/分发、进度监控、结果汇报
- 通过 TaskCreate 创建任务并分配给 worker 角色
- 解析用户需求,通过 AskUserQuestion 澄清模糊输入
- 创建团队并通过 TaskCreate 分配任务给 worker 角色
- 通过消息总线监控 worker 进度并路由消息
- 管理 Generator-Critic 循环计数,决定是否继续迭代
- 维护 session 状态持久化
### MUST NOT
- **直接生成创意、挑战假设、综合想法或评估排序**
- 直接调用实现类 subagent
- 直接修改产物文件ideas/*.md, critiques/*.md 等)
- 绕过 worker 角色自行完成应委派的工作
- 在输出中省略 `[coordinator]` 标识
- 直接生成创意、挑战假设、综合想法或评估排序
- 直接调用实现类 subagent
- 直接修改产物文件ideas/*.md, critiques/*.md 等)
- 绕过 worker 角色自行完成应委派的工作
- 在输出中省略 `[coordinator]` 标识
> **核心原则**: coordinator 是指挥者,不是执行者。所有实际工作必须通过 TaskCreate 委派给 worker 角色。
---
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `pipeline_selected` | coordinator all | Pipeline decided | Notify selected pipeline mode |
| `gc_loop_trigger` | coordinator ideator | Critique severity >= HIGH | Trigger ideator to revise |
| `task_unblocked` | coordinator any | Dependency resolved | Notify worker of available task |
| `error` | coordinator all | Critical system error | Escalation to user |
| `shutdown` | coordinator all | Team being dissolved | Clean shutdown signal |
| `pipeline_selected` | coordinator -> all | Pipeline decided | Notify selected pipeline mode |
| `gc_loop_trigger` | coordinator -> ideator | Critique severity >= HIGH | Trigger ideator to revise |
| `task_unblocked` | coordinator -> any | Dependency resolved | Notify worker of available task |
| `error` | coordinator -> all | Critical system error | Escalation to user |
| `shutdown` | coordinator -> all | Team being dissolved | Clean shutdown signal |
## Execution
## Message Bus
### Phase 1: Topic Clarification + Complexity Assessment
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```javascript
const args = "$ARGUMENTS"
const teamNameMatch = args.match(/--team-name[=\s]+([\w-]+)/)
const teamName = teamNameMatch ? teamNameMatch[1] : `brainstorm-${Date.now().toString(36)}`
const taskDescription = args.replace(/--team-name[=\s]+[\w-]+/, '').replace(/--role[=\s]+\w+/, '').trim()
```
Assess topic complexity and select pipeline:
```javascript
function assessComplexity(topic) {
let score = 0
if (/strategy|architecture|system|framework|paradigm/.test(topic)) score += 3
if (/multiple|compare|tradeoff|versus|alternative/.test(topic)) score += 2
if (/innovative|creative|novel|breakthrough/.test(topic)) score += 2
if (/simple|quick|straightforward|basic/.test(topic)) score -= 2
return score >= 4 ? 'high' : score >= 2 ? 'medium' : 'low'
}
const complexity = assessComplexity(taskDescription)
```
```javascript
AskUserQuestion({
questions: [
{
question: "选择头脑风暴模式:",
header: "Mode",
multiSelect: false,
options: [
{ label: complexity === 'low' ? "quick (推荐)" : "quick", description: "快速模式创意→挑战→综合3步" },
{ label: complexity === 'medium' ? "deep (推荐)" : "deep", description: "深度模式:含 Generator-Critic 循环6步" },
{ label: complexity === 'high' ? "full (推荐)" : "full", description: "完整模式:并行发散 + 循环 + 评估7步" }
]
},
{
question: "创意发散角度:",
header: "Angles",
multiSelect: true,
options: [
{ label: "技术视角", description: "技术可行性、实现方案、架构设计" },
{ label: "产品视角", description: "用户需求、市场定位、商业模式" },
{ label: "创新视角", description: "颠覆性思路、跨领域借鉴、未来趋势" },
{ label: "风险视角", description: "潜在问题、约束条件、替代方案" }
]
}
]
mcp__ccw-tools__team_msg({
operation: "log",
team: <team-name>,
from: "coordinator",
to: <recipient>,
type: <message-type>,
summary: "[coordinator] <action> complete: <subject>",
ref: <artifact-path>
})
```
### Phase 2: Create Team + Initialize Session
**CLI fallback** (when MCP unavailable):
```javascript
TeamCreate({ team_name: teamName })
const topicSlug = taskDescription.toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40)
const dateStr = new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString().substring(0, 10)
const sessionId = `BRS-${topicSlug}-${dateStr}`
const sessionFolder = `.workflow/.team/${sessionId}`
Bash(`mkdir -p "${sessionFolder}/ideas" "${sessionFolder}/critiques" "${sessionFolder}/synthesis" "${sessionFolder}/evaluation"`)
// Initialize shared memory
const sharedMemory = {
topic: taskDescription,
pipeline: selectedPipeline,
angles: selectedAngles,
gc_round: 0,
max_gc_rounds: 2,
generated_ideas: [],
critique_insights: [],
synthesis_themes: [],
evaluation_scores: []
}
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
// Create team-session.json
const teamSession = {
session_id: sessionId,
team_name: teamName,
topic: taskDescription,
pipeline: selectedPipeline,
status: "active",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
gc_round: 0,
completed_tasks: []
}
Write(`${sessionFolder}/team-session.json`, JSON.stringify(teamSession, null, 2))
```
Bash("ccw team log --team <team-name> --from coordinator --to <recipient> --type <message-type> --summary \"[coordinator] <action> complete\" --ref <artifact-path> --json")
```
// ⚠️ Workers are NOT pre-spawned here.
// Workers are spawned per-stage in Phase 4 via Stop-Wait Task(run_in_background: false).
// See SKILL.md Coordinator Spawn Template for worker prompt templates.
---
### Phase 3: Create Task Chain
## Entry Router
Task chain depends on the selected pipeline.
When coordinator is invoked, first detect the invocation type:
#### Quick Pipeline
| Detection | Condition | Handler |
|-----------|-----------|---------|
| Worker callback | Message contains `[role-name]` tag from a known worker role | -> handleCallback: auto-advance pipeline |
| Status check | Arguments contain "check" or "status" | -> handleCheck: output execution graph, no advancement |
| Manual resume | Arguments contain "resume" or "continue" | -> handleResume: check worker states, advance pipeline |
| New session | None of the above | -> Phase 0 (Session Resume Check) |
```javascript
// IDEA-001: 创意生成
TaskCreate({ subject: "IDEA-001: 多角度创意生成", description: `话题: ${taskDescription}\n\nSession: ${sessionFolder}\n角度: ${selectedAngles.join(', ')}\n输出: ${sessionFolder}/ideas/idea-001.md\n\n要求: 每个角度至少产出3个创意总计不少于6个`, activeForm: "生成创意中" })
TaskUpdate({ taskId: ideaId, owner: "ideator" })
For callback/check/resume: load monitor logic and execute the appropriate handler, then STOP.
// CHALLENGE-001: 挑战质疑 (blockedBy IDEA-001)
TaskCreate({ subject: "CHALLENGE-001: 假设挑战与可行性质疑", description: `对 IDEA-001 的创意进行批判性分析\n\nSession: ${sessionFolder}\n输入: ${sessionFolder}/ideas/idea-001.md\n输出: ${sessionFolder}/critiques/critique-001.md\n\n要求: 标记每个创意的挑战严重度 (LOW/MEDIUM/HIGH/CRITICAL)`, activeForm: "挑战创意中" })
TaskUpdate({ taskId: challengeId, owner: "challenger", addBlockedBy: [ideaId] })
---
// SYNTH-001: 综合整合 (blockedBy CHALLENGE-001)
TaskCreate({ subject: "SYNTH-001: 跨想法整合与主题提取", description: `整合所有创意和挑战反馈\n\nSession: ${sessionFolder}\n输入: ideas/ + critiques/\n输出: ${sessionFolder}/synthesis/synthesis-001.md\n\n要求: 提取核心主题、解决冲突、生成整合方案`, activeForm: "综合整合中" })
TaskUpdate({ taskId: synthId, owner: "synthesizer", addBlockedBy: [challengeId] })
```
## Phase 0: Session Resume Check
#### Deep Pipeline (with Generator-Critic Loop)
**Objective**: Detect and resume interrupted sessions before creating new ones.
```javascript
// IDEA-001 → CHALLENGE-001 → IDEA-002(fix) → CHALLENGE-002 → SYNTH-001 → EVAL-001
**Workflow**:
1. Scan session directory for sessions with status "active" or "paused"
2. No sessions found -> proceed to Phase 1
3. Single session found -> resume it (-> Session Reconciliation)
4. Multiple sessions -> AskUserQuestion for user selection
TaskCreate({ subject: "IDEA-001: 初始创意生成", description: `话题: ${taskDescription}\n\nSession: ${sessionFolder}\n输出: ${sessionFolder}/ideas/idea-001.md`, activeForm: "生成创意中" })
TaskUpdate({ taskId: idea1Id, owner: "ideator" })
**Session Reconciliation**:
1. Audit TaskList -> get real status of all tasks
2. Reconcile: session state <-> TaskList status (bidirectional sync)
3. Reset any in_progress tasks -> pending (they were interrupted)
4. Determine remaining pipeline from reconciled state
5. Rebuild team if disbanded (TeamCreate + spawn needed workers only)
6. Create missing tasks with correct blockedBy dependencies
7. Verify dependency chain integrity
8. Update session file with reconciled state
9. Kick first executable task's worker -> Phase 4
TaskCreate({ subject: "CHALLENGE-001: 第一轮挑战", description: `挑战 IDEA-001 的创意\n\nSession: ${sessionFolder}\n输入: ideas/idea-001.md\n输出: critiques/critique-001.md\n标记严重度`, activeForm: "挑战中" })
TaskUpdate({ taskId: challenge1Id, owner: "challenger", addBlockedBy: [idea1Id] })
---
TaskCreate({ subject: "IDEA-002: 创意修订Generator-Critic Round 1", description: `基于 CHALLENGE-001 的反馈修订创意\n\nSession: ${sessionFolder}\n输入: ideas/idea-001.md + critiques/critique-001.md\n输出: ideas/idea-002.md\n\n要求: 针对 HIGH/CRITICAL 严重度的挑战进行修订或替换`, activeForm: "修订创意中" })
TaskUpdate({ taskId: idea2Id, owner: "ideator", addBlockedBy: [challenge1Id] })
## Phase 1: Topic Clarification + Complexity Assessment
TaskCreate({ subject: "CHALLENGE-002: 第二轮验证", description: `验证修订后的创意\n\nSession: ${sessionFolder}\n输入: ideas/idea-002.md + critiques/critique-001.md\n输出: critiques/critique-002.md`, activeForm: "验证中" })
TaskUpdate({ taskId: challenge2Id, owner: "challenger", addBlockedBy: [idea2Id] })
**Objective**: Parse user input, assess complexity, select pipeline mode.
TaskCreate({ subject: "SYNTH-001: 综合整合", description: `整合全部创意和挑战反馈\n\nSession: ${sessionFolder}\n输入: ideas/ + critiques/\n输出: synthesis/synthesis-001.md`, activeForm: "综合中" })
TaskUpdate({ taskId: synthId, owner: "synthesizer", addBlockedBy: [challenge2Id] })
**Workflow**:
TaskCreate({ subject: "EVAL-001: 评分排序与最终筛选", description: `对综合方案评分排序\n\nSession: ${sessionFolder}\n输入: synthesis/synthesis-001.md + shared-memory.json\n输出: evaluation/evaluation-001.md\n\n评分维度: 可行性(30%) + 创新性(25%) + 影响力(25%) + 实施成本(20%)`, activeForm: "评估中" })
TaskUpdate({ taskId: evalId, owner: "evaluator", addBlockedBy: [synthId] })
```
1. Parse arguments for `--team-name` and task description
#### Full Pipeline (Fan-out + Generator-Critic)
2. Assess topic complexity:
```javascript
// 并行创意: IDEA-001 + IDEA-002 + IDEA-003 (no dependencies between them)
// Each gets a distinct agent owner for true parallel execution
const ideaAngles = selectedAngles.slice(0, 3)
ideaAngles.forEach((angle, i) => {
const ideatorName = ideaAngles.length > 1 ? `ideator-${i+1}` : 'ideator'
TaskCreate({ subject: `IDEA-00${i+1}: ${angle}角度创意生成`, description: `话题: ${taskDescription}\n角度: ${angle}\n\nSession: ${sessionFolder}\n输出: ideas/idea-00${i+1}.md`, activeForm: `${angle}创意生成中` })
TaskUpdate({ taskId: ideaIds[i], owner: ideatorName })
})
| Signal | Weight | Keywords |
|--------|--------|----------|
| Strategic/systemic | +3 | strategy, architecture, system, framework, paradigm |
| Multi-dimensional | +2 | multiple, compare, tradeoff, versus, alternative |
| Innovation-focused | +2 | innovative, creative, novel, breakthrough |
| Simple/basic | -2 | simple, quick, straightforward, basic |
// CHALLENGE-001: 批量挑战 (blockedBy all IDEA-001..003)
TaskCreate({ subject: "CHALLENGE-001: 批量创意挑战", description: `批量挑战所有角度的创意\n\nSession: ${sessionFolder}\n输入: ideas/idea-001..003.md\n输出: critiques/critique-001.md`, activeForm: "批量挑战中" })
TaskUpdate({ taskId: challenge1Id, owner: "challenger", addBlockedBy: ideaIds })
| Score | Complexity | Pipeline Recommendation |
|-------|------------|-------------------------|
| >= 4 | High | full |
| 2-3 | Medium | deep |
| 0-1 | Low | quick |
// IDEA-004: 修订 (blockedBy CHALLENGE-001)
TaskCreate({ subject: "IDEA-004: 创意修订", description: `基于批量挑战反馈修订\n\nSession: ${sessionFolder}\n输入: ideas/ + critiques/critique-001.md\n输出: ideas/idea-004.md`, activeForm: "修订中" })
TaskUpdate({ taskId: idea4Id, owner: "ideator", addBlockedBy: [challenge1Id] })
3. Ask for missing parameters via AskUserQuestion:
// SYNTH-001 (blockedBy IDEA-004)
TaskCreate({ subject: "SYNTH-001: 综合整合", description: `整合全部创意\n\nSession: ${sessionFolder}\n输入: ideas/ + critiques/\n输出: synthesis/synthesis-001.md`, activeForm: "综合中" })
TaskUpdate({ taskId: synthId, owner: "synthesizer", addBlockedBy: [idea4Id] })
| Question | Header | Options |
|----------|--------|---------|
| Pipeline mode | Mode | quick (3-step), deep (6-step with GC loop), full (7-step parallel + GC) |
| Divergence angles | Angles | Multi-select: Technical, Product, Innovation, Risk |
// EVAL-001 (blockedBy SYNTH-001)
TaskCreate({ subject: "EVAL-001: 评分排序", description: `最终评估\n\nSession: ${sessionFolder}\n输入: synthesis/ + shared-memory.json\n输出: evaluation/evaluation-001.md`, activeForm: "评估中" })
TaskUpdate({ taskId: evalId, owner: "evaluator", addBlockedBy: [synthId] })
```
4. Store requirements: mode, scope, angles, constraints
### Phase 4: Coordination Loop + Generator-Critic Control
**Success**: All parameters captured, pipeline finalized.
> **设计原则Stop-Wait**: 模型执行没有时间概念,禁止任何形式的轮询等待。
> - ❌ 禁止: `while` 循环 + `sleep` + 检查状态
> - ✅ 采用: 同步 `Task(run_in_background: false)` 调用Worker 返回 = 阶段完成信号
>
> 按 Phase 3 创建的任务链顺序,逐阶段 spawn worker 同步执行。
> Worker prompt 使用 SKILL.md Coordinator Spawn Template。
---
## Phase 2: Create Team + Initialize Session
**Objective**: Initialize team, session file, and shared memory.
**Workflow**:
1. Generate session ID: `BRS-<topic-slug>-<date>`
2. Create session folder structure
3. Call TeamCreate with team name
4. Initialize subdirectories: ideas/, critiques/, synthesis/, evaluation/
5. Initialize shared-memory.json with: topic, pipeline, angles, gc_round, generated_ideas, critique_insights, synthesis_themes, evaluation_scores
6. Write team-session.json with: session_id, team_name, topic, pipeline, status="active", created_at, updated_at
7. Workers are NOT pre-spawned here -> spawned per-stage in Phase 4
**Success**: Team created, session file written, directories initialized.
---
## Phase 3: Create Task Chain
**Objective**: Dispatch tasks based on selected pipeline with proper dependencies.
### Quick Pipeline
| Task ID | Subject | Owner | BlockedBy |
|---------|---------|-------|-----------|
| IDEA-001 | Multi-angle idea generation | ideator | - |
| CHALLENGE-001 | Assumption challenges | challenger | IDEA-001 |
| SYNTH-001 | Cross-idea synthesis | synthesizer | CHALLENGE-001 |
### Deep Pipeline (with Generator-Critic Loop)
| Task ID | Subject | Owner | BlockedBy |
|---------|---------|-------|-----------|
| IDEA-001 | Initial idea generation | ideator | - |
| CHALLENGE-001 | First round critique | challenger | IDEA-001 |
| IDEA-002 | Idea revision (GC Round 1) | ideator | CHALLENGE-001 |
| CHALLENGE-002 | Second round validation | challenger | IDEA-002 |
| SYNTH-001 | Synthesis | synthesizer | CHALLENGE-002 |
| EVAL-001 | Scoring and ranking | evaluator | SYNTH-001 |
### Full Pipeline (Fan-out + Generator-Critic)
| Task ID | Subject | Owner | BlockedBy |
|---------|---------|-------|-----------|
| IDEA-001 | Technical angle ideas | ideator-1 | - |
| IDEA-002 | Product angle ideas | ideator-2 | - |
| IDEA-003 | Innovation angle ideas | ideator-3 | - |
| CHALLENGE-001 | Batch critique | challenger | IDEA-001, IDEA-002, IDEA-003 |
| IDEA-004 | Revised ideas | ideator | CHALLENGE-001 |
| SYNTH-001 | Synthesis | synthesizer | IDEA-004 |
| EVAL-001 | Evaluation | evaluator | SYNTH-001 |
**Success**: All tasks created with correct dependencies and owners assigned.
---
## Phase 4: Coordination Loop + Generator-Critic Control
**Objective**: Monitor worker callbacks and advance pipeline.
> **Design Principle (Stop-Wait)**: No time-based polling. Worker return = stage complete signal.
| Received Message | Action |
|-----------------|--------|
| ideator: ideas_ready | Read ideas team_msg log TaskUpdate completed unblock CHALLENGE |
| challenger: critique_ready | Read critique **Generator-Critic 判断** → 决定是否触发 IDEA-fix |
| ideator: ideas_revised | Read revised ideas team_msg log TaskUpdate completed unblock CHALLENGE-2 |
| synthesizer: synthesis_ready | Read synthesis team_msg log TaskUpdate completed unblock EVAL (if exists) |
| evaluator: evaluation_ready | Read evaluation team_msg log TaskUpdate completed Phase 5 |
| All tasks completed | Phase 5 |
| ideator: ideas_ready | Read ideas -> team_msg log -> TaskUpdate completed -> unblock CHALLENGE |
| challenger: critique_ready | Read critique -> **Generator-Critic decision** -> decide if IDEA-fix needed |
| ideator: ideas_revised | Read revised ideas -> team_msg log -> TaskUpdate completed -> unblock next CHALLENGE |
| synthesizer: synthesis_ready | Read synthesis -> team_msg log -> TaskUpdate completed -> unblock EVAL (if exists) |
| evaluator: evaluation_ready | Read evaluation -> team_msg log -> TaskUpdate completed -> Phase 5 |
| All tasks completed | -> Phase 5 |
#### Generator-Critic Loop Control
### Generator-Critic Loop Control
```javascript
if (msgType === 'critique_ready') {
const critique = Read(`${sessionFolder}/critiques/critique-${round}.md`)
const sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
// Count HIGH/CRITICAL severity challenges
const criticalCount = (critique.match(/severity:\s*(HIGH|CRITICAL)/gi) || []).length
const gcRound = sharedMemory.gc_round || 0
if (criticalCount > 0 && gcRound < sharedMemory.max_gc_rounds) {
// Trigger another ideator round
sharedMemory.gc_round = gcRound + 1
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "coordinator", to: "ideator",
type: "gc_loop_trigger",
summary: `[coordinator] Generator-Critic round ${gcRound + 1}: ${criticalCount} critical challenges need revision`
})
// Unblock IDEA-fix task
} else {
// Converged → unblock SYNTH
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "coordinator", to: "synthesizer",
type: "task_unblocked",
summary: `[coordinator] Critique converged (round ${gcRound}), proceeding to synthesis`
})
}
}
```
| Condition | Action |
|-----------|--------|
| critique_ready + criticalCount > 0 + gcRound < maxRounds | Trigger IDEA-fix task, increment gc_round |
| critique_ready + (criticalCount == 0 OR gcRound >= maxRounds) | Converged -> unblock SYNTH task |
### Phase 5: Report + Persist
**GC Round Tracking**:
1. Read critique file
2. Count severity: HIGH and CRITICAL
3. Read shared-memory.json for gc_round
4. If criticalCount > 0 AND gcRound < max_gc_rounds:
- Increment gc_round in shared-memory.json
- Log team_msg with type "gc_loop_trigger"
- Unblock IDEA-fix task
5. Else: Log team_msg with type "task_unblocked", unblock SYNTH
```javascript
// Read final results
const synthesis = Read(`${sessionFolder}/synthesis/synthesis-001.md`)
const evaluation = selectedPipeline !== 'quick' ? Read(`${sessionFolder}/evaluation/evaluation-001.md`) : null
const sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
---
// Report to user
SendMessage({
content: `## [coordinator] 头脑风暴完成
## Phase 5: Report + Persist
**话题**: ${taskDescription}
**管道**: ${selectedPipeline}
**Generator-Critic 轮次**: ${sharedMemory.gc_round}
**创意总数**: ${sharedMemory.generated_ideas.length}
**Objective**: Completion report and follow-up options.
### 综合结果
${synthesis}
**Workflow**:
1. Load session state -> count completed tasks, duration
2. Read synthesis and evaluation results
3. Generate summary with: topic, pipeline, GC rounds, total ideas
4. Update session status -> "completed"
5. Report to user via SendMessage
6. Offer next steps via AskUserQuestion:
- New topic (continue brainstorming)
- Deep dive (analyze top-ranked idea)
- Close team (cleanup)
${evaluation ? `### 评估排序\n${evaluation}` : ''}`,
summary: `[coordinator] Brainstorm complete: ${sharedMemory.generated_ideas.length} ideas, ${sharedMemory.gc_round} GC rounds`
})
// Update session
updateSession(sessionFolder, { status: 'completed', completed_at: new Date().toISOString() })
AskUserQuestion({
questions: [{
question: "头脑风暴已完成。下一步:",
header: "Next",
multiSelect: false,
options: [
{ label: "新话题", description: "继续头脑风暴新话题" },
{ label: "深化探索", description: "对排名最高的创意进行深入分析" },
{ label: "关闭团队", description: "关闭所有 teammate 并清理" }
]
}]
})
```
---
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Teammate 无响应 | 发追踪消息2次无响应 → 重新 spawn |
| Generator-Critic 循环超限 | 强制收敛到 SYNTH 阶段 |
| Ideator 无法产出 | Coordinator 提供种子问题引导 |
| Challenger 全部标记 LOW | 直接进入 SYNTH,跳过修订 |
| 综合冲突无法解决 | 上报用户,AskUserQuestion 决定方向 |
| Teammate unresponsive | Send tracking message, 2 failures -> respawn worker |
| Generator-Critic loop exceeded | Force convergence to SYNTH stage |
| Ideator cannot produce | Provide seed questions as guidance |
| Challenger all LOW severity | Skip revision, proceed directly to SYNTH |
| Synthesis conflict unresolved | Report to user, AskUserQuestion for direction |
| Session corruption | Attempt recovery, fallback to manual reconciliation |

View File

@@ -1,16 +1,14 @@
# Role: evaluator
# Evaluator Role
评分排序与最终筛选。负责对综合方案进行多维度评分、优先级推荐、生成最终排名。
## Role Identity
## Identity
- **Name**: `evaluator`
- **Name**: `evaluator` | **Tag**: `[evaluator]`
- **Task Prefix**: `EVAL-*`
- **Responsibility**: Validation (评估验证)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[evaluator]`
- **Responsibility**: Validation (evaluation and ranking)
## Role Boundaries
## Boundaries
### MUST
@@ -19,171 +17,134 @@
- 仅通过 SendMessage 与 coordinator 通信
- Phase 2 读取 shared-memory.jsonPhase 5 写入 evaluation_scores
- 使用标准化评分维度,确保评分可追溯
- 为每个方案提供评分理由和推荐
### MUST NOT
- 生成新创意、挑战假设或综合整合
- 直接与其他 worker 角色通信
- 为其他角色创建任务
- 修改 shared-memory.json 中不属于自己的字段
- 生成新创意、挑战假设或综合整合
- 直接与其他 worker 角色通信
- 为其他角色创建任务
- 修改 shared-memory.json 中不属于自己的字段
- 在输出中省略 `[evaluator]` 标识
---
## Toolbox
### Tool Capabilities
| Tool | Type | Used By | Purpose |
|------|------|---------|---------|
| `TaskList` | Built-in | Phase 1 | Discover pending EVAL-* tasks |
| `TaskGet` | Built-in | Phase 1 | Get task details |
| `TaskUpdate` | Built-in | Phase 1/5 | Update task status |
| `Read` | Built-in | Phase 2 | Read shared-memory.json, synthesis files, ideas, critiques |
| `Write` | Built-in | Phase 3/5 | Write evaluation files, update shared memory |
| `Glob` | Built-in | Phase 2 | Find synthesis, idea, critique files |
| `SendMessage` | Built-in | Phase 5 | Report to coordinator |
| `mcp__ccw-tools__team_msg` | MCP | Phase 5 | Log communication |
---
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `evaluation_ready` | evaluator coordinator | Evaluation completed | 评估排序完成 |
| `error` | evaluator coordinator | Processing failure | 错误上报 |
| `evaluation_ready` | evaluator -> coordinator | Evaluation completed | Scoring and ranking complete |
| `error` | evaluator -> coordinator | Processing failure | Error report |
## Message Bus
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: <team-name>,
from: "evaluator",
to: "coordinator",
type: "evaluation_ready",
summary: "[evaluator] Evaluation complete: Top pick \"<title>\" (<score>/10)",
ref: <output-path>
})
```
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team <team-name> --from evaluator --to coordinator --type evaluation_ready --summary \"[evaluator] Evaluation complete\" --ref <output-path> --json")
```
---
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('EVAL-') &&
t.owner === 'evaluator' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
Standard task discovery flow: TaskList -> filter by prefix `EVAL-*` + owner match + pending + unblocked -> TaskGet -> TaskUpdate in_progress.
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
| Input | Source | Required |
|-------|--------|----------|
| Session folder | Task description (Session: line) | Yes |
| Synthesis results | synthesis/*.md files | Yes |
| All ideas | ideas/*.md files | No (for context) |
| All critiques | critiques/*.md files | No (for context) |
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
**Loading steps**:
// Read synthesis results
const synthesisFiles = Glob({ pattern: `${sessionFolder}/synthesis/*.md` })
const synthesis = synthesisFiles.map(f => Read(f))
1. Extract session path from task description (match "Session: <path>")
2. Glob synthesis files from session/synthesis/
3. Read all synthesis files for evaluation
4. Optionally read ideas and critiques for full context
// Read all ideas and critiques for full context
const ideaFiles = Glob({ pattern: `${sessionFolder}/ideas/*.md` })
const critiqueFiles = Glob({ pattern: `${sessionFolder}/critiques/*.md` })
### Phase 3: Evaluation and Scoring
**Scoring Dimensions**:
| Dimension | Weight | Focus |
|-----------|--------|-------|
| Feasibility | 30% | Technical feasibility, resource needs, timeline |
| Innovation | 25% | Novelty, differentiation, breakthrough potential |
| Impact | 25% | Scope of impact, value creation, problem resolution |
| Cost Efficiency | 20% | Implementation cost, risk cost, opportunity cost |
**Weighted Score Calculation**:
```
weightedScore = (Feasibility * 0.30) + (Innovation * 0.25) + (Impact * 0.25) + (Cost * 0.20)
```
### Phase 3: Evaluation & Scoring
**Evaluation Structure per Proposal**:
- Score for each dimension (1-10)
- Rationale for each score
- Overall recommendation (Strong Recommend / Recommend / Consider / Pass)
```javascript
// Scoring dimensions:
// 1. Feasibility (30%) — 技术可行性、资源需求、时间框架
// 2. Innovation (25%) — 新颖性、差异化、突破性
// 3. Impact (25%) — 影响范围、价值创造、问题解决度
// 4. Cost (20%) — 实施成本、风险成本、机会成本
const evalNum = task.subject.match(/EVAL-(\d+)/)?.[1] || '001'
const outputPath = `${sessionFolder}/evaluation/evaluation-${evalNum}.md`
const evaluationContent = `# Evaluation — Round ${evalNum}
**Input**: ${synthesisFiles.length} synthesis files
**Scoring Dimensions**: Feasibility(30%), Innovation(25%), Impact(25%), Cost(20%)
## Scoring Matrix
| Rank | Proposal | Feasibility | Innovation | Impact | Cost | **Weighted Score** |
|------|----------|-------------|------------|--------|------|-------------------|
${scoredProposals.map((p, i) => `| ${i + 1} | ${p.title} | ${p.feasibility}/10 | ${p.innovation}/10 | ${p.impact}/10 | ${p.cost}/10 | **${p.weightedScore.toFixed(1)}** |`).join('\n')}
## Detailed Evaluation
${scoredProposals.map((p, i) => `### ${i + 1}. ${p.title} (Score: ${p.weightedScore.toFixed(1)}/10)
**Feasibility** (${p.feasibility}/10):
${p.feasibilityRationale}
**Innovation** (${p.innovation}/10):
${p.innovationRationale}
**Impact** (${p.impact}/10):
${p.impactRationale}
**Cost Efficiency** (${p.cost}/10):
${p.costRationale}
**Recommendation**: ${p.recommendation}
`).join('\n')}
## Final Recommendation
**Top Pick**: ${scoredProposals[0].title}
**Runner-up**: ${scoredProposals.length > 1 ? scoredProposals[1].title : 'N/A'}
### Action Items
${actionItems.map((item, i) => `${i + 1}. ${item}`).join('\n')}
### Risk Summary
${riskSummary.map(r => `- **${r.risk}**: ${r.mitigation}`).join('\n')}
`
Write(outputPath, evaluationContent)
```
**Output file structure**:
- File: `<session>/evaluation/evaluation-<num>.md`
- Sections: Input summary, Scoring Matrix (ranked table), Detailed Evaluation per proposal, Final Recommendation, Action Items, Risk Summary
### Phase 4: Consistency Check
```javascript
// Verify scoring consistency
// - No proposal should have all 10s
// - Scores should reflect critique findings
// - Rankings should be deterministic
const maxScore = Math.max(...scoredProposals.map(p => p.weightedScore))
const minScore = Math.min(...scoredProposals.map(p => p.weightedScore))
const spread = maxScore - minScore
if (spread < 0.5 && scoredProposals.length > 1) {
// Too close — re-evaluate differentiators
}
```
| Check | Pass Criteria | Action on Failure |
|-------|---------------|-------------------|
| Score spread | max - min >= 0.5 (with >1 proposal) | Re-evaluate differentiators |
| No perfect scores | Not all 10s | Adjust scores to reflect critique findings |
| Ranking deterministic | Consistent ranking | Verify calculation |
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.evaluation_scores = scoredProposals.map(p => ({
title: p.title,
weighted_score: p.weightedScore,
rank: p.rank,
recommendation: p.recommendation
}))
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "evaluator",
to: "coordinator",
type: "evaluation_ready",
summary: `[evaluator] Evaluation complete: Top pick "${scoredProposals[0].title}" (${scoredProposals[0].weightedScore.toFixed(1)}/10)`,
ref: outputPath
})
Standard report flow: team_msg log -> SendMessage with `[evaluator]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [evaluator] Evaluation Results
**Shared Memory Update**:
1. Set shared-memory.json.evaluation_scores
2. Each entry: title, weighted_score, rank, recommendation
**Task**: ${task.subject}
**Proposals Evaluated**: ${scoredProposals.length}
**Output**: ${outputPath}
### Rankings
${scoredProposals.map((p, i) => `${i + 1}. **${p.title}** — ${p.weightedScore.toFixed(1)}/10 (${p.recommendation})`).join('\n')}
### Top Pick: ${scoredProposals[0].title}
${scoredProposals[0].feasibilityRationale}`,
summary: `[evaluator] Top: ${scoredProposals[0].title} (${scoredProposals[0].weightedScore.toFixed(1)}/10)`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
---
## Error Handling
@@ -193,3 +154,4 @@ TaskUpdate({ taskId: task.id, status: 'completed' })
| Synthesis files not found | Notify coordinator |
| Only one proposal | Evaluate against absolute criteria, recommend or reject |
| All proposals score below 5 | Flag all as weak, recommend re-brainstorming |
| Critical issue beyond scope | SendMessage error to coordinator |

View File

@@ -1,16 +1,14 @@
# Role: ideator
# Ideator Role
多角度创意生成者。负责发散思维、概念探索、创意修订。作为 Generator-Critic 循环中的 Generator 角色。
## Role Identity
## Identity
- **Name**: `ideator`
- **Name**: `ideator` | **Tag**: `[ideator]`
- **Task Prefix**: `IDEA-*`
- **Responsibility**: Read-only analysis (创意生成不修改代码)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[ideator]`
- **Responsibility**: Read-only analysis (idea generation, no code modification)
## Role Boundaries
## Boundaries
### MUST
@@ -18,205 +16,137 @@
- 所有输出SendMessage、team_msg、日志必须带 `[ideator]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- Phase 2 读取 shared-memory.jsonPhase 5 写入 generated_ideas
- 针对每个指定角度产出至少3个创意
### MUST NOT
- 执行挑战/评估/综合等其他角色工作
- 直接与其他 worker 角色通信
- 为其他角色创建任务TaskCreate 是 coordinator 专属)
- 修改 shared-memory.json 中不属于自己的字段
- 执行挑战/评估/综合等其他角色工作
- 直接与其他 worker 角色通信
- 为其他角色创建任务TaskCreate 是 coordinator 专属)
- 修改 shared-memory.json 中不属于自己的字段
- 在输出中省略 `[ideator]` 标识
---
## Toolbox
### Tool Capabilities
| Tool | Type | Used By | Purpose |
|------|------|---------|---------|
| `TaskList` | Built-in | Phase 1 | Discover pending IDEA-* tasks |
| `TaskGet` | Built-in | Phase 1 | Get task details |
| `TaskUpdate` | Built-in | Phase 1/5 | Update task status |
| `Read` | Built-in | Phase 2 | Read shared-memory.json, critique files |
| `Write` | Built-in | Phase 3/5 | Write idea files, update shared memory |
| `Glob` | Built-in | Phase 2 | Find critique files |
| `SendMessage` | Built-in | Phase 5 | Report to coordinator |
| `mcp__ccw-tools__team_msg` | MCP | Phase 5 | Log communication |
---
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `ideas_ready` | ideator coordinator | Initial ideas generated | 初始创意完成 |
| `ideas_revised` | ideator coordinator | Ideas revised after critique | 修订创意完成 (GC 循环) |
| `error` | ideator coordinator | Processing failure | 错误上报 |
| `ideas_ready` | ideator -> coordinator | Initial ideas generated | Initial idea generation complete |
| `ideas_revised` | ideator -> coordinator | Ideas revised after critique | Revised ideas complete (GC loop) |
| `error` | ideator -> coordinator | Processing failure | Error report |
## Message Bus
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: <team-name>,
from: "ideator",
to: "coordinator",
type: <ideas_ready|ideas_revised>,
summary: "[ideator] <Generated|Revised> <count> ideas (round <num>)",
ref: <output-path>
})
```
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team <team-name> --from ideator --to coordinator --type <message-type> --summary \"[ideator] ideas complete\" --ref <output-path> --json")
```
---
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
// Parse agent name for parallel instances (e.g., ideator-1, ideator-2)
const agentNameMatch = args.match(/--agent-name[=\s]+([\w-]+)/)
const agentName = agentNameMatch ? agentNameMatch[1] : 'ideator'
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('IDEA-') &&
t.owner === agentName && // Use agentName (e.g., 'ideator-1') instead of hardcoded 'ideator'
t.status === 'pending' &&
t.blockedBy.length === 0
)
Standard task discovery flow: TaskList -> filter by prefix `IDEA-*` + owner match + pending + unblocked -> TaskGet -> TaskUpdate in_progress.
if (myTasks.length === 0) return // idle
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
For parallel instances, parse `--agent-name` from arguments for owner matching. Falls back to `ideator` for single-instance roles.
### Phase 2: Context Loading + Shared Memory Read
```javascript
// Extract session folder from task description
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
| Input | Source | Required |
|-------|--------|----------|
| Session folder | Task description (Session: line) | Yes |
| Topic | shared-memory.json | Yes |
| Angles | shared-memory.json | Yes |
| GC Round | shared-memory.json | Yes |
| Previous critique | critiques/*.md | For revision tasks only |
| Previous ideas | shared-memory.json.generated_ideas | No |
// Read shared memory
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
**Loading steps**:
const topic = sharedMemory.topic || task.description
const angles = sharedMemory.angles || ['技术', '产品', '创新']
const gcRound = sharedMemory.gc_round || 0
// If this is a revision task (GC loop), read previous critique
let previousCritique = null
if (task.subject.includes('修订') || task.subject.includes('fix')) {
const critiqueFiles = Glob({ pattern: `${sessionFolder}/critiques/*.md` })
if (critiqueFiles.length > 0) {
previousCritique = Read(critiqueFiles[critiqueFiles.length - 1])
}
}
// Read previous ideas for context
const previousIdeas = sharedMemory.generated_ideas || []
```
1. Extract session path from task description (match "Session: <path>")
2. Read shared-memory.json for topic, angles, gc_round
3. If task is revision (subject contains "revision" or "fix"):
- Glob critique files
- Read latest critique for revision context
4. Read previous ideas from shared-memory.generated_ideas
### Phase 3: Idea Generation
```javascript
// Determine generation mode
const isRevision = !!previousCritique
| Mode | Condition | Focus |
|------|-----------|-------|
| Initial Generation | No previous critique | Multi-angle divergent thinking |
| GC Revision | Previous critique exists | Address HIGH/CRITICAL challenges |
if (isRevision) {
// === Generator-Critic Revision Mode ===
// Focus on HIGH/CRITICAL severity challenges
// Revise or replace challenged ideas
// Keep unchallenged ideas intact
// Output structure:
// - Retained ideas (unchallenged)
// - Revised ideas (with revision rationale)
// - New replacement ideas (for unsalvageable ones)
} else {
// === Initial Generation Mode ===
// For each angle, generate 3+ ideas
// Each idea includes:
// - Title
// - Description (2-3 sentences)
// - Key assumption
// - Potential impact
// - Implementation hint
}
**Initial Generation Mode**:
- For each angle, generate 3+ ideas
- Each idea includes: title, description (2-3 sentences), key assumption, potential impact, implementation hint
// Write ideas to file
const ideaNum = task.subject.match(/IDEA-(\d+)/)?.[1] || '001'
const outputPath = `${sessionFolder}/ideas/idea-${ideaNum}.md`
**GC Revision Mode**:
- Focus on HIGH/CRITICAL severity challenges from critique
- Retain unchallenged ideas intact
- Revise ideas with revision rationale
- Replace unsalvageable ideas with new alternatives
const ideaContent = `# ${isRevision ? 'Revised' : 'Initial'} Ideas — Round ${ideaNum}
**Topic**: ${topic}
**Angles**: ${angles.join(', ')}
**Mode**: ${isRevision ? 'Generator-Critic Revision (Round ' + gcRound + ')' : 'Initial Generation'}
${isRevision ? `## Revision Context\n\nBased on critique feedback:\n${previousCritique}\n\n` : ''}
## Ideas
${generatedIdeas.map((idea, i) => `### Idea ${i + 1}: ${idea.title}
**Description**: ${idea.description}
**Key Assumption**: ${idea.assumption}
**Potential Impact**: ${idea.impact}
**Implementation Hint**: ${idea.implementation}
${isRevision ? `**Revision Note**: ${idea.revision_note || 'New idea'}` : ''}
`).join('\n')}
## Summary
- Total ideas: ${generatedIdeas.length}
- ${isRevision ? `Retained: ${retainedCount}, Revised: ${revisedCount}, New: ${newCount}` : `Per angle: ${angles.map(a => `${a}: ${countByAngle[a]}`).join(', ')}`}
`
Write(outputPath, ideaContent)
```
**Output file structure**:
- File: `<session>/ideas/idea-<num>.md`
- Sections: Topic, Angles, Mode, [Revision Context if applicable], Ideas list, Summary
### Phase 4: Self-Review
```javascript
// Verify minimum idea count
const ideaCount = generatedIdeas.length
const minimumRequired = isRevision ? 3 : 6
if (ideaCount < minimumRequired) {
// Generate additional ideas to meet minimum
}
// Verify no duplicate ideas
const titles = generatedIdeas.map(i => i.title.toLowerCase())
const duplicates = titles.filter((t, i) => titles.indexOf(t) !== i)
if (duplicates.length > 0) {
// Replace duplicates
}
```
| Check | Pass Criteria | Action on Failure |
|-------|---------------|-------------------|
| Minimum count | >= 6 (initial) or >= 3 (revision) | Generate additional ideas |
| No duplicates | All titles unique | Replace duplicates |
| Angle coverage | At least 1 idea per angle | Generate missing angle ideas |
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
// Update shared memory
sharedMemory.generated_ideas = [
...sharedMemory.generated_ideas,
...generatedIdeas.map(i => ({
id: `idea-${ideaNum}-${i.index}`,
title: i.title,
round: parseInt(ideaNum),
revised: isRevision
}))
]
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
// Log message
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "ideator",
to: "coordinator",
type: isRevision ? "ideas_revised" : "ideas_ready",
summary: `[ideator] ${isRevision ? 'Revised' : 'Generated'} ${ideaCount} ideas (round ${ideaNum})`,
ref: outputPath
})
Standard report flow: team_msg log -> SendMessage with `[ideator]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [ideator] ${isRevision ? 'Ideas Revised' : 'Ideas Generated'}
**Shared Memory Update**:
1. Append new ideas to shared-memory.json.generated_ideas
2. Each entry: id, title, round, revised flag
**Task**: ${task.subject}
**Ideas**: ${ideaCount}
**Output**: ${outputPath}
### Highlights
${generatedIdeas.slice(0, 3).map(i => `- **${i.title}**: ${i.description.substring(0, 100)}...`).join('\n')}`,
summary: `[ideator] ${ideaCount} ideas ${isRevision ? 'revised' : 'generated'}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('IDEA-') &&
t.owner === agentName && // Use agentName for parallel instance filtering
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (nextTasks.length > 0) {
// Continue with next task → back to Phase 1
}
```
---
## Error Handling
@@ -226,4 +156,5 @@ if (nextTasks.length > 0) {
| Session folder not found | Notify coordinator, request path |
| Shared memory read fails | Initialize empty, proceed with generation |
| Topic too vague | Generate meta-questions as seed ideas |
| Previous critique not found (revision) | Generate new ideas instead of revising |
| Previous critique not found (revision task) | Generate new ideas instead of revising |
| Critical issue beyond scope | SendMessage error to coordinator |

View File

@@ -1,16 +1,14 @@
# Role: synthesizer
# Synthesizer Role
跨想法整合者。负责从多个创意和挑战反馈中提取主题、解决冲突、生成整合方案。
## Role Identity
## Identity
- **Name**: `synthesizer`
- **Name**: `synthesizer` | **Tag**: `[synthesizer]`
- **Task Prefix**: `SYNTH-*`
- **Responsibility**: Read-only analysis (综合整合)
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[synthesizer]`
- **Responsibility**: Read-only analysis (synthesis and integration)
## Role Boundaries
## Boundaries
### MUST
@@ -18,182 +16,146 @@
- 所有输出必须带 `[synthesizer]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- Phase 2 读取 shared-memory.jsonPhase 5 写入 synthesis_themes
- 从所有创意和挑战中提取共同主题
- 解决相互矛盾的想法,生成整合方案
### MUST NOT
- 生成新创意、挑战假设或评分排序
- 直接与其他 worker 角色通信
- 为其他角色创建任务
- 修改 shared-memory.json 中不属于自己的字段
- 生成新创意、挑战假设或评分排序
- 直接与其他 worker 角色通信
- 为其他角色创建任务
- 修改 shared-memory.json 中不属于自己的字段
- 在输出中省略 `[synthesizer]` 标识
---
## Toolbox
### Tool Capabilities
| Tool | Type | Used By | Purpose |
|------|------|---------|---------|
| `TaskList` | Built-in | Phase 1 | Discover pending SYNTH-* tasks |
| `TaskGet` | Built-in | Phase 1 | Get task details |
| `TaskUpdate` | Built-in | Phase 1/5 | Update task status |
| `Read` | Built-in | Phase 2 | Read shared-memory.json, idea files, critique files |
| `Write` | Built-in | Phase 3/5 | Write synthesis files, update shared memory |
| `Glob` | Built-in | Phase 2 | Find idea and critique files |
| `SendMessage` | Built-in | Phase 5 | Report to coordinator |
| `mcp__ccw-tools__team_msg` | MCP | Phase 5 | Log communication |
---
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `synthesis_ready` | synthesizer coordinator | Synthesis completed | 综合整合完成 |
| `error` | synthesizer coordinator | Processing failure | 错误上报 |
| `synthesis_ready` | synthesizer -> coordinator | Synthesis completed | Cross-idea synthesis complete |
| `error` | synthesizer -> coordinator | Processing failure | Error report |
## Message Bus
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: <team-name>,
from: "synthesizer",
to: "coordinator",
type: "synthesis_ready",
summary: "[synthesizer] Synthesis complete: <themeCount> themes, <proposalCount> proposals",
ref: <output-path>
})
```
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team <team-name> --from synthesizer --to coordinator --type synthesis_ready --summary \"[synthesizer] Synthesis complete\" --ref <output-path> --json")
```
---
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('SYNTH-') &&
t.owner === 'synthesizer' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
Standard task discovery flow: TaskList -> filter by prefix `SYNTH-*` + owner match + pending + unblocked -> TaskGet -> TaskUpdate in_progress.
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionMatch = task.description.match(/Session:\s*([^\n]+)/)
const sessionFolder = sessionMatch?.[1]?.trim()
| Input | Source | Required |
|-------|--------|----------|
| Session folder | Task description (Session: line) | Yes |
| All ideas | ideas/*.md files | Yes |
| All critiques | critiques/*.md files | Yes |
| GC rounds completed | shared-memory.json.gc_round | Yes |
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
**Loading steps**:
// Read all ideas and critiques
const ideaFiles = Glob({ pattern: `${sessionFolder}/ideas/*.md` })
const critiqueFiles = Glob({ pattern: `${sessionFolder}/critiques/*.md` })
const allIdeas = ideaFiles.map(f => Read(f))
const allCritiques = critiqueFiles.map(f => Read(f))
```
1. Extract session path from task description (match "Session: <path>")
2. Glob all idea files from session/ideas/
3. Glob all critique files from session/critiques/
4. Read all idea and critique files for synthesis
5. Read shared-memory.json for context
### Phase 3: Synthesis Execution
```javascript
// Synthesis process:
// 1. Theme Extraction — 识别跨创意的共同主题
// 2. Conflict Resolution — 解决相互矛盾的想法
// 3. Complementary Grouping — 将互补的创意组合
// 4. Gap Identification — 发现未覆盖的视角
// 5. Integrated Proposal — 生成1-3个整合方案
**Synthesis Process**:
const synthNum = task.subject.match(/SYNTH-(\d+)/)?.[1] || '001'
const outputPath = `${sessionFolder}/synthesis/synthesis-${synthNum}.md`
| Step | Action |
|------|--------|
| 1. Theme Extraction | Identify common themes across ideas |
| 2. Conflict Resolution | Resolve contradictory ideas |
| 3. Complementary Grouping | Group complementary ideas together |
| 4. Gap Identification | Discover uncovered perspectives |
| 5. Integrated Proposal | Generate 1-3 consolidated proposals |
const synthesisContent = `# Synthesis — Round ${synthNum}
**Theme Extraction**:
- Cross-reference ideas for shared concepts
- Rate theme strength (1-10)
- List supporting ideas per theme
**Input**: ${ideaFiles.length} idea files, ${critiqueFiles.length} critique files
**GC Rounds Completed**: ${sharedMemory.gc_round || 0}
**Conflict Resolution**:
- Identify contradictory ideas
- Determine resolution approach
- Document rationale for resolution
## Extracted Themes
**Integrated Proposal Structure**:
- Core concept description
- Source ideas combined
- Addressed challenges from critiques
- Feasibility score (1-10)
- Innovation score (1-10)
- Key benefits list
- Remaining risks list
${themes.map((theme, i) => `### Theme ${i + 1}: ${theme.name}
**Description**: ${theme.description}
**Supporting Ideas**: ${theme.supportingIdeas.join(', ')}
**Strength**: ${theme.strength}/10
`).join('\n')}
## Conflict Resolution
${conflicts.map(c => `### ${c.idea1} vs ${c.idea2}
**Nature**: ${c.nature}
**Resolution**: ${c.resolution}
**Rationale**: ${c.rationale}
`).join('\n')}
## Integrated Proposals
${proposals.map((p, i) => `### Proposal ${i + 1}: ${p.title}
**Core Concept**: ${p.concept}
**Combines**: ${p.sourceIdeas.join(' + ')}
**Addresses Challenges**: ${p.addressedChallenges.join(', ')}
**Feasibility**: ${p.feasibility}/10
**Innovation**: ${p.innovation}/10
**Description**:
${p.description}
**Key Benefits**:
${p.benefits.map(b => `- ${b}`).join('\n')}
**Remaining Risks**:
${p.risks.map(r => `- ${r}`).join('\n')}
`).join('\n')}
## Coverage Analysis
| Aspect | Covered | Gaps |
|--------|---------|------|
${coverageAnalysis.map(a => `| ${a.aspect} | ${a.covered ? '✅' : '❌'} | ${a.gap || '—'} |`).join('\n')}
`
Write(outputPath, synthesisContent)
```
**Output file structure**:
- File: `<session>/synthesis/synthesis-<num>.md`
- Sections: Input summary, Extracted Themes, Conflict Resolution, Integrated Proposals, Coverage Analysis
### Phase 4: Quality Check
```javascript
// Verify synthesis quality
const proposalCount = proposals.length
const themeCount = themes.length
if (proposalCount === 0) {
// At least one proposal required
}
if (themeCount < 2) {
// May need to look for more patterns
}
```
| Check | Pass Criteria | Action on Failure |
|-------|---------------|-------------------|
| Proposal count | >= 1 proposal | Generate at least one proposal |
| Theme count | >= 2 themes | Look for more patterns |
| Conflict resolution | All conflicts documented | Address unresolved conflicts |
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.synthesis_themes = themes.map(t => ({
name: t.name,
strength: t.strength,
supporting_ideas: t.supportingIdeas
}))
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "synthesizer",
to: "coordinator",
type: "synthesis_ready",
summary: `[synthesizer] Synthesis complete: ${themeCount} themes, ${proposalCount} proposals`,
ref: outputPath
})
Standard report flow: team_msg log -> SendMessage with `[synthesizer]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [synthesizer] Synthesis Results
**Shared Memory Update**:
1. Set shared-memory.json.synthesis_themes
2. Each entry: name, strength, supporting_ideas
**Task**: ${task.subject}
**Themes**: ${themeCount}
**Proposals**: ${proposalCount}
**Conflicts Resolved**: ${conflicts.length}
**Output**: ${outputPath}
### Top Proposals
${proposals.slice(0, 3).map((p, i) => `${i + 1}. **${p.title}** — ${p.concept} (Feasibility: ${p.feasibility}/10, Innovation: ${p.innovation}/10)`).join('\n')}`,
summary: `[synthesizer] ${themeCount} themes, ${proposalCount} proposals`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('SYNTH-') && t.owner === 'synthesizer' &&
t.status === 'pending' && t.blockedBy.length === 0
)
if (nextTasks.length > 0) { /* back to Phase 1 */ }
```
---
## Error Handling
@@ -203,3 +165,4 @@ if (nextTasks.length > 0) { /* back to Phase 1 */ }
| No ideas/critiques found | Notify coordinator |
| Irreconcilable conflicts | Present both sides, recommend user decision |
| Only one idea survives | Create single focused proposal |
| Critical issue beyond scope | SendMessage error to coordinator |