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,178 +6,180 @@ allowed-tools: TeamCreate(*), TeamDelete(*), SendMessage(*), TaskCreate(*), Task
# Team Ultra Analyze
深度协作分析团队技能。将单体分析工作流拆分为 5 角色协作:探索→分析→讨论→综合。支持 Quick/Standard/Deep 三种管道模式,通过讨论循环实现用户引导的渐进式理解深化。所有成员通过 `--role=xxx` 路由到角色执行逻辑。
Deep collaborative analysis team skill. Splits monolithic analysis into 5-role collaboration: explore -> analyze -> discuss -> synthesize. Supports Quick/Standard/Deep pipeline modes with configurable depth (N parallel agents). Discussion loops enable user-guided progressive understanding. All members route via `--role=xxx`.
## Architecture Overview
## Architecture
```
┌─────────────────────────────────────────────────────────┐
Skill(skill="team-ultra-analyze", args="--role=xxx")
└──────────────────────┬──────────────────────────────────┘
│ Role Router
┌──────────┬───────┼───────────┬───────────┐
↓ ↓ ↓ ↓
┌────────┐┌────────┐┌────────┐┌──────────┐┌───────────┐
│coordi- ││explorer││analyst ││discussant││synthesizer│
│nator ││EXPLORE-││ANALYZE-││DISCUSS-* ││SYNTH-* │
│ roles/ ││* roles/││* roles/││ roles/ ││ roles/ │
└────────┘└────────┘└────────┘└──────────┘└───────────┘
+-------------------------------------------------------------+
| Skill(skill="team-ultra-analyze") |
| args="topic description" or args="--role=xxx" |
+----------------------------+--------------------------------+
| Role Router
+---- --role present? ----+
| NO | YES
v v
Orchestration Mode Role Dispatch
(auto -> coordinator) (route to role.md)
|
+-----+------+----------+-----------+
v v v v v
coordinator explorer analyst discussant synthesizer
EXPLORE-* ANALYZE-* DISCUSS-* SYNTH-*
```
## Command Architecture
```
roles/
├── coordinator/
├── role.md # 编排:话题澄清、管道选择、讨论循环、结果汇报
└── commands/
├── dispatch.md # 任务链创建与依赖管理
└── monitor.md # 进度监控 + 讨论循环
├── explorer/
├── role.md # 代码库探索
└── commands/
└── explore.md # cli-explore-agent 并行探索
├── analyst/
├── role.md # 深度分析
└── commands/
└── analyze.md # CLI 多视角分析
├── discussant/
├── role.md # 讨论处理 + 方向调整
└── commands/
└── deepen.md # 深入探索
└── synthesizer/
├── role.md # 综合结论
└── commands/
└── synthesize.md # 跨视角整合
+-- coordinator/
| +-- role.md # Orchestration: topic clarification, pipeline selection, discussion loop, reporting
| +-- commands/
| +-- dispatch.md # Task chain creation and dependency management
| +-- monitor.md # Progress monitoring + discussion loop
+-- explorer/
| +-- role.md # Codebase exploration
| +-- commands/
| +-- explore.md # cli-explore-agent parallel exploration
+-- analyst/
| +-- role.md # Deep analysis
| +-- commands/
| +-- analyze.md # CLI multi-perspective analysis
+-- discussant/
| +-- role.md # Discussion processing + direction adjustment
| +-- commands/
| +-- deepen.md # Deep-dive exploration
+-- synthesizer/
+-- role.md # Synthesis and conclusions
+-- commands/
+-- synthesize.md # Cross-perspective integration
```
**设计原则**: role.md 保留 Phase 1Task Discovery)和 Phase 5Report内联。Phase 2-4 根据复杂度决定内联或委派到 `commands/*.md`
**Design principle**: role.md retains Phase 1 (Task Discovery) and Phase 5 (Report) inline. Phase 2-4 delegate to `commands/*.md` based on complexity.
## Role Router
### Input Parsing
Parse `$ARGUMENTS` to extract `--role` and optional `--agent-name`:
Parse `$ARGUMENTS` to extract `--role` and optional `--agent-name`. If `--role` is absent, enter Orchestration Mode (auto route to coordinator). The `--agent-name` parameter supports parallel instances (e.g., explorer-1, analyst-2) and is passed through to role.md for task discovery filtering.
```javascript
const args = "$ARGUMENTS"
const roleMatch = args.match(/--role[=\s]+(\w+)/)
### Role Registry
if (!roleMatch) {
throw new Error("Missing --role argument. Available roles: coordinator, explorer, analyst, discussant, synthesizer")
}
| Role | File | Task Prefix | Type | Compact |
|------|------|-------------|------|---------|
| coordinator | [roles/coordinator/role.md](roles/coordinator/role.md) | (none) | orchestrator | **compress: must re-read** |
| explorer | [roles/explorer/role.md](roles/explorer/role.md) | EXPLORE-* | parallel worker | compress: must re-read |
| analyst | [roles/analyst/role.md](roles/analyst/role.md) | ANALYZE-* | parallel worker | compress: must re-read |
| discussant | [roles/discussant/role.md](roles/discussant/role.md) | DISCUSS-* | pipeline | compress: must re-read |
| synthesizer | [roles/synthesizer/role.md](roles/synthesizer/role.md) | SYNTH-* | pipeline | compress: must re-read |
const role = roleMatch[1]
const teamName = args.match(/--team[=\s]+([\w-]+)/)?.[1] || "ultra-analyze"
// --agent-name for parallel instances (e.g., explorer-1, analyst-2)
// Passed through to role.md for task discovery filtering
const agentName = args.match(/--agent-name[=\s]+([\w-]+)/)?.[1] || role
> **COMPACT PROTECTION**: Role files are execution documents, not reference material. When context compression occurs and role instructions are reduced to summaries, you **must immediately `Read` the corresponding role.md to reload before continuing execution**. Never execute any Phase based on compressed summaries alone.
### 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 the analysis topic.
**Invocation**: `Skill(skill="team-ultra-analyze", args="analysis topic description")`
**Lifecycle**:
```
User provides analysis topic
-> coordinator Phase 1-3: topic clarification -> TeamCreate -> pipeline selection -> create task chain
-> coordinator Phase 4: spawn depth explorers in parallel (background) -> STOP
-> Explorers execute -> SendMessage callback -> coordinator spawns analysts
-> Analysts execute -> SendMessage callback -> coordinator spawns discussant
-> Discussion loop (Deep mode: user feedback -> deepen -> re-analyze -> repeat)
-> coordinator spawns synthesizer -> final conclusions -> Phase 5 report
```
### Role Dispatch
**User Commands** (wake suspended coordinator):
```javascript
const VALID_ROLES = {
"coordinator": { file: "roles/coordinator/role.md", prefix: null },
"explorer": { file: "roles/explorer/role.md", prefix: "EXPLORE" },
"analyst": { file: "roles/analyst/role.md", prefix: "ANALYZE" },
"discussant": { file: "roles/discussant/role.md", prefix: "DISCUSS" },
"synthesizer": { file: "roles/synthesizer/role.md", prefix: "SYNTH" }
}
| Command | Action |
|---------|--------|
| `check` / `status` | Output execution status diagram, do not advance pipeline |
| `resume` / `continue` | Check worker status, advance to next pipeline 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/role.md](roles/coordinator/role.md) |
| `explorer` | EXPLORE-* | cli-explore-agent 多角度并行代码库探索 | [roles/explorer/role.md](roles/explorer/role.md) |
| `analyst` | ANALYZE-* | CLI 多视角深度分析 | [roles/analyst/role.md](roles/analyst/role.md) |
| `discussant` | DISCUSS-* | 用户反馈处理、方向调整、深入分析 | [roles/discussant/role.md](roles/discussant/role.md) |
| `synthesizer` | SYNTH-* | 跨视角整合、结论生成、决策追踪 | [roles/synthesizer/role.md](roles/synthesizer/role.md) |
---
## Shared Infrastructure
The following templates apply to all worker roles. Each role.md only needs to define **Phase 2-4** role-specific logic.
### Worker Phase 1: Task Discovery (shared by all workers)
Each 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 matches this agent's name + 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 recovery):
- Check if this task's output artifacts already exist
- Artifacts complete -> skip to Phase 5 report completion
- Artifacts incomplete or missing -> execute Phase 2-4 normally
### Worker Phase 5: Report (shared by all workers)
Standard report flow after task completion:
1. **Message Bus**: Call `mcp__ccw-tools__team_msg` to log message
- Parameters: operation="log", team=<team-name>, from=<role>, to="coordinator", type=<message-type>, summary="[<role>] <summary>", ref=<artifact-path>
- **CLI fallback**: When MCP unavailable -> `ccw team log --team <team> --from <role> --to coordinator --type <type> --summary "[<role>] ..." --json`
2. **SendMessage**: Send result to coordinator (both content and summary prefixed with `[<role>]`)
3. **TaskUpdate**: Mark task completed
4. **Loop**: Return to Phase 1 to check for next task
### Wisdom Accumulation (all roles)
Cross-task knowledge accumulation. Coordinator creates `wisdom/` directory during session initialization.
**Directory**:
```
<session-folder>/wisdom/
+-- learnings.md # Patterns and insights
+-- decisions.md # Analysis direction decisions
+-- conventions.md # Codebase conventions discovered
+-- 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 discoveries from this task into corresponding wisdom files.
### Role Isolation Rules
**核心原则**: 每个角色仅能执行自己职责范围内的工作。
| Allowed | Prohibited |
|---------|-----------|
| Process tasks matching 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/*.md | Modify resources outside own responsibility |
#### Output Tagging强制
Coordinator additionally prohibited: directly executing code exploration or analysis, directly calling cli-explore-agent or CLI analysis tools, bypassing workers to complete work.
所有角色的输出必须带 `[role_name]` 标识前缀:
### Shared Memory
```javascript
SendMessage({ content: `## [${role}] ...`, summary: `[${role}] ...` })
mcp__ccw-tools__team_msg({ summary: `[${role}] ...` })
```
Core shared artifact stored at `<session-folder>/shared-memory.json`. Each role reads the full memory but writes only to its own designated field:
#### Coordinator 隔离
| Role | Write Field |
|------|-------------|
| explorer | `explorations` |
| analyst | `analyses` |
| discussant | `discussions` |
| synthesizer | `synthesis` |
| coordinator | `decision_trail` + `current_understanding` |
| 允许 | 禁止 |
|------|------|
| 话题澄清 (AskUserQuestion) | ❌ 直接执行代码探索或分析 |
| 创建任务链 (TaskCreate) | ❌ 直接调用 cli-explore-agent |
| 管道选择 + 讨论循环驱动 | ❌ 直接调用 CLI 分析工具 |
| 监控进度 (消息总线) | ❌ 绕过 worker 自行完成 |
#### Worker 隔离
| 允许 | 禁止 |
|------|------|
| 处理自己前缀的任务 | ❌ 处理其他角色前缀的任务 |
| 读写 shared-memory.json (自己的字段) | ❌ 为其他角色创建任务 |
| SendMessage 给 coordinator | ❌ 直接与其他 worker 通信 |
### Team Configuration
```javascript
const TEAM_CONFIG = {
name: "ultra-analyze",
sessionDir: ".workflow/.team/UAN-{slug}-{date}/",
sharedMemory: "shared-memory.json",
analysisDimensions: ["architecture", "implementation", "performance", "security", "concept", "comparison", "decision"],
maxDiscussionRounds: 5
}
```
### Shared Memory核心产物
```javascript
// 各角色读取共享记忆
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
// 各角色写入自己负责的字段:
// explorer → sharedMemory.explorations
// analyst → sharedMemory.analyses
// discussant → sharedMemory.discussions
// synthesizer → sharedMemory.synthesis
// coordinator → sharedMemory.decision_trail + current_understanding
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
```
On startup, read the file. After completing work, update own field and write back. If file does not exist, initialize with empty object.
### Message Bus (All Roles)
```javascript
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: role,
to: "coordinator",
type: "<type>",
summary: `[${role}] <summary>`,
ref: "<file_path>"
})
```
All roles log messages before sending via SendMessage. Call `mcp__ccw-tools__team_msg` with: operation="log", team=<team-name>, from=<role>, to="coordinator", type=<message-type>, summary="[<role>] <summary>", ref=<file-path>.
| Role | Types |
|------|-------|
@@ -187,286 +189,251 @@ mcp__ccw-tools__team_msg({
| discussant | `discussion_processed`, `error` |
| synthesizer | `synthesis_ready`, `error` |
### CLI 回退
**CLI fallback**: When MCP unavailable -> `ccw team log --team "<team>" --from "<role>" --to "coordinator" --type "<type>" --summary "<summary>" --json`
```javascript
Bash(`ccw team log --team "${teamName}" --from "${role}" --to "coordinator" --type "<type>" --summary "<摘要>" --json`)
```
### Task Lifecycle (All Worker Roles)
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith(`${VALID_ROLES[role].prefix}-`) &&
t.owner === role &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
// Phase 2-4: Role-specific
// Phase 5: Report + Loop
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' })
```
---
## Three-Mode Pipeline Architecture
```
Quick: EXPLORE-001 ANALYZE-001 SYNTH-001
Standard: [EXPLORE-001..N](parallel) [ANALYZE-001..N](parallel) DISCUSS-001 SYNTH-001
Deep: [EXPLORE-001..N] → [ANALYZE-001..N] → DISCUSS-001 ANALYZE-fix DISCUSS-002 ... SYNTH-001
Quick: EXPLORE-001 -> ANALYZE-001 -> SYNTH-001
Standard: [EXPLORE-001..depth](parallel) -> [ANALYZE-001..depth](parallel) -> DISCUSS-001 -> SYNTH-001
Deep: [EXPLORE-001..depth] -> [ANALYZE-001..depth] -> DISCUSS-001 -> ANALYZE-fix -> DISCUSS-002 -> ... -> SYNTH-001
```
### Mode Auto-Detection
```javascript
function detectPipelineMode(args, taskDescription) {
const modeMatch = args.match(/--mode[=\s]+(quick|standard|deep)/)
if (modeMatch) return modeMatch[1]
// 自动检测
if (/快速|quick|overview|概览/.test(taskDescription)) return 'quick'
if (/深入|deep|thorough|详细|全面/.test(taskDescription)) return 'deep'
return 'standard'
}
```
Parse `--mode` from arguments first. If not specified, auto-detect from topic description:
| Condition | Mode | Depth |
|-----------|------|-------|
| `--mode=quick` explicit or topic contains "quick/overview/fast" | Quick | 1 |
| `--mode=deep` explicit or topic contains "deep/thorough/detailed/comprehensive" | Deep | N (from perspectives) |
| Default (no match) | Standard | N (from perspectives) |
**Depth** is determined by the number of selected analysis perspectives (e.g., architecture, implementation, performance, security, concept, comparison, decision). Quick mode always uses depth=1. Standard/Deep mode uses depth = number of selected perspectives.
### Discussion Loop (Deep Mode)
```
coordinator(AskUser) DISCUSS-N(deepen) [optional ANALYZE-fix] coordinator(AskUser) ... SYNTH
coordinator(AskUser) -> DISCUSS-N(deepen) -> [optional ANALYZE-fix] -> coordinator(AskUser) -> ... -> SYNTH
```
Maximum 5 discussion rounds. If exceeded, force synthesis and offer continuation option.
## Decision Recording Protocol
**⚠️ CRITICAL**: 继承自原 analyze-with-file 命令。分析过程中以下情况必须立即记录到 discussion.md
**CRITICAL**: Inherited from the original analyze-with-file command. During analysis, the following must be immediately recorded to discussion.md:
| Trigger | What to Record | Target Section |
|---------|---------------|----------------|
| **Direction choice** | 选择了什么、为什么、放弃了哪些替代方案 | `#### Decision Log` |
| **Key finding** | 发现内容、影响范围、置信度 | `#### Key Findings` |
| **Assumption change** | 旧假设→新理解、变更原因、影响 | `#### Corrected Assumptions` |
| **User feedback** | 用户原始输入、采纳/调整理由 | `#### User Input` |
| **Direction choice** | What was chosen, why, which alternatives were rejected | `#### Decision Log` |
| **Key finding** | Discovery content, impact scope, confidence level | `#### Key Findings` |
| **Assumption change** | Old assumption -> new understanding, reason for change, impact | `#### Corrected Assumptions` |
| **User feedback** | User's raw input, adoption/adjustment rationale | `#### User Input` |
## Cadence Control
**Beat model**: Event-driven. Each beat = coordinator wakes -> processes callback -> spawns next phase -> STOP.
```
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)
=====================================================================
```
**Discussion Loop Beat (Deep mode with configurable depth)**:
```
Phase 1 (explore): Spawn depth explorers simultaneously
EXPLORE-1, EXPLORE-2, ..., EXPLORE-depth (all parallel)
-> All complete -> coordinator wakes
Phase 2 (analyze): Spawn depth analysts simultaneously
ANALYZE-1, ANALYZE-2, ..., ANALYZE-depth (all parallel)
-> All complete -> coordinator wakes
Phase 3 (discuss): Spawn 1 discussant
DISCUSS-001
-> Complete -> coordinator asks user for direction
Phase 3a (loop): If user requests deeper analysis (Deep mode only):
-> Spawn ANALYZE-fix tasks -> DISCUSS-002 -> ask user -> repeat
-> Maximum 5 rounds
Phase 4 (synth): Spawn 1 synthesizer
SYNTHESIZE-001
-> Complete -> coordinator reports to user
```
**Pipeline Beat Views**:
```
Quick (3 beats, serial)
------------------------------------------------------
Beat 1 2 3
| | |
EXPLORE -> ANALYZE -> SYNTH
Standard (4 beats, parallel windows)
------------------------------------------------------
Beat 1 2 3 4
+----- ... ----+ +----- ... ----+ | |
E1 || E2 || EN A1 || A2 || AN -> DISCUSS -> SYNTH
+---- parallel ---+ +---- parallel ---+
Deep (4+ beats, with discussion loop)
------------------------------------------------------
Beat 1 2 3 3a... 4
+-...-+ +-...-+ | +-- loop --+ |
E1||EN A1||AN -> DISC -> A-fix->DISC -> SYNTH
(max 5 rounds)
```
**Checkpoints**:
| Trigger | Location | Behavior |
|---------|----------|----------|
| Discussion round (Deep mode) | After DISCUSS-N completes | Pause, AskUser for direction/continuation |
| Discussion loop limit | >5 rounds | Force synthesis, offer continuation |
| Pipeline stall | No ready + no running | Check missing tasks, report to user |
**Stall detection** (coordinator `handleCheck`):
| Check | Condition | Resolution |
|-------|-----------|------------|
| Worker unresponsive | in_progress task with no callback | Report waiting tasks, suggest user `resume` |
| Pipeline deadlock | No ready + no running + has pending | Check blockedBy chain, report blockage |
| Discussion loop over limit | DISCUSS round > 5 | Terminate loop, output latest discussion state |
## Task Metadata Registry
| Task ID | Role | Phase | Dependencies | Description |
|---------|------|-------|-------------|-------------|
| EXPLORE-1..depth | explorer | explore | (none) | Parallel codebase exploration, one per perspective |
| ANALYZE-1..depth | analyst | analyze | EXPLORE-1..depth (all complete) | Parallel deep analysis, one per perspective |
| DISCUSS-001 | discussant | discuss | ANALYZE-1..depth (all complete) | Process analysis results, identify gaps |
| ANALYZE-fix-N | analyst | discuss-loop | DISCUSS-N | Re-analysis for specific areas (Deep mode only) |
| DISCUSS-002..N | discussant | discuss-loop | ANALYZE-fix-N | Subsequent discussion rounds (Deep mode, max 5) |
| SYNTHESIZE-001 | synthesizer | synthesize | Last DISCUSS-N | Cross-perspective integration and conclusions |
**Dynamic task creation**: Coordinator creates EXPLORE-1 through EXPLORE-depth and ANALYZE-1 through ANALYZE-depth based on the number of selected perspectives. Discussion loop tasks (ANALYZE-fix-N, DISCUSS-002+) are created dynamically in Deep mode based on user feedback.
## Coordinator Spawn Template
When coordinator spawns workers, use background mode (Spawn-and-Stop pattern). The coordinator determines the depth (number of parallel agents) based on selected perspectives.
**Phase 1 - Spawn Explorers**: Create depth explorer agents in parallel (EXPLORE-1 through EXPLORE-depth). Each explorer receives its assigned perspective/domain and agent name for task matching. All spawned with run_in_background:true. Coordinator stops after spawning and waits for callbacks.
**Phase 2 - Spawn Analysts**: After all explorers complete, create depth analyst agents in parallel (ANALYZE-1 through ANALYZE-depth). Each analyst receives its assigned perspective matching the corresponding explorer. All spawned with run_in_background:true. Coordinator stops.
**Phase 3 - Spawn Discussant**: After all analysts complete, create 1 discussant. It processes all analysis results and presents findings to user. Coordinator stops.
**Phase 3a - Discussion Loop** (Deep mode only): Based on user feedback, coordinator may create additional ANALYZE-fix and DISCUSS tasks. Loop continues until user is satisfied or 5 rounds reached.
**Phase 4 - Spawn Synthesizer**: After final discussion round, create 1 synthesizer. It integrates all explorations, analyses, and discussions into final conclusions. Coordinator stops.
**Quick mode exception**: When depth=1, spawn single explorer, single analyst, single discussant, single synthesizer -- all as simple agents without numbered suffixes.
**Single spawn example** (worker template used for all roles):
```
Task({
subagent_type: "general-purpose",
description: "Spawn <role> worker",
team_name: <team-name>,
name: "<agent-name>",
run_in_background: true,
prompt: `You are team "<team-name>" <ROLE> (<agent-name>).
Your agent name is "<agent-name>", use it for task discovery owner matching.
## Primary Instruction
All work must be executed by calling Skill for role definition:
Skill(skill="team-ultra-analyze", args="--role=<role> --agent-name=<agent-name>")
Current topic: <task-description>
Session: <session-folder>
## Role Rules
- Only process <PREFIX>-* tasks where owner === "<agent-name>"
- All output prefixed with [<role>] identifier
- Communicate only 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. Execute role.md 5-Phase process
3. team_msg + SendMessage result to coordinator
4. TaskUpdate completed -> check next task`
})
```
## Team Configuration
| Setting | Value |
|---------|-------|
| Team name | ultra-analyze |
| Session directory | .workflow/.team/UAN-{slug}-{date}/ |
| Shared memory file | shared-memory.json |
| Analysis dimensions | architecture, implementation, performance, security, concept, comparison, decision |
| Max discussion rounds | 5 |
## Unified Session Directory
```
.workflow/.team/UAN-{slug}-{YYYY-MM-DD}/
├── shared-memory.json # 探索/分析/讨论/综合 共享记忆
├── discussion.md # ⭐ 理解演进 & 讨论时间线
├── explorations/ # Explorer output
├── exploration-001.json
└── exploration-002.json
├── analyses/ # Analyst output
├── analysis-001.json
└── analysis-002.json
├── discussions/ # Discussant output
└── discussion-round-001.json
└── conclusions.json # Synthesizer output
+-- shared-memory.json # Exploration/analysis/discussion/synthesis shared memory
+-- discussion.md # Understanding evolution and discussion timeline
+-- explorations/ # Explorer output
| +-- exploration-001.json
| +-- exploration-002.json
+-- analyses/ # Analyst output
| +-- analysis-001.json
| +-- analysis-002.json
+-- discussions/ # Discussant output
| +-- discussion-round-001.json
+-- conclusions.json # Synthesizer output
+-- wisdom/ # Cross-task knowledge
| +-- learnings.md
| +-- decisions.md
| +-- conventions.md
| +-- issues.md
```
## Coordinator Spawn Template
## Session Resume
```javascript
TeamCreate({ team_name: teamName })
Coordinator supports `--resume` / `--continue` for interrupted sessions:
// ── Determine parallel agent count ──
const perspectiveCount = selectedPerspectives.length
const isParallel = perspectiveCount > 1
// ── Explorers ──
// Quick mode (1 perspective): single "explorer"
// Standard/Deep mode (N perspectives): "explorer-1", "explorer-2", ...
if (isParallel) {
for (let i = 0; i < perspectiveCount; i++) {
const agentName = `explorer-${i + 1}`
Task({
subagent_type: "general-purpose",
description: `Spawn ${agentName} worker`,
team_name: teamName,
name: agentName,
prompt: `你是 team "${teamName}" 的 EXPLORER (${agentName})。
你的 agent 名称是 "${agentName}",任务发现时用此名称匹配 owner。
当你收到 EXPLORE-* 任务时,调用 Skill(skill="team-ultra-analyze", args="--role=explorer --agent-name=${agentName}") 执行。
当前需求: ${taskDescription}
约束: ${constraints}
## 角色准则(强制)
- 你只能处理 owner 为 "${agentName}" 的 EXPLORE-* 前缀任务
- 所有输出SendMessage、team_msg必须带 [explorer] 标识前缀
- 仅与 coordinator 通信,不得直接联系其他 worker
- 不得使用 TaskCreate 为其他角色创建任务
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 owner === "${agentName}" 的 EXPLORE-* 任务
2. Skill(skill="team-ultra-analyze", args="--role=explorer --agent-name=${agentName}") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [explorer] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
}
} else {
// Single explorer for quick mode
Task({
subagent_type: "general-purpose",
description: `Spawn explorer worker`,
team_name: teamName,
name: "explorer",
prompt: `你是 team "${teamName}" 的 EXPLORER。
当你收到 EXPLORE-* 任务时,调用 Skill(skill="team-ultra-analyze", args="--role=explorer") 执行。
当前需求: ${taskDescription}
约束: ${constraints}
## 角色准则(强制)
- 你只能处理 EXPLORE-* 前缀的任务,不得执行其他角色的工作
- 所有输出SendMessage、team_msg必须带 [explorer] 标识前缀
- 仅与 coordinator 通信,不得直接联系其他 worker
- 不得使用 TaskCreate 为其他角色创建任务
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 EXPLORE-* 任务
2. Skill(skill="team-ultra-analyze", args="--role=explorer") 执行
3. team_msg log + SendMessage 结果给 coordinator带 [explorer] 标识)
4. TaskUpdate completed → 检查下一个任务`
})
}
// ── Analysts ──
// Same pattern: parallel mode spawns N analysts, quick mode spawns 1
if (isParallel) {
for (let i = 0; i < perspectiveCount; i++) {
const agentName = `analyst-${i + 1}`
Task({
subagent_type: "general-purpose",
description: `Spawn ${agentName} worker`,
team_name: teamName,
name: agentName,
prompt: `你是 team "${teamName}" 的 ANALYST (${agentName})。
你的 agent 名称是 "${agentName}",任务发现时用此名称匹配 owner。
当你收到 ANALYZE-* 任务时,调用 Skill(skill="team-ultra-analyze", args="--role=analyst --agent-name=${agentName}") 执行。
当前需求: ${taskDescription}
约束: ${constraints}
## 角色准则(强制)
- 你只能处理 owner 为 "${agentName}" 的 ANALYZE-* 前缀任务
- 所有输出必须带 [analyst] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 owner === "${agentName}" 的 ANALYZE-* 任务
2. Skill(skill="team-ultra-analyze", args="--role=analyst --agent-name=${agentName}") 执行
3. team_msg log + SendMessage 结果给 coordinator
4. TaskUpdate completed → 检查下一个任务`
})
}
} else {
Task({
subagent_type: "general-purpose",
description: `Spawn analyst worker`,
team_name: teamName,
name: "analyst",
prompt: `你是 team "${teamName}" 的 ANALYST。
当你收到 ANALYZE-* 任务时,调用 Skill(skill="team-ultra-analyze", args="--role=analyst") 执行。
当前需求: ${taskDescription}
约束: ${constraints}
## 角色准则(强制)
- 你只能处理 ANALYZE-* 前缀的任务
- 所有输出必须带 [analyst] 标识前缀
- 仅与 coordinator 通信
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 ANALYZE-* 任务
2. Skill(skill="team-ultra-analyze", args="--role=analyst") 执行
3. team_msg log + SendMessage 结果给 coordinator
4. TaskUpdate completed → 检查下一个任务`
})
}
// ── Discussant (always single) ──
Task({
subagent_type: "general-purpose",
description: `Spawn discussant worker`,
team_name: teamName,
name: "discussant",
prompt: `你是 team "${teamName}" 的 DISCUSSANT。
当你收到 DISCUSS-* 任务时,调用 Skill(skill="team-ultra-analyze", args="--role=discussant") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 DISCUSS-* 前缀的任务
- 所有输出必须带 [discussant] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 DISCUSS-* 任务
2. Skill(skill="team-ultra-analyze", args="--role=discussant") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
// ── Synthesizer (always single) ──
Task({
subagent_type: "general-purpose",
description: `Spawn synthesizer worker`,
team_name: teamName,
name: "synthesizer",
prompt: `你是 team "${teamName}" 的 SYNTHESIZER。
当你收到 SYNTH-* 任务时,调用 Skill(skill="team-ultra-analyze", args="--role=synthesizer") 执行。
当前需求: ${taskDescription}
## 角色准则(强制)
- 你只能处理 SYNTH-* 前缀的任务
- 所有输出必须带 [synthesizer] 标识前缀
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
工作流程:
1. TaskList → 找到 SYNTH-* 任务
2. Skill(skill="team-ultra-analyze", args="--role=synthesizer") 执行
3. team_msg log + SendMessage
4. TaskUpdate completed → 检查下一个任务`
})
```
1. Scan `.workflow/.team/UAN-*/` for active/paused sessions
2. Multiple matches -> AskUserQuestion for selection
3. Audit TaskList -> reconcile session state with task status
4. Reset in_progress -> pending (interrupted tasks)
5. Rebuild team and spawn needed workers only
6. Create missing tasks with correct blockedBy
7. Kick first executable task -> Phase 4 coordination loop
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown --role value | Error with available role list |
| Missing --role arg | Error with usage hint |
| Missing --role arg | Orchestration Mode -> coordinator |
| Role file not found | Error with expected path (roles/{name}/role.md) |
| Task prefix conflict | Log warning, proceed |
| Discussion loop stuck >5 rounds | Force synthesis, offer continuation |
| CLI tool unavailable | Fallback chain: gemini codex manual analysis |
| CLI tool unavailable | Fallback chain: gemini -> codex -> manual analysis |
| Explorer agent fails | Continue with available context, note limitation |

View File

@@ -1,40 +1,35 @@
# Role: analyst
# Analyst Role
深度分析师。基于 explorer 的代码库探索结果,通过 CLI 多视角深度分析,生成结构化洞察和讨论要点。
## Role Identity
## Identity
- **Name**: `analyst`
- **Name**: `analyst` | **Tag**: `[analyst]`
- **Task Prefix**: `ANALYZE-*`
- **Responsibility**: Read-only analysis深度分析
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[analyst]`
- **Responsibility**: Read-only analysis (深度分析)
## Role Boundaries
## Boundaries
### MUST
- 仅处理 `ANALYZE-*` 前缀的任务
- 所有输出必须带 `[analyst]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- 基于 explorer 的探索结果进行深度分析
- 将分析结果写入 shared-memory.json 的 `analyses` 字段
- Only process `ANALYZE-*` prefixed tasks
- All output (SendMessage, team_msg, logs) must carry `[analyst]` identifier
- Only communicate with coordinator via SendMessage
- Work strictly within deep analysis responsibility scope
- Base analysis on explorer exploration results
- Write analysis results to shared-memory.json `analyses` field
### MUST NOT
- ❌ 执行代码库探索(属于 explorer
- ❌ 处理用户反馈(属于 discussant
- ❌ 生成最终结论(属于 synthesizer
- ❌ 为其他角色创建任务
- ❌ 直接与其他 worker 通信
- ❌ 修改源代码
- Execute codebase exploration (belongs to explorer)
- Handle user feedback (belongs to discussant)
- Generate final conclusions (belongs to synthesizer)
- Create tasks for other roles (TaskCreate is coordinator-exclusive)
- Communicate directly with other worker roles
- Modify source code
- Omit `[analyst]` identifier in any output
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `analysis_ready` | analyst → coordinator | 分析完成 | 包含洞察、讨论要点、开放问题 |
| `error` | analyst → coordinator | 分析失败 | 阻塞性错误 |
---
## Toolbox
@@ -44,11 +39,16 @@
|---------|------|-------|-------------|
| `analyze` | [commands/analyze.md](commands/analyze.md) | Phase 3 | CLI 多视角深度分析 |
### Subagent Capabilities
### Tool Capabilities
> Analyst 不直接使用 subagent
| Tool | Type | Used By | Purpose |
|------|------|---------|---------|
| `Bash` | CLI | analyze.md | Execute ccw cli for analysis |
| `Read` | File | analyst | Read exploration results and session context |
| `Write` | File | analyst | Write analysis results |
| `Glob` | File | analyst | Find exploration/analysis files |
### CLI Capabilities
### CLI Tools
| CLI Tool | Mode | Used By | Purpose |
|----------|------|---------|---------|
@@ -56,239 +56,196 @@
| `codex` | analysis | analyze.md | 业务视角分析 |
| `claude` | analysis | analyze.md | 架构视角分析 |
---
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `analysis_ready` | analyst → coordinator | 分析完成 | 包含洞察、讨论要点、开放问题 |
| `error` | analyst → coordinator | 分析失败 | 阻塞性错误 |
## Message Bus
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: "ultra-analyze",
from: "analyst",
to: "coordinator",
type: "analysis_ready",
summary: "[analyst] ANALYZE complete: <summary>",
ref: "<output-path>"
})
```
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team ultra-analyze --from analyst --to coordinator --type analysis_ready --summary \"[analyst] ...\" --ref <path> --json")
```
---
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
// Parse agent name from --agent-name arg (for parallel instances) or default to 'analyst'
const agentNameMatch = args.match(/--agent-name[=\s]+([\w-]+)/)
const agentName = agentNameMatch ? agentNameMatch[1] : 'analyst'
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('ANALYZE-') &&
t.owner === agentName &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
Standard task discovery flow: TaskList -> filter by prefix `ANALYZE-*` + 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 `analyst` for single-instance roles.
### Phase 2: Context Loading
```javascript
// 从任务描述中提取上下文
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1]?.trim()
const topic = task.description.match(/topic:\s*(.+)/)?.[1]?.trim()
const perspective = task.description.match(/perspective:\s*(.+)/)?.[1]?.trim() || 'technical'
const dimensions = (task.description.match(/dimensions:\s*(.+)/)?.[1]?.trim() || 'general').split(', ')
const isDirectionFix = task.description.includes('type: direction-fix')
const adjustedFocus = task.description.match(/adjusted_focus:\s*(.+)/)?.[1]?.trim()
**Loading steps**:
// 读取 shared memory
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
1. Extract session path from task description
2. Extract topic, perspective, dimensions from task metadata
3. Check for direction-fix type (补充分析)
4. Read shared-memory.json for existing context
5. Read corresponding exploration results
// 读取对应的探索结果
const analyzeNum = task.subject.match(/ANALYZE-(\w+)/)?.[1] || '001'
let explorationContext = {}
**Context extraction**:
if (isDirectionFix) {
// 方向调整:读取所有已有探索结果
const explorationFiles = Glob({ pattern: `${sessionFolder}/explorations/*.json` })
const allExplorations = explorationFiles.map(f => JSON.parse(Read(f)))
explorationContext = {
relevant_files: allExplorations.flatMap(e => e.relevant_files || []).slice(0, 10),
patterns: allExplorations.flatMap(e => e.patterns || []),
key_findings: allExplorations.flatMap(e => e.key_findings || [])
}
} else {
// 正常分析:读取对应编号的探索结果
try {
explorationContext = JSON.parse(Read(`${sessionFolder}/explorations/exploration-${analyzeNum}.json`))
} catch {
// 尝试读取任意可用的探索结果
const explorationFiles = Glob({ pattern: `${sessionFolder}/explorations/*.json` })
if (explorationFiles.length > 0) {
explorationContext = JSON.parse(Read(explorationFiles[0]))
}
}
}
| Field | Source | Pattern |
|-------|--------|---------|
| sessionFolder | task description | `session:\s*(.+)` |
| topic | task description | `topic:\s*(.+)` |
| perspective | task description | `perspective:\s*(.+)` or default "technical" |
| dimensions | task description | `dimensions:\s*(.+)` or default "general" |
| isDirectionFix | task description | `type:\s*direction-fix` |
| adjustedFocus | task description | `adjusted_focus:\s*(.+)` |
// 确定 CLI 工具
const PERSPECTIVE_TOOLS = {
'technical': 'gemini',
'architectural': 'claude',
'business': 'codex',
'domain_expert': 'gemini'
}
const cliTool = PERSPECTIVE_TOOLS[perspective] || 'gemini'
```
**Exploration context loading**:
| Condition | Source |
|-----------|--------|
| Direction fix | Read ALL exploration files, merge context |
| Normal analysis | Read exploration file matching ANALYZE-N number |
| Fallback | Read first available exploration file |
**CLI tool selection**:
| Perspective | CLI Tool |
|-------------|----------|
| technical | gemini |
| architectural | claude |
| business | codex |
| domain_expert | gemini |
### Phase 3: Deep Analysis via CLI
```javascript
// Read commands/analyze.md for full CLI analysis implementation
Read("commands/analyze.md")
Delegate to `commands/analyze.md` if available, otherwise execute inline.
**Analysis prompt structure** (Direction Fix):
```
**核心策略**: 基于探索结果,通过 CLI 执行深度分析
```javascript
const analysisPrompt = isDirectionFix
? `PURPOSE: 补充分析 - 方向调整至 "${adjustedFocus}"
PURPOSE: 补充分析 - 方向调整至 "<adjusted_focus>"
Success: 针对新方向的深入洞察
PRIOR EXPLORATION CONTEXT:
- Key files: ${(explorationContext.relevant_files || []).slice(0, 5).map(f => f.path || f).join(', ')}
- Patterns: ${(explorationContext.patterns || []).slice(0, 3).join(', ')}
- Previous findings: ${(explorationContext.key_findings || []).slice(0, 3).join(', ')}
- Key files: <top 5 files from exploration>
- Patterns: <top 3 patterns>
- Previous findings: <top 3 findings>
TASK:
Focus analysis on: ${adjustedFocus}
Build on previous exploration findings
Identify new insights from adjusted perspective
Generate discussion points for user
- Focus analysis on: <adjusted_focus>
- Build on previous exploration findings
- Identify new insights from adjusted perspective
- Generate discussion points for user
MODE: analysis
CONTEXT: @**/* | Topic: ${topic}
CONTEXT: @**/* | Topic: <topic>
EXPECTED: Structured analysis with adjusted focus, new insights, updated discussion points
CONSTRAINTS: Focus on ${adjustedFocus}`
: `PURPOSE: Analyze topic '${topic}' from ${perspective} perspective across ${dimensions.join(', ')} dimensions
CONSTRAINTS: Focus on <adjusted_focus>
```
**Analysis prompt structure** (Normal):
```
PURPOSE: Analyze topic '<topic>' from <perspective> perspective across <dimensions> dimensions
Success: Actionable insights with clear reasoning and evidence
PRIOR EXPLORATION CONTEXT:
- Key files: ${(explorationContext.relevant_files || []).slice(0, 5).map(f => f.path || f).join(', ')}
- Patterns found: ${(explorationContext.patterns || []).slice(0, 3).join(', ')}
- Key findings: ${(explorationContext.key_findings || []).slice(0, 3).join(', ')}
- Key files: <top 5 files from exploration>
- Patterns found: <top 3 patterns>
- Key findings: <top 3 findings>
TASK:
Build on exploration findings above
Analyze from ${perspective} perspective: ${dimensions.join(', ')}
Identify patterns, anti-patterns, and opportunities
Generate discussion points for user clarification
Assess confidence level for each insight
- Build on exploration findings above
- Analyze from <perspective> perspective: <dimensions>
- Identify patterns, anti-patterns, and opportunities
- Generate discussion points for user clarification
- Assess confidence level for each insight
MODE: analysis
CONTEXT: @**/* | Topic: ${topic}
CONTEXT: @**/* | Topic: <topic>
EXPECTED: Structured analysis with: key insights (with confidence), discussion points, open questions, recommendations with rationale
CONSTRAINTS: Focus on ${dimensions.join(', ')} | ${perspective} perspective`
CONSTRAINTS: Focus on <dimensions> | <perspective> perspective
```
**CLI execution**:
```
Bash({
command: `ccw cli -p "${analysisPrompt}" --tool ${cliTool} --mode analysis`,
command: "ccw cli -p \"<analysis-prompt>\" --tool <cli-tool> --mode analysis",
run_in_background: true
})
// ⚠️ STOP POINT: Wait for CLI callback
// STOP POINT: Wait for CLI callback
```
### Phase 4: Result Aggregation
```javascript
// CLI 结果返回后,构建分析输出
const outputPath = `${sessionFolder}/analyses/analysis-${analyzeNum}.json`
**Analysis output structure**:
const analysisResult = {
perspective,
dimensions,
is_direction_fix: isDirectionFix,
adjusted_focus: adjustedFocus || null,
key_insights: [], // 从 CLI 结果提取
key_findings: [], // 具体发现
discussion_points: [], // 讨论要点
open_questions: [], // 开放问题
recommendations: [], // 建议
confidence_levels: {}, // 各洞察的置信度
evidence: [], // 证据引用
_metadata: {
cli_tool: cliTool,
perspective,
timestamp: new Date().toISOString()
}
}
| Field | Description |
|-------|-------------|
| perspective | Analysis perspective |
| dimensions | Analysis dimensions |
| is_direction_fix | Boolean for direction fix mode |
| adjusted_focus | Focus area if direction fix |
| key_insights | Main insights with confidence levels |
| key_findings | Specific findings |
| discussion_points | Points for user discussion |
| open_questions | Unresolved questions |
| recommendations | Actionable recommendations |
| evidence | Supporting evidence references |
Write(outputPath, JSON.stringify(analysisResult, null, 2))
```
**Output path**: `<session-folder>/analyses/analysis-<num>.json`
### Phase 5: Report to Coordinator
```javascript
// 更新 shared memory
sharedMemory.analyses = sharedMemory.analyses || []
sharedMemory.analyses.push({
id: `analysis-${analyzeNum}`,
perspective,
is_direction_fix: isDirectionFix,
insight_count: analysisResult.key_insights?.length || 0,
finding_count: analysisResult.key_findings?.length || 0,
timestamp: new Date().toISOString()
})
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
const resultSummary = `${perspective} 视角: ${analysisResult.key_insights?.length || 0} 个洞察, ${analysisResult.discussion_points?.length || 0} 个讨论点`
Standard report flow: team_msg log -> SendMessage with `[analyst]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "analyst",
to: "coordinator",
type: "analysis_ready",
summary: `[analyst] ${resultSummary}`,
ref: outputPath
})
**Shared memory update**:
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [analyst] Analysis Results
**Task**: ${task.subject}
**Perspective**: ${perspective}${isDirectionFix ? ` (Direction Fix: ${adjustedFocus})` : ''}
**CLI Tool**: ${cliTool}
### Summary
${resultSummary}
### Key Insights
${(analysisResult.key_insights || []).slice(0, 5).map(i => `- ${i}`).join('\n')}
### Discussion Points
${(analysisResult.discussion_points || []).slice(0, 3).map(p => `- ${p}`).join('\n')}
### Open Questions
${(analysisResult.open_questions || []).slice(0, 3).map(q => `- ${q}`).join('\n')}
### Output
${outputPath}`,
summary: `[analyst] ANALYZE complete: ${resultSummary}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('ANALYZE-') &&
t.owner === agentName &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (nextTasks.length > 0) {
// Continue with next task → back to Phase 1
}
```
sharedMemory.analyses.push({
id: "analysis-<num>",
perspective: <perspective>,
is_direction_fix: <boolean>,
insight_count: <count>,
finding_count: <count>,
timestamp: <timestamp>
})
```
---
## Error Handling
| Scenario | Resolution |
|----------|------------|
| No ANALYZE-* tasks available | Idle, wait for coordinator assignment |
| CLI tool unavailable | Fallback chain: gemini codex claude |
| CLI tool unavailable | Fallback chain: gemini -> codex -> claude |
| No exploration results found | Analyze with topic keywords only, note limitation |
| CLI timeout | Use partial results, report incomplete |
| Invalid exploration JSON | Skip context, analyze from scratch |
| Command file not found | Fall back to inline execution |

View File

@@ -1,16 +1,13 @@
# Role: coordinator
# Coordinator Role
分析团队协调者。编排 pipeline话题澄清 → 管道选择 → 团队创建 → 任务分发 → 讨论循环 → 结果汇报。
## 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**: Orchestration (Parse requirements -> Create team -> Dispatch tasks -> Monitor progress -> Report results)
## Role Boundaries
## Boundaries
### MUST
@@ -19,17 +16,42 @@
- 通过 TaskCreate 创建任务并分配给 worker 角色
- 通过消息总线监控 worker 进度并路由消息
- 讨论循环中通过 AskUserQuestion 收集用户反馈
- 维护会话状态持久化
### MUST NOT
- **直接执行任何业务任务**代码探索、CLI 分析、综合整合等)
- 直接调用 cli-explore-agent、code-developer 等实现类 subagent
- 直接调用 CLI 分析工具ccw cli
- 绕过 worker 角色自行完成应委派的工作
- 在输出中省略 `[coordinator]` 标识
- 直接执行任何业务任务代码探索、CLI 分析、综合整合等)
- 直接调用 cli-explore-agent、code-developer 等实现类 subagent
- 直接调用 CLI 分析工具ccw cli
- 绕过 worker 角色自行完成应委派的工作
- 在输出中省略 `[coordinator]` 标识
> **核心原则**: coordinator 是指挥者,不是执行者。所有实际工作必须通过 TaskCreate 委派给 worker 角色。
---
## Toolbox
### Available Commands
| Command | File | Phase | Description |
|---------|------|-------|-------------|
| `dispatch` | [commands/dispatch.md](commands/dispatch.md) | Phase 3 | 任务链创建与依赖管理 |
| `monitor` | [commands/monitor.md](commands/monitor.md) | Phase 4 | 讨论循环 + 进度监控 |
### Tool Capabilities
| Tool | Type | Used By | Purpose |
|------|------|---------|---------|
| `TaskCreate` | Task | coordinator | 创建任务并分配给 worker |
| `TaskList` | Task | coordinator | 监控任务状态 |
| `TeamCreate` | Team | coordinator | 创建分析团队 |
| `AskUserQuestion` | Interaction | coordinator | 收集用户反馈 |
| `SendMessage` | Communication | coordinator | 与 worker 通信 |
| `Read/Write` | File | coordinator | 会话状态管理 |
---
## Message Types
| Type | Direction | Trigger | Description |
@@ -41,300 +63,290 @@
| `error` | coordinator → user | 协调错误 | 阻塞性问题 |
| `shutdown` | coordinator → all | 团队关闭 | 清理资源 |
## Toolbox
## Message Bus
### Available Commands
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
| Command | File | Phase | Description |
|---------|------|-------|-------------|
| `dispatch` | [commands/dispatch.md](commands/dispatch.md) | Phase 3 | 任务链创建与依赖管理 |
| `monitor` | [commands/monitor.md](commands/monitor.md) | Phase 4 | 讨论循环 + 进度监控 |
```
mcp__ccw-tools__team_msg({
operation: "log",
team: "ultra-analyze",
from: "coordinator",
to: "<recipient>",
type: "<message-type>",
summary: "[coordinator] <summary>",
ref: "<artifact-path>"
})
```
### Subagent Capabilities
**CLI fallback** (when MCP unavailable):
> Coordinator 不直接使用 subagent通过 worker 角色间接使用)
```
Bash("ccw team log --team ultra-analyze --from coordinator --to <recipient> --type <type> --summary \"[coordinator] ...\" --ref <path> --json")
```
### CLI Capabilities
---
> Coordinator 不直接使用 CLI 分析工具
## Entry Router
## Execution
When coordinator is invoked, first detect the invocation type:
### Phase 1: Topic Understanding & Requirement Clarification
| 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
const args = "$ARGUMENTS"
For callback/check/resume: load `commands/monitor.md` and execute the appropriate handler, then STOP.
// 提取话题描述
const taskDescription = args.replace(/--role[=\s]+\w+/, '').replace(/--team[=\s]+[\w-]+/, '').replace(/--mode[=\s]+\w+/, '').trim()
---
// ★ 统一 auto mode 检测
const autoYes = /\b(-y|--yes)\b/.test(args)
## Phase 0: Session Resume Check
// 管道模式选择
function detectPipelineMode(args, desc) {
const modeMatch = args.match(/--mode[=\s]+(quick|standard|deep)/)
if (modeMatch) return modeMatch[1]
if (/快速|quick|overview|概览/.test(desc)) return 'quick'
if (/深入|deep|thorough|详细|全面/.test(desc)) return 'deep'
return 'standard'
}
**Objective**: Detect and resume interrupted sessions before creating new ones.
let pipelineMode = detectPipelineMode(args, taskDescription)
**Workflow**:
// 维度检测
const DIMENSION_KEYWORDS = {
architecture: /架构|architecture|design|structure|设计/,
implementation: /实现|implement|code|coding|代码/,
performance: /性能|performance|optimize|bottleneck|优化/,
security: /安全|security|auth|permission|权限/,
concept: /概念|concept|theory|principle|原理/,
comparison: /比较|compare|vs|difference|区别/,
decision: /决策|decision|choice|tradeoff|选择/
}
1. Scan `.workflow/.team/UAN-*/` 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
const detectedDimensions = Object.entries(DIMENSION_KEYWORDS)
.filter(([_, regex]) => regex.test(taskDescription))
.map(([dim]) => dim)
**Session Reconciliation**:
const dimensions = detectedDimensions.length > 0 ? detectedDimensions : ['general']
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
// 交互式澄清(非 auto 模式)
if (!autoYes) {
// 1. Focus 方向选择
const DIMENSION_DIRECTIONS = {
architecture: ['System Design', 'Component Interactions', 'Technology Choices', 'Design Patterns', 'Scalability Strategy'],
implementation: ['Code Structure', 'Implementation Details', 'Code Patterns', 'Error Handling', 'Algorithm Analysis'],
performance: ['Performance Bottlenecks', 'Optimization Opportunities', 'Resource Utilization', 'Caching Strategy'],
security: ['Security Vulnerabilities', 'Authentication/Authorization', 'Access Control', 'Data Protection'],
concept: ['Conceptual Foundation', 'Core Mechanisms', 'Fundamental Patterns', 'Trade-offs & Reasoning'],
comparison: ['Solution Comparison', 'Pros & Cons Analysis', 'Technology Evaluation'],
decision: ['Decision Criteria', 'Trade-off Analysis', 'Risk Assessment', 'Impact Analysis'],
general: ['Overview', 'Key Patterns', 'Potential Issues', 'Improvement Opportunities']
---
## Phase 1: Topic Understanding & Requirement Clarification
**Objective**: Parse user input and gather execution parameters.
**Workflow**:
1. **Parse arguments** for explicit settings: mode, scope, focus areas
2. **Extract topic description**: Remove `--role`, `--team`, `--mode` flags from arguments
3. **Pipeline mode selection**:
| Condition | Mode |
|-----------|------|
| `--mode=quick` explicit or topic contains "quick/overview/fast" | Quick |
| `--mode=deep` explicit or topic contains "deep/thorough/detailed/comprehensive" | Deep |
| Default (no match) | Standard |
4. **Dimension detection** (from topic keywords):
| Dimension | Keywords |
|-----------|----------|
| architecture | 架构, architecture, design, structure, 设计 |
| implementation | 实现, implement, code, 代码 |
| performance | 性能, performance, optimize, 优化 |
| security | 安全, security, auth, 权限 |
| concept | 概念, concept, theory, 原理 |
| comparison | 比较, compare, vs, 区别 |
| decision | 决策, decision, choice, 选择 |
5. **Interactive clarification** (non-auto mode only):
| Question | Purpose |
|----------|---------|
| Analysis Focus | Multi-select focus directions |
| Analysis Perspectives | Select technical/architectural/business/domain views |
| Analysis Depth | Confirm Quick/Standard/Deep |
**Success**: All parameters captured, mode finalized.
---
## Phase 2: Create Team + Initialize Session
**Objective**: Initialize team, session file, and wisdom directory.
**Workflow**:
1. **Generate session ID**: `UAN-{slug}-{YYYY-MM-DD}`
2. **Create session folder structure**:
```
.workflow/.team/UAN-{slug}-{date}/
+-- shared-memory.json
+-- discussion.md
+-- explorations/
+-- analyses/
+-- discussions/
+-- wisdom/
+-- learnings.md
+-- decisions.md
+-- conventions.md
+-- issues.md
```
3. **Initialize shared-memory.json**:
```json
{
"explorations": [],
"analyses": [],
"discussions": [],
"synthesis": null,
"decision_trail": [],
"current_understanding": {
"established": [],
"clarified": [],
"key_insights": []
}
const directionOptions = dimensions.flatMap(d => (DIMENSION_DIRECTIONS[d] || []).slice(0, 3))
.map(d => ({ label: d, description: `Focus on ${d}` }))
const focusResult = AskUserQuestion({
questions: [{
question: "选择分析方向(可多选)",
header: "Analysis Focus",
multiSelect: true,
options: directionOptions
}]
})
// 2. 视角选择Standard/Deep 模式)
let selectedPerspectives = ['technical']
if (pipelineMode !== 'quick') {
const perspectiveResult = AskUserQuestion({
questions: [{
question: "选择分析视角可多选最多4个",
header: "Analysis Perspectives",
multiSelect: true,
options: [
{ label: "Technical", description: "实现、代码模式、技术可行性" },
{ label: "Architectural", description: "系统设计、可扩展性、组件交互" },
{ label: "Business", description: "价值、ROI、利益相关者影响" },
{ label: "Domain Expert", description: "领域特定模式、最佳实践、标准" }
]
}]
})
// Parse selected perspectives
}
// 3. 深度选择
const depthResult = AskUserQuestion({
questions: [{
question: "选择分析深度",
header: "Analysis Depth",
multiSelect: false,
options: [
{ label: "Quick Overview", description: "快速概览 (10-15min)" },
{ label: "Standard Analysis", description: "标准分析 (30-60min)" },
{ label: "Deep Dive", description: "深度分析 (1-2hr)" }
]
}]
})
const depthMap = { 'Quick Overview': 'quick', 'Standard Analysis': 'standard', 'Deep Dive': 'deep' }
pipelineMode = depthMap[depthResult["Analysis Depth"]] || pipelineMode
}
```
### Phase 2: Create Team + Initialize Session
4. **Initialize discussion.md** with session metadata
5. **Call TeamCreate** with team name "ultra-analyze"
6. **Spawn worker roles** (see SKILL.md Coordinator Spawn Template)
```javascript
const teamName = "ultra-analyze"
const sessionSlug = taskDescription.slice(0, 30).replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '-')
const sessionDate = new Date().toISOString().slice(0, 10)
const sessionFolder = `.workflow/.team/UAN-${sessionSlug}-${sessionDate}`
Bash(`mkdir -p "${sessionFolder}/explorations" "${sessionFolder}/analyses" "${sessionFolder}/discussions"`)
**Success**: Team created, session file written, wisdom initialized, workers ready.
// 初始化 shared memory
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify({
explorations: [],
analyses: [],
discussions: [],
synthesis: null,
decision_trail: [],
current_understanding: {
established: [],
clarified: [],
key_insights: []
}
}, null, 2))
---
// 初始化 discussion.md
Write(`${sessionFolder}/discussion.md`, `# Analysis Discussion
## Phase 3: Create Task Chain
## Session Metadata
- **ID**: UAN-${sessionSlug}-${sessionDate}
- **Topic**: ${taskDescription}
- **Started**: ${new Date().toISOString()}
- **Dimensions**: ${dimensions.join(', ')}
- **Pipeline**: ${pipelineMode}
**Objective**: Dispatch tasks based on mode with proper dependencies.
## User Context
- **Focus Areas**: ${dimensions.join(', ')}
- **Analysis Depth**: ${pipelineMode}
Delegate to `commands/dispatch.md` which creates the full task chain:
## Initial Understanding
- **Dimensions**: ${dimensions.join(', ')}
- **Scope**: ${taskDescription}
**Quick Mode** (3 beats, serial):
## Discussion Timeline
`)
TeamCreate({ team_name: teamName })
// ⚠️ 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.
// Quick mode: 1 explorer + 1 analyst (single agents)
// Standard/Deep mode: N explorers + N analysts (parallel agents with distinct names)
// explorer-1, explorer-2... / analyst-1, analyst-2... for true parallel execution
// Discussant and Synthesizer are always single instances
```
### Phase 3: Create Task Chain
根据 pipelineMode 创建不同的任务链:
```javascript
// Read commands/dispatch.md for full implementation
Read("commands/dispatch.md")
```
**Quick Mode**:
```
EXPLORE-001 → ANALYZE-001 → SYNTH-001
```
**Standard Mode**:
**Standard Mode** (4 beats, parallel windows):
```
[EXPLORE-001..N](parallel) → [ANALYZE-001..N](parallel) → DISCUSS-001 → SYNTH-001
```
**Deep Mode**:
**Deep Mode** (4+ beats, with discussion loop):
```
[EXPLORE-001..N](parallel) → [ANALYZE-001..N](parallel) → DISCUSS-001 → [ANALYZE-fix] → DISCUSS-002 → ... → SYNTH-001
[EXPLORE-001..N] → [ANALYZE-001..N] → DISCUSS-001 → [ANALYZE-fix] → DISCUSS-002 → ... → SYNTH-001
```
### Phase 4: Discussion Loop + Coordination
**Task chain rules**:
> **设计原则Stop-Wait**: 模型执行没有时间概念,禁止任何形式的轮询等待。
> - ❌ 禁止: `while` 循环 + `sleep` + 检查状态
> - ✅ 采用: 同步 `Task(run_in_background: false)` 调用Worker 返回 = 阶段完成信号
>
> 按 Phase 3 创建的任务链顺序,逐阶段 spawn worker 同步执行。
> Worker prompt 使用 SKILL.md Coordinator Spawn Template。
1. Reads SKILL.md Task Metadata Registry for task definitions
2. Creates tasks via TaskCreate with correct blockedBy
3. Assigns owner based on role mapping
4. Includes `Session: <session-folder>` in every task description
```javascript
// Read commands/monitor.md for full implementation
Read("commands/monitor.md")
```
---
## Phase 4: Discussion Loop + Coordination
**Objective**: Spawn workers in background, monitor callbacks, drive discussion loop.
**Design**: Spawn-and-Stop + Callback pattern.
- Spawn workers with `Task(run_in_background: true)` -> immediately return
- Worker completes -> SendMessage callback -> auto-advance
- User can use "check" / "resume" to manually advance
- Coordinator does one operation per invocation, then STOPS
**Workflow** (see `commands/monitor.md` for details):
1. Load `commands/monitor.md`
2. Find tasks with: status=pending, blockedBy all resolved, owner assigned
3. For each ready task -> spawn worker (see SKILL.md Spawn Template)
4. Output status summary
5. STOP
**Callback handlers**:
| Received Message | Action |
|-----------------|--------|
| `exploration_ready` | 标记 EXPLORE complete → 解锁 ANALYZE |
| `analysis_ready` | 标记 ANALYZE complete → 解锁 DISCUSS SYNTH |
| `discussion_processed` | 标记 DISCUSS complete AskUser → 决定下一步 |
| `synthesis_ready` | 标记 SYNTH complete → 进入 Phase 5 |
| Worker: `error` | 评估严重性 → 重试或上报用户 |
| `exploration_ready` | Mark EXPLORE complete -> unblock ANALYZE |
| `analysis_ready` | Mark ANALYZE complete -> unblock DISCUSS or SYNTH |
| `discussion_processed` | Mark DISCUSS complete -> AskUser -> decide next |
| `synthesis_ready` | Mark SYNTH complete -> Phase 5 |
| Worker: `error` | Assess severity -> retry or report to user |
**讨论循环逻辑** (Standard/Deep mode):
```javascript
let discussionRound = 0
const MAX_ROUNDS = pipelineMode === 'deep' ? 5 : 1
**Discussion loop logic** (Standard/Deep mode):
while (discussionRound < MAX_ROUNDS) {
// 等待 DISCUSS-N 完成
// AskUserQuestion: 同意继续 / 调整方向 / 分析完成 / 有具体问题
// 根据用户选择:
// 同意继续 → 创建 DISCUSS-(N+1)
// 调整方向 → 创建 ANALYZE-fix + DISCUSS-(N+1)
// 分析完成 → 退出循环,创建 SYNTH-001
// 有具体问题 → 创建 DISCUSS-(N+1) with questions
discussionRound++
}
| Round | Action |
|-------|--------|
| After DISCUSS-N completes | AskUserQuestion: continue / adjust direction / complete / specific questions |
| User: "继续深入" | Create DISCUSS-(N+1) |
| User: "调整方向" | Create ANALYZE-fix + DISCUSS-(N+1) |
| User: "分析完成" | Exit loop, create SYNTH-001 |
| Round > MAX_ROUNDS (5) | Force synthesis, offer continuation |
**Pipeline advancement** driven by three wake sources:
- Worker callback (automatic) -> Entry Router -> handleCallback
- User "check" -> handleCheck (status only)
- User "resume" -> handleResume (advance)
---
## Phase 5: Report + Persist
**Objective**: Completion report and follow-up options.
**Workflow**:
1. Load session state -> count completed tasks, duration
2. List deliverables with output paths
3. Update session status -> "completed"
4. Output final report
5. Offer next steps to user
**Report structure**:
```
## [coordinator] Analysis Complete
**Mode**: <mode>
**Topic**: <topic>
**Explorations**: <count>
**Analyses**: <count>
**Discussion Rounds**: <count>
**Decisions Made**: <count>
📄 Discussion: <session-folder>/discussion.md
📊 Conclusions: <session-folder>/conclusions.json
```
### Phase 5: Report + Persist
**Next step options**:
```javascript
// 读取 shared memory 汇总结果
const memory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
| Option | Description |
|--------|-------------|
| 创建Issue | 基于结论创建 Issue |
| 生成任务 | 启动 workflow-lite-plan 规划实施 |
| 导出报告 | 生成独立分析报告 |
| 关闭团队 | 关闭所有 teammate 并清理 |
const report = {
mode: pipelineMode,
topic: taskDescription,
explorations_count: memory.explorations?.length || 0,
analyses_count: memory.analyses?.length || 0,
discussion_rounds: memory.discussions?.length || 0,
decisions_made: memory.decision_trail?.length || 0,
has_synthesis: !!memory.synthesis
}
mcp__ccw-tools__team_msg({
operation: "log", team: teamName, from: "coordinator",
to: "user", type: "pipeline_selected",
summary: `[coordinator] 分析完成: ${report.explorations_count}次探索, ${report.analyses_count}次分析, ${report.discussion_rounds}轮讨论`
})
SendMessage({
content: `## [coordinator] Analysis Complete\n\n${JSON.stringify(report, null, 2)}\n\n📄 Discussion: ${sessionFolder}/discussion.md\n📊 Conclusions: ${sessionFolder}/conclusions.json`,
summary: `[coordinator] Analysis complete: ${pipelineMode} mode`
})
// 询问下一步auto 模式跳过,默认关闭团队)
if (!autoYes) {
AskUserQuestion({
questions: [{
question: "分析流程已完成。下一步:",
header: "Next",
multiSelect: false,
options: [
{ label: "创建Issue", description: "基于结论创建 Issue" },
{ label: "生成任务", description: "启动 workflow-lite-plan 规划实施" },
{ label: "导出报告", description: "生成独立分析报告" },
{ label: "关闭团队", description: "关闭所有 teammate 并清理" }
]
}]
})
}
```
---
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Teammate unresponsive | Send follow-up, 2x respawn |
| Teammate unresponsive | Send follow-up, 2x -> respawn |
| Explorer finds nothing | Continue with limited context, note limitation |
| Discussion loop stuck >5 rounds | Force synthesis, offer continuation |
| CLI unavailable | Fallback chain: gemini codex manual |
| CLI unavailable | Fallback chain: gemini -> codex -> manual |
| User timeout in discussion | Save state, show resume command |
| Max rounds reached | Force synthesis, offer continuation option |
| Session folder conflict | Append timestamp suffix |
| Task timeout | Log, mark failed, ask user to retry or skip |
| Worker crash | Respawn worker, reassign task |
| Dependency cycle | Detect, report to user, halt |

View File

@@ -1,40 +1,35 @@
# Role: discussant
# Discussant Role
讨论处理者。根据 coordinator 传递的用户反馈,执行方向调整、深入探索或补充分析,更新讨论时间线。
## Role Identity
## Identity
- **Name**: `discussant`
- **Name**: `discussant` | **Tag**: `[discussant]`
- **Task Prefix**: `DISCUSS-*`
- **Responsibility**: Analysis + Exploration讨论处理
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[discussant]`
- **Responsibility**: Analysis + Exploration (讨论处理)
## Role Boundaries
## Boundaries
### MUST
- 仅处理 `DISCUSS-*` 前缀的任务
- 所有输出必须带 `[discussant]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- 基于用户反馈和已有分析结果执行深入探索
- 将讨论结果写入 shared-memory.json 的 `discussions` 字段
- 更新 discussion.md 的讨论时间线
- Only process `DISCUSS-*` prefixed tasks
- All output (SendMessage, team_msg, logs) must carry `[discussant]` identifier
- Only communicate with coordinator via SendMessage
- Work strictly within discussion processing responsibility scope
- Execute deep exploration based on user feedback and existing analysis
- Write discussion results to shared-memory.json `discussions` field
- Update discussion.md discussion timeline
### MUST NOT
- ❌ 直接与用户交互(AskUserQuestion coordinator 驱动)
- ❌ 生成最终结论(属于 synthesizer
- ❌ 为其他角色创建任务
- ❌ 直接与其他 worker 通信
- ❌ 修改源代码
- Interact directly with user (AskUserQuestion is coordinator-driven)
- Generate final conclusions (belongs to synthesizer)
- Create tasks for other roles (TaskCreate is coordinator-exclusive)
- Communicate directly with other worker roles
- Modify source code
- Omit `[discussant]` identifier in any output
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `discussion_processed` | discussant → coordinator | 讨论处理完成 | 包含更新的理解和新发现 |
| `error` | discussant → coordinator | 处理失败 | 阻塞性错误 |
---
## Toolbox
@@ -44,223 +39,179 @@
|---------|------|-------|-------------|
| `deepen` | [commands/deepen.md](commands/deepen.md) | Phase 3 | 深入探索与补充分析 |
### Subagent Capabilities
### Tool Capabilities
| Agent Type | Used By | Purpose |
|------------|---------|---------|
| `cli-explore-agent` | deepen.md | 针对性代码库探索 |
| Tool | Type | Used By | Purpose |
|------|------|---------|---------|
| `Task` | Subagent | deepen.md | Spawn cli-explore-agent for targeted exploration |
| `Bash` | CLI | deepen.md | Execute ccw cli for deep analysis |
| `Read` | File | discussant | Read analysis results and session context |
| `Write` | File | discussant | Write discussion results |
| `Glob` | File | discussant | Find analysis/exploration files |
### CLI Capabilities
### CLI Tools
| CLI Tool | Mode | Used By | Purpose |
|----------|------|---------|---------|
| `gemini` | analysis | deepen.md | 深入分析 |
---
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `discussion_processed` | discussant → coordinator | 讨论处理完成 | 包含更新的理解和新发现 |
| `error` | discussant → coordinator | 处理失败 | 阻塞性错误 |
## Message Bus
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: "ultra-analyze",
from: "discussant",
to: "coordinator",
type: "discussion_processed",
summary: "[discussant] DISCUSS complete: <summary>",
ref: "<output-path>"
})
```
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team ultra-analyze --from discussant --to coordinator --type discussion_processed --summary \"[discussant] ...\" --ref <path> --json")
```
---
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('DISCUSS-') &&
t.owner === 'discussant' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
if (myTasks.length === 0) return // idle
Standard task discovery flow: TaskList -> filter by prefix `DISCUSS-*` + owner match + pending + unblocked -> TaskGet -> TaskUpdate in_progress.
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })
```
Falls back to `discussant` for single-instance role.
### Phase 2: Context Loading
```javascript
// 从任务描述中提取上下文
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1]?.trim()
const topic = task.description.match(/topic:\s*(.+)/)?.[1]?.trim()
const round = parseInt(task.description.match(/round:\s*(\d+)/)?.[1] || '1')
const discussType = task.description.match(/type:\s*(.+)/)?.[1]?.trim() || 'initial'
const userFeedback = task.description.match(/user_feedback:\s*(.+)/)?.[1]?.trim() || ''
**Loading steps**:
// 读取 shared memory
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
1. Extract session path from task description
2. Extract topic, round number, discussion type, user feedback
3. Read shared-memory.json for existing context
4. Read all analysis results
5. Read all exploration results
6. Aggregate current findings, insights, questions
// 读取已有分析结果
const analysisFiles = Glob({ pattern: `${sessionFolder}/analyses/*.json` })
const allAnalyses = analysisFiles.map(f => {
try { return JSON.parse(Read(f)) } catch { return null }
}).filter(Boolean)
**Context extraction**:
// 读取已有探索结果
const explorationFiles = Glob({ pattern: `${sessionFolder}/explorations/*.json` })
const allExplorations = explorationFiles.map(f => {
try { return JSON.parse(Read(f)) } catch { return null }
}).filter(Boolean)
| Field | Source | Pattern |
|-------|--------|---------|
| sessionFolder | task description | `session:\s*(.+)` |
| topic | task description | `topic:\s*(.+)` |
| round | task description | `round:\s*(\d+)` or default 1 |
| discussType | task description | `type:\s*(.+)` or default "initial" |
| userFeedback | task description | `user_feedback:\s*(.+)` or empty |
// 聚合当前理解
const currentFindings = allAnalyses.flatMap(a => a.key_findings || [])
const currentInsights = allAnalyses.flatMap(a => a.key_insights || [])
const openQuestions = allAnalyses.flatMap(a => a.open_questions || [])
const discussionPoints = allAnalyses.flatMap(a => a.discussion_points || [])
```
**Discussion types**:
| Type | Description |
|------|-------------|
| initial | 首轮讨论:汇总所有分析结果,生成讨论摘要 |
| deepen | 继续深入:在当前方向上进一步探索 |
| direction-adjusted | 方向调整:基于新方向重新组织发现 |
| specific-questions | 具体问题:针对用户问题进行分析 |
### Phase 3: Discussion Processing
```javascript
// Read commands/deepen.md for full implementation
Read("commands/deepen.md")
```
Delegate to `commands/deepen.md` if available, otherwise execute inline.
**根据 discussType 选择处理策略**:
**Processing by discussion type**:
```javascript
const discussNum = task.subject.match(/DISCUSS-(\d+)/)?.[1] || '001'
const outputPath = `${sessionFolder}/discussions/discussion-round-${discussNum}.json`
| Type | Strategy |
|------|----------|
| initial | Aggregate all analysis results, generate discussion summary with confirmed/corrected/new insights |
| deepen | Focus on current direction, explore deeper with cli-explore-agent |
| direction-adjusted | Re-organize findings around new focus, identify new patterns |
| specific-questions | Targeted analysis addressing user's specific questions |
switch (discussType) {
case 'initial':
// 首轮讨论:汇总所有分析结果,生成讨论摘要
processInitialDiscussion()
break
**Round content structure**:
case 'deepen':
// 继续深入:在当前方向上进一步探索
processDeepenDiscussion()
break
case 'direction-adjusted':
// 方向调整:基于新方向重新组织发现
processDirectionAdjusted()
break
case 'specific-questions':
// 具体问题:针对用户问题进行分析
processSpecificQuestions()
break
}
```
| Field | Description |
|-------|-------------|
| round | Discussion round number |
| type | Discussion type |
| user_feedback | User input (if any) |
| updated_understanding | confirmed, corrected, new_insights arrays |
| new_findings | New discoveries |
| new_questions | Open questions |
| timestamp | ISO timestamp |
### Phase 4: Update Discussion Timeline
```javascript
// 构建讨论轮次内容
const roundContent = {
round,
type: discussType,
user_feedback: userFeedback,
updated_understanding: {
confirmed: [], // 确认的假设
corrected: [], // 纠正的假设
new_insights: [] // 新发现
},
new_findings: [],
new_questions: [],
timestamp: new Date().toISOString()
}
**Output path**: `<session-folder>/discussions/discussion-round-<num>.json`
Write(outputPath, JSON.stringify(roundContent, null, 2))
**discussion.md update template**:
// 更新 discussion.md
const discussionMdContent = `
### Round ${round + 1} - Discussion (${new Date().toISOString()})
```markdown
### Round <N> - Discussion (<timestamp>)
#### Type
${discussType}
<discussType>
#### User Input
${userFeedback || '(Initial discussion round)'}
<userFeedback or "(Initial discussion round)">
#### Updated Understanding
${roundContent.updated_understanding.confirmed.length > 0
? `**Confirmed**: ${roundContent.updated_understanding.confirmed.map(c => `\n- ✅ ${c}`).join('')}` : ''}
${roundContent.updated_understanding.corrected.length > 0
? `**Corrected**: ${roundContent.updated_understanding.corrected.map(c => `\n- 🔄 ${c}`).join('')}` : ''}
${roundContent.updated_understanding.new_insights.length > 0
? `**New Insights**: ${roundContent.updated_understanding.new_insights.map(i => `\n- 💡 ${i}`).join('')}` : ''}
**Confirmed**: <list of confirmed assumptions>
**Corrected**: <list of corrected assumptions>
**New Insights**: <list of new insights>
#### New Findings
${(roundContent.new_findings || []).map(f => `- ${f}`).join('\n') || '(None)'}
<list of new findings or "(None)">
#### Open Questions
${(roundContent.new_questions || []).map(q => `- ${q}`).join('\n') || '(None)'}
`
const currentDiscussion = Read(`${sessionFolder}/discussion.md`)
Write(`${sessionFolder}/discussion.md`, currentDiscussion + discussionMdContent)
<list of open questions or "(None)">
```
**Update steps**:
1. Write round content JSON to discussions folder
2. Read current discussion.md
3. Append new round section
4. Write updated discussion.md
### Phase 5: Report to Coordinator
```javascript
// 更新 shared memory
sharedMemory.discussions = sharedMemory.discussions || []
sharedMemory.discussions.push({
id: `discussion-round-${discussNum}`,
round,
type: discussType,
new_insight_count: roundContent.updated_understanding.new_insights?.length || 0,
corrected_count: roundContent.updated_understanding.corrected?.length || 0,
timestamp: new Date().toISOString()
})
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
// 更新 current_understanding
sharedMemory.current_understanding = sharedMemory.current_understanding || { established: [], clarified: [], key_insights: [] }
sharedMemory.current_understanding.established.push(...(roundContent.updated_understanding.confirmed || []))
sharedMemory.current_understanding.clarified.push(...(roundContent.updated_understanding.corrected || []))
sharedMemory.current_understanding.key_insights.push(...(roundContent.updated_understanding.new_insights || []))
Standard report flow: team_msg log -> SendMessage with `[discussant]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
**Shared memory update**:
const resultSummary = `Round ${round}: ${roundContent.updated_understanding.new_insights?.length || 0} 新洞察, ${roundContent.updated_understanding.corrected?.length || 0} 纠正`
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "discussant",
to: "coordinator",
type: "discussion_processed",
summary: `[discussant] ${resultSummary}`,
ref: outputPath
})
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [discussant] Discussion Round ${round} Results
**Task**: ${task.subject}
**Type**: ${discussType}
### Summary
${resultSummary}
### Key Updates
${roundContent.updated_understanding.new_insights?.slice(0, 3).map(i => `- 💡 ${i}`).join('\n') || '(No new insights)'}
${roundContent.updated_understanding.corrected?.slice(0, 3).map(c => `- 🔄 ${c}`).join('\n') || ''}
### Output
${outputPath}`,
summary: `[discussant] DISCUSS complete: ${resultSummary}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('DISCUSS-') &&
t.owner === 'discussant' &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (nextTasks.length > 0) {
// Continue with next task → back to Phase 1
}
```
sharedMemory.discussions.push({
id: "discussion-round-<num>",
round: <round>,
type: <discussType>,
new_insight_count: <count>,
corrected_count: <count>,
timestamp: <timestamp>
})
// Update current_understanding
sharedMemory.current_understanding.established += confirmed
sharedMemory.current_understanding.clarified += corrected
sharedMemory.current_understanding.key_insights += new_insights
```
---
## Error Handling
@@ -271,3 +222,4 @@ if (nextTasks.length > 0) {
| CLI tool unavailable | Use existing analysis results for discussion |
| User feedback unclear | Process as 'deepen' type, note ambiguity |
| Session folder missing | Error to coordinator |
| Command file not found | Fall back to inline execution |

View File

@@ -1,39 +1,33 @@
# Role: explorer
# Explorer Role
代码库探索者。通过 cli-explore-agent 多角度并行探索代码库,收集结构化上下文供后续分析使用。
## Role Identity
## Identity
- **Name**: `explorer`
- **Name**: `explorer` | **Tag**: `[explorer]`
- **Task Prefix**: `EXPLORE-*`
- **Responsibility**: Orchestration代码库探索编排
- **Communication**: SendMessage to coordinator only
- **Output Tag**: `[explorer]`
- **Responsibility**: Orchestration (代码库探索编排)
## Role Boundaries
## Boundaries
### MUST
- 仅处理 `EXPLORE-*` 前缀的任务
- 所有输出必须带 `[explorer]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- 严格在代码库探索职责范围内工作
- 将探索结果写入 shared-memory.json `explorations` 字段
- Only process `EXPLORE-*` prefixed tasks
- All output (SendMessage, team_msg, logs) must carry `[explorer]` identifier
- Only communicate with coordinator via SendMessage
- Work strictly within codebase exploration responsibility scope
- Write exploration results to shared-memory.json `explorations` field
### MUST NOT
- ❌ 执行深度分析(属于 analyst
- ❌ 处理用户反馈(属于 discussant
- ❌ 生成结论或建议(属于 synthesizer
- ❌ 为其他角色创建任务
- ❌ 直接与其他 worker 通信
- Execute deep analysis (belongs to analyst)
- Handle user feedback (belongs to discussant)
- Generate conclusions or recommendations (belongs to synthesizer)
- Create tasks for other roles (TaskCreate is coordinator-exclusive)
- Communicate directly with other worker roles
- Omit `[explorer]` identifier in any output
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `exploration_ready` | explorer → coordinator | 探索完成 | 包含发现的文件、模式、关键发现 |
| `error` | explorer → coordinator | 探索失败 | 阻塞性错误 |
---
## Toolbox
@@ -43,90 +37,117 @@
|---------|------|-------|-------------|
| `explore` | [commands/explore.md](commands/explore.md) | Phase 3 | cli-explore-agent 并行探索 |
### Subagent Capabilities
### Tool Capabilities
| Agent Type | Used By | Purpose |
|------------|---------|---------|
| `cli-explore-agent` | explore.md | 多角度代码库探索 |
| Tool | Type | Used By | Purpose |
|------|------|---------|---------|
| `Task` | Subagent | explore.md | Spawn cli-explore-agent for codebase exploration |
| `Read` | File | explorer | Read session files and exploration context |
| `Write` | File | explorer | Write exploration results |
| `Glob` | File | explorer | Find relevant files |
| `mcp__ace-tool__search_context` | MCP | explorer | ACE semantic search fallback |
| `Grep` | Search | explorer | Pattern search fallback |
### CLI Capabilities
---
> Explorer 不直接使用 CLI 分析工具(通过 cli-explore-agent 间接使用)
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `exploration_ready` | explorer → coordinator | 探索完成 | 包含发现的文件、模式、关键发现 |
| `error` | explorer → coordinator | 探索失败 | 阻塞性错误 |
## Message Bus
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: "ultra-analyze",
from: "explorer",
to: "coordinator",
type: "exploration_ready",
summary: "[explorer] EXPLORE complete: <summary>",
ref: "<output-path>"
})
```
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team ultra-analyze --from explorer --to coordinator --type exploration_ready --summary \"[explorer] ...\" --ref <path> --json")
```
---
## Execution (5-Phase)
### Phase 1: Task Discovery
```javascript
// Parse agent name from --agent-name arg (for parallel instances) or default to 'explorer'
const agentNameMatch = args.match(/--agent-name[=\s]+([\w-]+)/)
const agentName = agentNameMatch ? agentNameMatch[1] : 'explorer'
> See SKILL.md Shared Infrastructure -> Worker Phase 1: Task Discovery
const tasks = TaskList()
const myTasks = tasks.filter(t =>
t.subject.startsWith('EXPLORE-') &&
t.owner === agentName &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
Standard task discovery flow: TaskList -> filter by prefix `EXPLORE-*` + 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 `explorer` for single-instance roles.
### Phase 2: Context & Scope Assessment
```javascript
// 从任务描述中提取上下文
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1]?.trim()
const topic = task.description.match(/topic:\s*(.+)/)?.[1]?.trim()
const perspective = task.description.match(/perspective:\s*(.+)/)?.[1]?.trim() || 'general'
const dimensions = (task.description.match(/dimensions:\s*(.+)/)?.[1]?.trim() || 'general').split(', ')
**Loading steps**:
// 读取 shared memory
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`)) } catch {}
1. Extract session path from task description
2. Extract topic, perspective, dimensions from task metadata
3. Read shared-memory.json for existing context
4. Determine exploration number from task subject (EXPLORE-N)
// 评估探索范围
const exploreNum = task.subject.match(/EXPLORE-(\d+)/)?.[1] || '001'
```
**Context extraction**:
| Field | Source | Pattern |
|-------|--------|---------|
| sessionFolder | task description | `session:\s*(.+)` |
| topic | task description | `topic:\s*(.+)` |
| perspective | task description | `perspective:\s*(.+)` or default "general" |
| dimensions | task description | `dimensions:\s*(.+)` or default "general" |
### Phase 3: Codebase Exploration
```javascript
// Read commands/explore.md for full cli-explore-agent implementation
Read("commands/explore.md")
Delegate to `commands/explore.md` if available, otherwise execute inline.
**Exploration strategy**:
| Condition | Strategy |
|-----------|----------|
| Single perspective | Direct cli-explore-agent spawn |
| Multi-perspective | Per-perspective exploration with focused prompts |
| Limited context | ACE search + Grep fallback |
**cli-explore-agent spawn**:
```
**核心策略**: 通过 cli-explore-agent 执行代码库探索
```javascript
Task({
subagent_type: "cli-explore-agent",
run_in_background: false,
description: `Explore codebase: ${topic} (${perspective})`,
description: "Explore codebase: <topic> (<perspective>)",
prompt: `
## Analysis Context
Topic: ${topic}
Perspective: ${perspective}
Dimensions: ${dimensions.join(', ')}
Session: ${sessionFolder}
Topic: <topic>
Perspective: <perspective>
Dimensions: <dimensions>
Session: <session-folder>
## MANDATORY FIRST STEPS
1. Run: ccw tool exec get_modules_by_depth '{}'
2. Execute relevant searches based on topic keywords
3. Read: .workflow/project-tech.json (if exists)
## Exploration Focus (${perspective} angle)
${dimensions.map(d => `- ${d}: Identify relevant code patterns and structures`).join('\n')}
## Exploration Focus (<perspective> angle)
<dimensions map to exploration focus areas>
## Output
Write findings to: ${sessionFolder}/explorations/exploration-${exploreNum}.json
Write findings to: <session-folder>/explorations/exploration-<num>.json
Schema: {
perspective: "${perspective}",
perspective: "<perspective>",
relevant_files: [{path, relevance, summary}],
patterns: [string],
key_findings: [string],
@@ -139,102 +160,50 @@ Schema: {
### Phase 4: Result Validation
```javascript
// 验证探索结果
const outputPath = `${sessionFolder}/explorations/exploration-${exploreNum}.json`
let explorationResult = {}
try {
explorationResult = JSON.parse(Read(outputPath))
} catch {
// Agent 未写入文件,使用空结果
explorationResult = {
perspective,
relevant_files: [],
patterns: [],
key_findings: ['Exploration produced no structured output'],
questions_for_analysis: [],
_metadata: { agent: 'cli-explore-agent', timestamp: new Date().toISOString(), status: 'partial' }
}
Write(outputPath, JSON.stringify(explorationResult, null, 2))
}
**Validation steps**:
// 基本质量检查
const hasFiles = explorationResult.relevant_files?.length > 0
const hasFindings = explorationResult.key_findings?.length > 0
| Check | Method | Action on Failure |
|-------|--------|-------------------|
| Output file exists | Read output path | Create empty result structure |
| Has relevant files | Check array length | Trigger ACE fallback |
| Has findings | Check key_findings | Note partial results |
**ACE fallback** (when exploration produces no output):
if (!hasFiles && !hasFindings) {
// 探索结果为空,尝试 ACE 搜索兜底
const aceResults = mcp__ace-tool__search_context({
project_root_path: ".",
query: topic
})
// 补充到结果中
}
```
mcp__ace-tool__search_context({
project_root_path: ".",
query: <topic>
})
```
**Quality validation**:
| Metric | Threshold | Action |
|--------|-----------|--------|
| relevant_files count | > 0 | Proceed |
| key_findings count | > 0 | Proceed |
| Both empty | - | Use ACE fallback, mark partial |
### Phase 5: Report to Coordinator
```javascript
// 更新 shared memory
sharedMemory.explorations = sharedMemory.explorations || []
sharedMemory.explorations.push({
id: `exploration-${exploreNum}`,
perspective,
file_count: explorationResult.relevant_files?.length || 0,
finding_count: explorationResult.key_findings?.length || 0,
timestamp: new Date().toISOString()
})
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
const resultSummary = `${perspective} 视角: ${explorationResult.relevant_files?.length || 0} 个相关文件, ${explorationResult.key_findings?.length || 0} 个发现`
Standard report flow: team_msg log -> SendMessage with `[explorer]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "explorer",
to: "coordinator",
type: "exploration_ready",
summary: `[explorer] ${resultSummary}`,
ref: outputPath
})
**Shared memory update**:
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [explorer] Exploration Results
**Task**: ${task.subject}
**Perspective**: ${perspective}
**Status**: ${hasFiles || hasFindings ? 'Findings Available' : 'Limited Results'}
### Summary
${resultSummary}
### Top Findings
${(explorationResult.key_findings || []).slice(0, 5).map(f => `- ${f}`).join('\n')}
### Questions for Analysis
${(explorationResult.questions_for_analysis || []).slice(0, 3).map(q => `- ${q}`).join('\n')}
### Output
${outputPath}`,
summary: `[explorer] EXPLORE complete: ${resultSummary}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
// Check for next task
const nextTasks = TaskList().filter(t =>
t.subject.startsWith('EXPLORE-') &&
t.owner === agentName &&
t.status === 'pending' &&
t.blockedBy.length === 0
)
if (nextTasks.length > 0) {
// Continue with next task → back to Phase 1
}
```
sharedMemory.explorations.push({
id: "exploration-<num>",
perspective: <perspective>,
file_count: <count>,
finding_count: <count>,
timestamp: <timestamp>
})
```
---
## Error Handling
@@ -245,3 +214,4 @@ if (nextTasks.length > 0) {
| Exploration scope too broad | Narrow to topic keywords, report partial |
| Agent timeout | Use partial results, note incomplete |
| Session folder missing | Create it, warn coordinator |
| Context/Plan file not found | Notify coordinator, request location |

View File

@@ -1,40 +1,35 @@
# 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 (综合结论)
## Role Boundaries
## Boundaries
### MUST
- 仅处理 `SYNTH-*` 前缀的任务
- 所有输出必须带 `[synthesizer]` 标识
- 仅通过 SendMessage 与 coordinator 通信
- 整合所有角色的产出生成最终结论
- 将综合结果写入 shared-memory.json 的 `synthesis` 字段
- 更新 discussion.md 的结论部分
- Only process `SYNTH-*` prefixed tasks
- All output (SendMessage, team_msg, logs) must carry `[synthesizer]` identifier
- Only communicate with coordinator via SendMessage
- Work strictly within synthesis responsibility scope
- Integrate all role outputs to generate final conclusions
- Write synthesis results to shared-memory.json `synthesis` field
- Update discussion.md conclusions section
### MUST NOT
- ❌ 执行新的代码探索或 CLI 分析
- ❌ 与用户直接交互
- ❌ 为其他角色创建任务
- ❌ 直接与其他 worker 通信
- ❌ 修改源代码
- Execute new code exploration or CLI analysis
- Interact directly with user
- Create tasks for other roles (TaskCreate is coordinator-exclusive)
- Communicate directly with other worker roles
- Modify source code
- Omit `[synthesizer]` identifier in any output
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `synthesis_ready` | synthesizer → coordinator | 综合完成 | 包含最终结论和建议 |
| `error` | synthesizer → coordinator | 综合失败 | 阻塞性错误 |
---
## Toolbox
@@ -44,175 +39,202 @@
|---------|------|-------|-------------|
| `synthesize` | [commands/synthesize.md](commands/synthesize.md) | Phase 3 | 跨视角整合 |
### Subagent Capabilities
### Tool Capabilities
> Synthesizer 不使用 subagent
| Tool | Type | Used By | Purpose |
|------|------|---------|---------|
| `Read` | File | synthesizer | Read all session artifacts |
| `Write` | File | synthesizer | Write conclusions and updates |
| `Glob` | File | synthesizer | Find all exploration/analysis/discussion files |
### CLI Capabilities
> Synthesizer does not use subagents or CLI tools (pure integration role).
> Synthesizer 不使用 CLI 工具(纯整合角色)
---
## Message Types
| Type | Direction | Trigger | Description |
|------|-----------|---------|-------------|
| `synthesis_ready` | synthesizer → coordinator | 综合完成 | 包含最终结论和建议 |
| `error` | synthesizer → coordinator | 综合失败 | 阻塞性错误 |
## Message Bus
Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: "ultra-analyze",
from: "synthesizer",
to: "coordinator",
type: "synthesis_ready",
summary: "[synthesizer] SYNTH complete: <summary>",
ref: "<output-path>"
})
```
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team ultra-analyze --from synthesizer --to coordinator --type synthesis_ready --summary \"[synthesizer] ...\" --ref <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.
Falls back to `synthesizer` for single-instance role.
### Phase 2: Context Loading + Shared Memory Read
```javascript
const sessionFolder = task.description.match(/session:\s*(.+)/)?.[1]?.trim()
const topic = task.description.match(/topic:\s*(.+)/)?.[1]?.trim()
**Loading steps**:
const memoryPath = `${sessionFolder}/shared-memory.json`
let sharedMemory = {}
try { sharedMemory = JSON.parse(Read(memoryPath)) } catch {}
1. Extract session path from task description
2. Extract topic
3. Read shared-memory.json
4. Read all exploration files
5. Read all analysis files
6. Read all discussion round files
7. Extract decision trail and current understanding
// Read all explorations
const explorationFiles = Glob({ pattern: `${sessionFolder}/explorations/*.json` })
const allExplorations = explorationFiles.map(f => {
try { return JSON.parse(Read(f)) } catch { return null }
}).filter(Boolean)
**Context extraction**:
// Read all analyses
const analysisFiles = Glob({ pattern: `${sessionFolder}/analyses/*.json` })
const allAnalyses = analysisFiles.map(f => {
try { return JSON.parse(Read(f)) } catch { return null }
}).filter(Boolean)
| Field | Source | Pattern |
|-------|--------|---------|
| sessionFolder | task description | `session:\s*(.+)` |
| topic | task description | `topic:\s*(.+)` |
// Read all discussion rounds
const discussionFiles = Glob({ pattern: `${sessionFolder}/discussions/discussion-round-*.json` })
const allDiscussions = discussionFiles.map(f => {
try { return JSON.parse(Read(f)) } catch { return null }
}).filter(Boolean)
**File loading**:
// Read decision trail
const decisionTrail = sharedMemory.decision_trail || []
const currentUnderstanding = sharedMemory.current_understanding || {}
```
| Artifact | Path Pattern |
|----------|--------------|
| Explorations | `<session>/explorations/*.json` |
| Analyses | `<session>/analyses/*.json` |
| Discussions | `<session>/discussions/discussion-round-*.json` |
| Decision trail | `sharedMemory.decision_trail` |
| Current understanding | `sharedMemory.current_understanding` |
### Phase 3: Synthesis Execution
```javascript
// Read commands/synthesize.md for full implementation
Read("commands/synthesize.md")
```
Delegate to `commands/synthesize.md` if available, otherwise execute inline.
**Synthesis dimensions**:
| Dimension | Source | Purpose |
|-----------|--------|---------|
| Explorations | All exploration files | Cross-perspective file relevance |
| Analyses | All analysis files | Key insights and discussion points |
| Discussions | All discussion rounds | Understanding evolution |
| Decision trail | sharedMemory | Critical decision history |
**Conclusions structure**:
| Field | Description |
|-------|-------------|
| summary | Executive summary |
| key_conclusions | Array of {point, confidence, evidence} |
| recommendations | Array of {priority, action, rationale} |
| open_questions | Remaining unresolved questions |
| _metadata | Synthesis metadata |
**Confidence levels**:
| Level | Criteria |
|-------|----------|
| High | Multiple sources confirm, strong evidence |
| Medium | Single source or partial evidence |
| Low | Speculative, needs verification |
### Phase 4: Write Conclusions + Update discussion.md
```javascript
const synthNum = task.subject.match(/SYNTH-(\d+)/)?.[1] || '001'
const conclusionsPath = `${sessionFolder}/conclusions.json`
**Output paths**:
// 写入 conclusions.json
Write(conclusionsPath, JSON.stringify(conclusions, null, 2))
| File | Path |
|------|------|
| Conclusions | `<session-folder>/conclusions.json` |
| Discussion update | `<session-folder>/discussion.md` |
// 更新 discussion.md — 结论部分
const conclusionsMd = `
**discussion.md conclusions section**:
```markdown
## Conclusions
### Summary
${conclusions.summary}
<conclusions.summary>
### Key Conclusions
${conclusions.key_conclusions.map((c, i) => `${i + 1}. **${c.point}** (Confidence: ${c.confidence})
- Evidence: ${c.evidence}`).join('\n')}
1. **<point>** (Confidence: <confidence>)
- Evidence: <evidence>
2. ...
### Recommendations
${conclusions.recommendations.map((r, i) => `${i + 1}. **[${r.priority}]** ${r.action}
- Rationale: ${r.rationale}`).join('\n')}
1. **[<priority>]** <action>
- Rationale: <rationale>
2. ...
### Remaining Questions
${(conclusions.open_questions || []).map(q => `- ${q}`).join('\n') || '(None)'}
- <question 1>
- <question 2>
## Decision Trail
### Critical Decisions
${decisionTrail.map(d => `- **Round ${d.round}**: ${d.decision}${d.context}`).join('\n') || '(None)'}
- **Round N**: <decision> — <context>
## Current Understanding (Final)
### What We Established
${(currentUnderstanding.established || []).map(e => `- ${e}`).join('\n') || '(None)'}
- <established item 1>
- <established item 2>
### What Was Clarified/Corrected
${(currentUnderstanding.clarified || []).map(c => `- ${c}`).join('\n') || '(None)'}
- <clarified item 1>
- <clarified item 2>
### Key Insights
${(currentUnderstanding.key_insights || []).map(i => `- ${i}`).join('\n') || '(None)'}
- <insight 1>
- <insight 2>
## Session Statistics
- **Explorations**: ${allExplorations.length}
- **Analyses**: ${allAnalyses.length}
- **Discussion Rounds**: ${allDiscussions.length}
- **Decisions Made**: ${decisionTrail.length}
- **Completed**: ${new Date().toISOString()}
`
const currentDiscussion = Read(`${sessionFolder}/discussion.md`)
Write(`${sessionFolder}/discussion.md`, currentDiscussion + conclusionsMd)
- **Explorations**: <count>
- **Analyses**: <count>
- **Discussion Rounds**: <count>
- **Decisions Made**: <count>
- **Completed**: <timestamp>
```
**Update steps**:
1. Write conclusions.json
2. Read current discussion.md
3. Append conclusions section
4. Write updated discussion.md
### Phase 5: Report to Coordinator + Shared Memory Write
```javascript
sharedMemory.synthesis = {
conclusion_count: conclusions.key_conclusions?.length || 0,
recommendation_count: conclusions.recommendations?.length || 0,
open_question_count: conclusions.open_questions?.length || 0,
timestamp: new Date().toISOString()
}
Write(memoryPath, JSON.stringify(sharedMemory, null, 2))
> See SKILL.md Shared Infrastructure -> Worker Phase 5: Report
const resultSummary = `${conclusions.key_conclusions?.length || 0} 结论, ${conclusions.recommendations?.length || 0} 建议`
Standard report flow: team_msg log -> SendMessage with `[synthesizer]` prefix -> TaskUpdate completed -> Loop to Phase 1 for next task.
mcp__ccw-tools__team_msg({
operation: "log",
team: teamName,
from: "synthesizer",
to: "coordinator",
type: "synthesis_ready",
summary: `[synthesizer] Synthesis complete: ${resultSummary}`,
ref: conclusionsPath
})
**Shared memory update**:
SendMessage({
type: "message",
recipient: "coordinator",
content: `## [synthesizer] Synthesis Results
**Task**: ${task.subject}
**Topic**: ${topic}
### Summary
${conclusions.summary}
### Top Conclusions
${(conclusions.key_conclusions || []).slice(0, 3).map((c, i) => `${i + 1}. **${c.point}** (${c.confidence})`).join('\n')}
### Top Recommendations
${(conclusions.recommendations || []).slice(0, 3).map((r, i) => `${i + 1}. [${r.priority}] ${r.action}`).join('\n')}
### Artifacts
- 📄 Discussion: ${sessionFolder}/discussion.md
- 📊 Conclusions: ${conclusionsPath}`,
summary: `[synthesizer] SYNTH complete: ${resultSummary}`
})
TaskUpdate({ taskId: task.id, status: 'completed' })
```
sharedMemory.synthesis = {
conclusion_count: <count>,
recommendation_count: <count>,
open_question_count: <count>,
timestamp: <timestamp>
}
```
---
## Error Handling
@@ -223,3 +245,5 @@ TaskUpdate({ taskId: task.id, status: 'completed' })
| Conflicting analyses | Present both sides, recommend user decision |
| Empty shared memory | Generate minimal conclusions from discussion.md |
| Only one perspective | Create focused single-perspective synthesis |
| Command file not found | Fall back to inline execution |
| Session folder missing | Error to coordinator |