swarm-discussion
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseswarm-discussion
swarm-discussion
"Deep-dive into problems as if multiple experts were debating"
“如同多位专家辩论般深入探讨问题”
Staff+ Engineer Thinking Pattern
资深工程师思考模式
"When there's no clear answer, expose blind spots by confronting diverse perspectives."
For unsolved problems or unprecedented challenges, multiple experts participate as a team,
engaging in "true discussions" through messaging where they challenge and supplement each other.
“当没有明确答案时,通过碰撞多元视角来暴露认知盲区。”
针对未解决的问题或前所未有的挑战,多位专家以团队形式参与,通过消息机制开展“真正的讨论”,相互质疑和补充观点。
Features
核心特性
- Team-based Architecture: Compose teams using the Teammate API
- Messaging-based Dialogue: Experts communicate directly with each other
- Structured Disagreement Protocol: Prevent echo chambers through designed tension
- Argument Graph: Every claim cites or rebuts prior statements with explicit references
- Adaptive Flow: Discussion phases adjust based on convergence signals
- Quality Gates: Automatic checks prevent premature consensus
- Dynamic Expert Generation: Automatically define appropriate experts based on the topic
- Cost-aware Modes: Choose between deep and lightweight discussion modes
- Live Progress Reporting: Real-time updates shown to user as each discussion step completes
- Complete Evidence Preservation: Save all messages with citation chains
- User Participation: Use AskUserQuestion for direction confirmation
- 基于团队的架构:通过Teammate API组建讨论团队
- 基于消息的对话:专家之间直接进行交流
- 结构化分歧协议:通过设计的张力避免回声室效应
- 论点图谱:每个主张都明确引用或反驳先前的陈述
- 自适应流程:讨论阶段根据收敛信号动态调整
- 质量关卡:自动检查防止过早达成共识
- 动态专家生成:根据主题自动定义合适的专家角色
- 成本感知模式:可选择深度、标准或轻量讨论模式
- 实时进度报告:每完成一个讨论步骤就向用户展示实时更新
- 完整证据留存:保存所有带引用链的消息
- 用户参与:通过AskUserQuestion确认讨论方向
Architecture
架构设计
┌─────────────────────────────────────────────────────────────────┐
│ Discussion Team │
│ team_name: discussion-{id} │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Expert 1 │ │ Expert 2 │ │ Contrarian │ │Cross-Domain│ │
│ │ │◄──────────────►│ │◄─────────────►│ │
│ │ inbox ◄───┼──── messages ──┼──► inbox │ messages │ │
│ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │
│ │ │ │ │ │
│ └──────────────┴──────┬───────┴──────────────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ Moderator │ │
│ │ - Present topics │ │
│ │ - Quality gates │ │
│ │ - Convergence │ │
│ └─────────┬─────────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ Historian │ │
│ │ - Argument graph │ │
│ │ - Synthesize │ │
│ └───────────────────┘ │
└─────────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────────┐
│ Discussion Team │
│ team_name: discussion-{id} │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Expert 1 │ │ Expert 2 │ │ Contrarian │ │Cross-Domain│ │
│ │ │◄──────────────►│ │◄─────────────►│ │
│ │ inbox ◄───┼──── messages ──┼──► inbox │ messages │ │
│ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │
│ │ │ │ │ │
│ └──────────────┴──────┬───────┴──────────────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ Moderator │ │
│ │ - Present topics │ │
│ │ - Quality gates │ │
│ │ - Convergence │ │
│ └─────────┬─────────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ Historian │ │
│ │ - Argument graph │ │
│ │ - Synthesize │ │
│ └───────────────────┘ │
└─────────────────────────────────────────────────────────────────┘Discussion Modes
讨论模式
Choose based on problem complexity and budget:
| Mode | Experts | Rounds | Calls/Round | Use When |
|---|---|---|---|---|
| Deep | 3-4 dynamic + 4 fixed | 3-5 | 8-12 | Unprecedented problems, high-stakes decisions |
| Standard | 2-3 dynamic + 4 fixed | 2-3 | 5-8 | Typical design decisions, tradeoff analysis |
| Lightweight | 2 dynamic + 2 fixed (Moderator, Contrarian) | 1-2 | 3-5 | Quick sanity checks, idea validation |
Default: Standard. Specify mode with .
/swarm-discussion --mode deep "topic"可根据问题复杂度和预算选择合适模式:
| 模式 | 专家配置 | 轮次 | 每轮调用数 | 适用场景 |
|---|---|---|---|---|
| 深度模式 | 3-4个动态专家 + 4个固定角色 | 3-5轮 | 8-12次 | 前所未有的问题、高风险决策 |
| 标准模式 | 2-3个动态专家 + 4个固定角色 | 2-3轮 | 5-8次 | 典型设计决策、权衡分析 |
| 轻量模式 | 2个动态专家 + 2个固定角色(Moderator、Contrarian) | 1-2轮 | 3-5次 | 快速合理性检查、想法验证 |
默认模式:标准模式。可通过指定模式。
/swarm-discussion --mode deep "topic"Role Design
角色设计
Fixed Roles
固定角色
| Role | Responsibility | Quality Function |
|---|---|---|
| Moderator | Facilitate discussion, enforce quality gates, determine convergence | Prevents premature consensus; ensures all perspectives are heard |
| Historian | Build argument graph, synthesize, generate summaries | Maintains traceability; prevents circular arguments |
| Contrarian | Question assumptions, present counterarguments | Prevents echo chambers; stress-tests ideas |
| Cross-Domain | Provide analogies from other fields | Prevents domain-locked thinking; seeds novel approaches |
| 角色 | 职责 | 质量保障作用 |
|---|---|---|
| Moderator | 主持讨论、执行质量关卡、判断共识收敛 | 防止过早达成共识;确保所有视角都被倾听 |
| Historian | 构建论点图谱、综合分析、生成总结 | 保持可追溯性;防止循环论证 |
| Contrarian | 质疑假设、提出反论点 | 避免回声室效应;压力测试想法 |
| Cross-Domain | 提供其他领域的类比参考 | 避免领域局限思维;激发创新思路 |
Dynamically Generated Roles (2-4 based on topic and mode)
动态生成角色(根据主题和模式生成2-4个)
Analyze the topic and define appropriate experts. Each expert has the following attributes:
json
{
"id": "database-expert",
"name": "Database Expert",
"expertise": ["RDB", "NoSQL", "Distributed DB"],
"thinkingStyle": "pragmatic",
"bias": "Prioritizes practicality and performance",
"replyTendency": "Shows concrete implementation examples",
"stakes": "Owns the data layer; bad decisions mean data loss or inconsistency",
"blindSpots": ["Tends to underestimate application-level complexity"]
}New fields:
- : What this expert stands to lose if the wrong decision is made. Drives genuine engagement.
stakes - : Known limitations of this perspective. Enables other experts to target these.
blindSpots
分析主题并定义合适的专家,每个专家具备以下属性:
json
{
"id": "database-expert",
"name": "Database Expert",
"expertise": ["RDB", "NoSQL", "Distributed DB"],
"thinkingStyle": "pragmatic",
"bias": "Prioritizes practicality and performance",
"replyTendency": "Shows concrete implementation examples",
"stakes": "Owns the data layer; bad decisions mean data loss or inconsistency",
"blindSpots": ["Tends to underestimate application-level complexity"]
}新增字段:
- :若决策错误,该专家将面临的损失。驱动真正的参与度。
stakes - :该视角的已知局限性。让其他专家能够针对性挑战。
blindSpots
Tension Map (Critical for Discussion Quality)
张力映射(对讨论质量至关重要)
When generating personas, the Moderator MUST design a tension map — pairs of experts with naturally opposing viewpoints:
json
{
"tensionMap": [
{
"between": ["database-expert", "api-designer"],
"axis": "Data consistency vs. API flexibility",
"description": "Database Expert wants strict schemas; API Designer wants loose coupling"
},
{
"between": ["security-engineer", "ml-practitioner"],
"axis": "Control vs. Autonomy",
"description": "Security Engineer restricts; ML Practitioner needs freedom to experiment"
}
]
}Why this matters: Without designed tension, AI agents tend toward premature agreement. The tension map ensures that at least some expert pairs have structurally opposing incentives, producing genuine debate rather than a series of "I agree, and also..." statements.
生成角色时,Moderator必须设计张力映射——即存在天然对立观点的专家配对:
json
{
"tensionMap": [
{
"between": ["database-expert", "api-designer"],
"axis": "Data consistency vs. API flexibility",
"description": "Database Expert wants strict schemas; API Designer wants loose coupling"
},
{
"between": ["security-engineer", "ml-practitioner"],
"axis": "Control vs. Autonomy",
"description": "Security Engineer restricts; ML Practitioner needs freedom to experiment"
}
]
}重要性:如果没有设计好的张力,AI Agent往往会过早达成一致。张力映射确保至少有部分专家配对存在结构性对立的动机,从而产生真正的辩论,而非一系列“我同意,而且...”的陈述。
Structured Disagreement Protocol
结构化分歧协议
The Echo Chamber Problem
回声室问题
AI agents playing expert roles naturally tend to:
- Agree with well-reasoned prior statements
- Add supplementary points rather than challenge
- Converge too quickly on the first plausible solution
扮演专家角色的AI Agent自然倾向于:
- 认同推理严谨的先前陈述
- 补充观点而非挑战
- 过快收敛到第一个看似合理的解决方案
Prevention Mechanisms
预防机制
1. Mandatory Position Declaration
Before the discussion begins, each expert MUST declare a preliminary position:
json
{
"from": "database-expert",
"type": "position_declaration",
"position": "Saga pattern with orchestration",
"confidence": 0.7,
"conditions": "Assuming < 10 services involved",
"wouldChangeIf": "Someone shows orchestration overhead exceeds 30% of request latency"
}The field is critical — it forces each expert to pre-commit to what evidence would change their mind, preventing unfalsifiable positions.
wouldChangeIf2. Steel-Manning Requirement
Before disagreeing, an expert MUST demonstrate understanding of the opposing view:
Before I present my counterargument, let me confirm I understand the position:
[Restate the argument in the strongest possible form]
My concern with this is: [counterargument]3. Disagreement Budget
The Moderator tracks a "disagreement score" for each round:
- If score < 2 (too much agreement): Moderator explicitly asks "What could go wrong with this consensus?" and directs Contrarian to challenge the strongest agreement
- If score > 8 (too much disagreement): Moderator asks "Where is the common ground?" and focuses on finding shared premises
4. Position Shift Tracking
The Historian records when experts change their positions:
json
{
"type": "position_shift",
"expert": "database-expert",
"from": "Saga pattern with orchestration",
"to": "Event sourcing with compensating actions",
"trigger": "Message #msg-007 from operations-engineer",
"reasoning": "Operational complexity of orchestrator convinced me"
}1. 强制立场声明
讨论开始前,每位专家必须声明初步立场:
json
{
"from": "database-expert",
"type": "position_declaration",
"position": "Saga pattern with orchestration",
"confidence": 0.7,
"conditions": "Assuming < 10 services involved",
"wouldChangeIf": "Someone shows orchestration overhead exceeds 30% of request latency"
}wouldChangeIf2. 最强反驳要求
在提出反对意见前,专家必须证明自己理解对立观点:
在提出我的反论点之前,先确认我是否理解了你的立场:
[以最有力的形式重述对方论点]
我对此的担忧是:[反论点]3. 分歧预算
Moderator跟踪每轮的“分歧得分”:
- 如果得分<2(过于一致):Moderator明确询问“这个共识可能存在什么问题?”,并指示Contrarian挑战最强烈的共识
- 如果得分>8(过于分歧):Moderator询问“共识基础在哪里?”,专注于寻找共同前提
4. 立场转变跟踪
Historian记录专家何时改变立场:
json
{
"type": "position_shift",
"expert": "database-expert",
"from": "Saga pattern with orchestration",
"to": "Event sourcing with compensating actions",
"trigger": "Message #msg-007 from operations-engineer",
"reasoning": "Operational complexity of orchestrator convinced me"
}Discussion Flow
讨论流程
Phase 1: Initialization
阶段1:初始化
javascript
// 1. Generate discussion ID
const discussionId = slugify(topic); // e.g., "microservice-transaction"
// 2. Determine mode (deep / standard / lightweight)
const mode = parseMode(userInput); // default: "standard"
// 3. Create team
Teammate({
operation: "spawnTeam",
team_name: `discussion-${discussionId}`
})
// 4. Create directory structure
Bash({
command: `mkdir -p ~/.claude/discussions/${discussionId}/{personas,rounds,artifacts,context}`
})
// 5. Analyze topic and define experts with tension map
const topicAnalysis = analyzeTopicAndDefineExperts(topic, mode);
// → {
// experts: [{ id, name, expertise, thinkingStyle, bias, replyTendency, stakes, blindSpots }],
// tensionMap: [{ between, axis, description }],
// problemDefinition: { statement, scope, successCriteria }
// }
// 6. Add fixed roles (based on mode)
const fixedRoles = mode === "lightweight"
? [
{ id: "moderator", name: "Moderator", role: "Discussion facilitator" },
{ id: "contrarian", name: "Contrarian", role: "Devil's advocate" }
]
: [
{ id: "moderator", name: "Moderator", role: "Discussion facilitator" },
{ id: "historian", name: "Historian", role: "Record keeper" },
{ id: "contrarian", name: "Contrarian", role: "Devil's advocate" },
{ id: "cross-domain", name: "Cross-Domain", role: "Alternative perspective" }
];
const allExperts = [...topicAnalysis.experts, ...fixedRoles];
// 7. Confirm expert composition with user (show tension map)
AskUserQuestion({
questions: [{
question: `Start discussion with the following experts?\n\n` +
`**Dynamic Experts:**\n${topicAnalysis.experts.map(e =>
`- ${e.name} (${e.thinkingStyle}) — Stakes: ${e.stakes}`
).join('\n')}\n\n` +
`**Designed Tensions:**\n${topicAnalysis.tensionMap.map(t =>
`- ${t.between[0]} vs ${t.between[1]}: ${t.axis}`
).join('\n')}\n\n` +
`**Mode:** ${mode}`,
header: "Confirm Experts & Tensions",
options: [
{ label: "Start (Recommended)", description: "Begin with this composition" },
{ label: "Modify", description: "Add or change experts" },
{ label: "Change Mode", description: "Switch between deep/standard/lightweight" }
],
multiSelect: false
}]
})
// 8. Save manifest.json (includes tension map)
Write(`~/.claude/discussions/${discussionId}/manifest.json`, {
id: discussionId,
title: topic,
created: new Date().toISOString(),
status: "active",
mode: mode,
currentPhase: "initial",
currentRound: 0,
team_name: `discussion-${discussionId}`,
personas: allExperts,
tensionMap: topicAnalysis.tensionMap,
problemDefinition: topicAnalysis.problemDefinition
})
// 9. Save each expert definition
for (const expert of allExperts) {
Write(`~/.claude/discussions/${discussionId}/personas/${expert.id}.json`, expert)
}javascript
// 1. 生成讨论ID
const discussionId = slugify(topic); // 例如:"microservice-transaction"
// 2. 确定模式(deep / standard / lightweight)
const mode = parseMode(userInput); // 默认:"standard"
// 3. 创建团队
Teammate({
operation: "spawnTeam",
team_name: `discussion-${discussionId}`
})
// 4. 创建目录结构
Bash({
command: `mkdir -p ~/.claude/discussions/${discussionId}/{personas,rounds,artifacts,context}`
})
// 5. 分析主题并定义专家及张力映射
const topicAnalysis = analyzeTopicAndDefineExperts(topic, mode);
// → {
// experts: [{ id, name, expertise, thinkingStyle, bias, replyTendency, stakes, blindSpots }],
// tensionMap: [{ between, axis, description }],
// problemDefinition: { statement, scope, successCriteria }
// }
// 6. 添加固定角色(根据模式)
const fixedRoles = mode === "lightweight"
? [
{ id: "moderator", name: "Moderator", role: "Discussion facilitator" },
{ id: "contrarian", name: "Contrarian", role: "Devil's advocate" }
]
: [
{ id: "moderator", name: "Moderator", role: "Discussion facilitator" },
{ id: "historian", name: "Historian", role: "Record keeper" },
{ id: "contrarian", name: "Contrarian", role: "Devil's advocate" },
{ id: "cross-domain", name: "Cross-Domain", role: "Alternative perspective" }
];
const allExperts = [...topicAnalysis.experts, ...fixedRoles];
// 7. 与用户确认专家配置(展示张力映射)
AskUserQuestion({
questions: [{
question: `是否使用以下专家开始讨论?\n\n` +
`**动态专家:**\n${topicAnalysis.experts.map(e =>
`- ${e.name} (${e.thinkingStyle}) — 利益相关:${e.stakes}`
).join('\n')}\n\n` +
`**设计的张力:**\n${topicAnalysis.tensionMap.map(t =>
`- ${t.between[0]} vs ${t.between[1]}: ${t.axis}`
).join('\n')}\n\n` +
`**模式:** ${mode}`,
header: "确认专家与张力配置",
options: [
{ label: "开始(推荐)", description: "使用此配置开始" },
{ label: "修改", description: "添加或更改专家" },
{ label: "切换模式", description: "在深度/标准/轻量模式间切换" }
],
multiSelect: false
}]
})
// 8. 保存manifest.json(包含张力映射)
Write(`~/.claude/discussions/${discussionId}/manifest.json`, {
id: discussionId,
title: topic,
created: new Date().toISOString(),
status: "active",
mode: mode,
currentPhase: "initial",
currentRound: 0,
team_name: `discussion-${discussionId}`,
personas: allExperts,
tensionMap: topicAnalysis.tensionMap,
problemDefinition: topicAnalysis.problemDefinition
})
// 9. 保存每个专家的定义
for (const expert of allExperts) {
Write(`~/.claude/discussions/${discussionId}/personas/${expert.id}.json`, expert)
}Phase 2: Round Execution (Position → Debate → Convergence Check)
阶段2:轮次执行(立场声明 → 辩论 → 收敛检查)
Live Progress Reporting
实时进度报告
During round execution, the orchestrator MUST report progress to the user after each
major step completes. This serves two purposes:
- User-facing output: Print a concise markdown summary directly to the conversation so the user sees what's happening in real-time, without waiting for the full round.
- Progress file: Append to so the user can check the file at any time (e.g., from another terminal).
~/.claude/discussions/{id}/progress.md
Progress format (output directly to the user after each step):
undefined在轮次执行期间,编排器必须在每个主要步骤完成后向用户报告进度。这有两个目的:
- 面向用户的输出:直接在对话中打印简洁的Markdown摘要,让用户实时了解进展,无需等待整轮完成。
- 进度文件:将内容追加到,以便用户随时查看(例如从其他终端)。
~/.claude/discussions/{id}/progress.md
进度格式(每个步骤完成后直接输出给用户):
undefined📍 Round {N} — Step {step}: {step_name}
📍 第{N}轮 — 步骤{step}:{step_name}
{1-3 sentence summary of what just happened}
Key takeaway: {most important point from this step}
The orchestrator MUST NOT silently proceed through all steps. Each step's result
must be surfaced to the user immediately.
```javascript
async function executeRound(discussionId, roundNum, roundTopic) {
const teamName = `discussion-${discussionId}`;
const manifest = loadManifest(discussionId);
const experts = loadPersonas(discussionId);
const mode = manifest.mode;
// Live progress file path
const progressFile = `~/.claude/discussions/${discussionId}/progress.md`;
// Helper: Report progress to user and append to progress file
function reportProgress(step, stepName, summary, keyTakeaway) {
const progressEntry = `### Round ${roundNum} — Step ${step}: ${stepName}\n\n` +
`${summary}\n\n` +
`**Key takeaway**: ${keyTakeaway}\n\n---\n\n`;
// 1. Print directly to user (output as text in the conversation)
output(progressEntry);
// 2. Append to progress file for async checking
Bash({ command: `echo '${escapeForShell(progressEntry)}' >> ${progressFile}` });
}
// Track argument graph for this round
const argumentGraph = [];
let messageCounter = 0;
function nextMsgId() { return `r${roundNum}-msg-${String(++messageCounter).padStart(3, '0')}`; }
// Array to store all messages
const allMessages = [];
// ========== Step 1: Position Declaration (NEW) ==========
// Each dynamic expert declares their preliminary position BEFORE seeing others
// This prevents anchoring bias from the first speaker
const positionDeclarations = [];
for (const expert of getDynamicExperts(experts)) {
Task({
team_name: teamName,
name: expert.id,
subagent_type: "general-purpose",
prompt: buildPositionDeclarationPrompt(expert, roundTopic),
run_in_background: true
})
}
// Collect position declarations
for (const expert of getDynamicExperts(experts)) {
const declaration = await collectStatement(expert.id);
const msgId = nextMsgId();
positionDeclarations.push({
id: msgId,
from: expert.id,
type: "position_declaration",
content: declaration, // { position, confidence, conditions, wouldChangeIf }
timestamp: new Date().toISOString()
});
allMessages.push(positionDeclarations[positionDeclarations.length - 1]);
}
// >>> PROGRESS REPORT: Position Declarations <<<
reportProgress(1, "Position Declarations",
positionDeclarations.map(d =>
`**${d.from}**: "${d.content.position}" (confidence: ${d.content.confidence})`
).join('\n'),
`${positionDeclarations.length} experts declared positions. ` +
`Confidence range: ${Math.min(...positionDeclarations.map(d => d.content.confidence))}–${Math.max(...positionDeclarations.map(d => d.content.confidence))}`
);
// ========== Step 2: Moderator Opening ==========
// Moderator now has ALL positions and can frame the discussion
// around actual disagreements rather than generic angles
const moderatorOpening = await Task({
team_name: teamName,
name: "moderator",
subagent_type: "general-purpose",
prompt: `
You are the Moderator. Frame this round's discussion.
【Topic】
${roundTopic}
【Position Declarations】
${formatPositionDeclarations(positionDeclarations)}
【Tension Map】
${JSON.stringify(manifest.tensionMap, null, 2)}
【Previous Discussion】
${previousRoundsSummary || "(New discussion)"}
【Task】
1. Identify where positions actually diverge (not where they superficially differ)
2. Frame 2-3 specific questions that target the real disagreements
3. Direct questions to specific experts based on the tension map
4. Set the disagreement budget for this round (target: 3-6 on a 0-10 scale)
Do NOT present generic angles. Use the position declarations to find genuine fault lines.
`
});
const moderatorMsgId = nextMsgId();
allMessages.push({
id: moderatorMsgId,
from: "moderator",
type: "opening",
content: moderatorOpening,
timestamp: new Date().toISOString()
});
// Broadcast to all
broadcastMessage(teamName, "moderator", moderatorOpening, experts);
// >>> PROGRESS REPORT: Moderator Opening <<<
reportProgress(2, "Moderator Framing",
`Moderator identified key fault lines and framed ${mode === "lightweight" ? "1-2" : "2-3"} targeted questions for the experts.`,
moderatorOpening.substring(0, 200) + "..."
);
// ========== Step 3: Argumentation Phase ==========
// Dynamic experts argue their positions with CITATIONS
// Must reference prior messages by ID
for (const expert of getDynamicExperts(experts)) {
Task({
team_name: teamName,
name: expert.id,
subagent_type: "general-purpose",
prompt: buildExpertPrompt(expert, {
phase: "argumentation",
topic: roundTopic,
positionDeclarations: positionDeclarations,
moderatorOpening: moderatorOpening,
tensionMap: manifest.tensionMap,
instruction: `
Argue your position. You MUST:
1. Reference at least one other expert's position by message ID (e.g., "Regarding ${positionDeclarations[0]?.id}...")
2. Steel-man any position you disagree with before countering it
3. Identify what evidence would change your mind
4. Be specific — cite concrete scenarios, numbers, or code examples
Do NOT simply agree with others. If you agree, explain what ADDITIONAL risk or nuance they missed.
`
}),
run_in_background: true
})
}
// Collect arguments and build argument graph
const arguments = [];
for (const expert of getDynamicExperts(experts)) {
const argument = await collectStatement(expert.id);
const msgId = nextMsgId();
const msg = {
id: msgId,
from: expert.id,
type: "argument",
content: argument,
references: extractReferences(argument), // Parse referenced message IDs
timestamp: new Date().toISOString()
};
arguments.push(msg);
allMessages.push(msg);
// Build argument graph edge
for (const ref of msg.references) {
argumentGraph.push({
from: msgId,
to: ref.targetId,
relation: ref.type // "supports", "counters", "extends", "questions"
});
}
broadcastMessage(teamName, expert.id, argument, experts);
}
// >>> PROGRESS REPORT: Argumentation <<<
reportProgress(3, "Expert Arguments",
arguments.map(a =>
`**${a.from}**: "${a.content.position}" — references: ${a.references.map(r => r.targetId).join(', ') || 'none'}`
).join('\n'),
`${arguments.length} arguments filed with ${argumentGraph.length} cross-references. ` +
`${argumentGraph.filter(e => e.relation === 'counters').length} counterarguments, ` +
`${argumentGraph.filter(e => e.relation === 'supports').length} supporting arguments.`
);
// ========== Step 4: Contrarian Stress Test ==========
// Contrarian targets the STRONGEST consensus, not the weakest argument
const contrarianResponse = await Task({
team_name: teamName,
name: "contrarian",
subagent_type: "general-purpose",
prompt: `
You are the Contrarian.
【Topic】
${roundTopic}
【All Arguments So Far】
${formatMessagesWithIds(allMessages)}
【Argument Graph】
${JSON.stringify(argumentGraph, null, 2)}
【Task】
1. Identify the point where most experts AGREE — this is your primary target
2. Challenge this consensus: What assumption does it rest on? What if that assumption is wrong?
3. Find the WEAKEST evidence cited in support of the consensus
4. Present a concrete scenario where the consensus leads to failure
5. If there's genuine disagreement already, amplify the minority position with new arguments
Do NOT be contrarian for its own sake. Target the most dangerous blind spot.
Reference prior messages by ID when challenging them.
`
});
const contrarianMsgId = nextMsgId();
allMessages.push({
id: contrarianMsgId,
from: "contrarian",
type: "stress_test",
content: contrarianResponse,
references: extractReferences(contrarianResponse),
timestamp: new Date().toISOString()
});
broadcastMessage(teamName, "contrarian", contrarianResponse, experts);
// >>> PROGRESS REPORT: Contrarian Stress Test <<<
reportProgress(4, "Contrarian Stress Test",
`Contrarian targeted the emerging consensus and challenged ${extractReferences(contrarianResponse).length} prior arguments.`,
typeof contrarianResponse === 'string'
? contrarianResponse.substring(0, 200) + "..."
: JSON.stringify(contrarianResponse).substring(0, 200) + "..."
);
// ========== Step 5: Response Phase ==========
// Experts respond to Contrarian — must explicitly state if position shifted
for (const expert of getDynamicExperts(experts)) {
Task({
team_name: teamName,
name: expert.id,
subagent_type: "general-purpose",
prompt: buildExpertPrompt(expert, {
phase: "response",
topic: roundTopic,
allMessages: allMessages,
contrarianResponse: contrarianResponse,
contrarianMsgId: contrarianMsgId,
instruction: `
Respond to Contrarian's stress test (${contrarianMsgId}).
You MUST include a position update:
{
"positionShift": "none" | "minor" | "major",
"currentPosition": "Your current stance",
"previousPosition": "Your stance before this round (from position declaration)",
"shiftReason": "What specifically changed your mind (if anything)"
}
If your position hasn't changed, explain specifically why the Contrarian's argument doesn't apply to your case.
`
}),
run_in_background: true
})
}
// Collect responses and track position shifts
const responses = [];
const positionShifts = [];
for (const expert of getDynamicExperts(experts)) {
const response = await collectStatement(expert.id);
const msgId = nextMsgId();
responses.push({
id: msgId,
from: expert.id,
type: "response",
content: response,
references: extractReferences(response),
timestamp: new Date().toISOString()
});
allMessages.push(responses[responses.length - 1]);
// Track position shifts
if (response.positionShift && response.positionShift !== "none") {
positionShifts.push({
type: "position_shift",
expert: expert.id,
from: response.previousPosition,
to: response.currentPosition,
trigger: contrarianMsgId,
reasoning: response.shiftReason
});
}
}
// >>> PROGRESS REPORT: Response Phase <<<
reportProgress(5, "Expert Responses & Position Shifts",
responses.map(r =>
`**${r.from}**: shift=${r.content.positionShift || 'none'}` +
(r.content.positionShift !== 'none' ? ` → "${r.content.currentPosition}"` : '')
).join('\n'),
positionShifts.length > 0
? `${positionShifts.length} position shift(s) detected! ${positionShifts.map(s => `${s.expert} shifted due to ${s.trigger}`).join('; ')}`
: `No position shifts — experts held their ground against the Contrarian's challenge.`
);
// ========== Step 6: Cross-Domain Perspective (Standard/Deep only) ==========
if (mode !== "lightweight") {
const crossDomainResponse = await Task({
team_name: teamName,
name: "cross-domain",
subagent_type: "general-purpose",
prompt: `
You are the Cross-Domain Thinker.
【Topic】
${roundTopic}
【Discussion So Far (with message IDs)】
${formatMessagesWithIds(allMessages)}
【Position Shifts This Round】
${JSON.stringify(positionShifts, null, 2)}
【Task】
1. Identify the UNDERLYING pattern in this debate (not the surface-level topic)
2. Find an analogous problem in a completely different field where this pattern was resolved
3. Explain the analogy in detail: what maps to what, and what doesn't map
4. Propose a framework or principle from the analogous field
5. Be honest about where the analogy breaks down
Fields to consider: biology, physics, economics, law, military strategy, urban planning, game theory, ecology.
Reference specific messages by ID that your analogy addresses.
`
});
const crossDomainMsgId = nextMsgId();
allMessages.push({
id: crossDomainMsgId,
from: "cross-domain",
type: "analogy",
content: crossDomainResponse,
references: extractReferences(crossDomainResponse),
timestamp: new Date().toISOString()
});
// >>> PROGRESS REPORT: Cross-Domain <<<
reportProgress(6, "Cross-Domain Perspective",
`Cross-Domain Thinker provided analogies from other fields, referencing ${extractReferences(crossDomainResponse).length} prior messages.`,
typeof crossDomainResponse === 'string'
? crossDomainResponse.substring(0, 200) + "..."
: JSON.stringify(crossDomainResponse).substring(0, 200) + "..."
);
}
// ========== Step 7: Quality Gate & Convergence Check ==========
const qualityCheck = await Task({
team_name: teamName,
name: "moderator",
subagent_type: "general-purpose",
prompt: `
Evaluate this round's discussion quality and synthesize.
【All Messages】
${formatMessagesWithIds(allMessages)}
【Argument Graph】
${JSON.stringify(argumentGraph, null, 2)}
【Position Shifts】
${JSON.stringify(positionShifts, null, 2)}
【Quality Gate Checklist】
Rate each 1-5 and explain:
1. Genuine Disagreement: Did experts actually challenge each other, or just agree?
2. Evidence Quality: Were claims supported by specifics (scenarios, data, code)?
3. Steel-manning: Did experts accurately represent opposing views before countering?
4. Novel Insights: Did the discussion produce ideas not present in initial positions?
5. Position Evolution: Did any expert change their mind based on arguments?
【Synthesis Task】
{
"qualityScore": {
"genuineDisagreement": 1-5,
"evidenceQuality": 1-5,
"steelManning": 1-5,
"novelInsights": 1-5,
"positionEvolution": 1-5,
"overall": 1-5
},
"summary": "Summary of this round (200-300 characters)",
"agreements": [{ "point": "...", "supporters": ["expert-ids"], "strength": "strong|moderate|weak" }],
"activeDisagreements": [{ "point": "...", "positions": [{"stance": "...", "advocates": ["expert-ids"]}] }],
"insights": [{ "insight": "...", "novelty": "high|medium|low", "source": "message-id" }],
"openQuestions": ["..."],
"positionShifts": [...],
"recommendation": "continue|deep-dive|different-angle|synthesize",
"recommendationReason": "Why this next step"
}
If overall quality < 3, flag it and suggest what went wrong (e.g., "Too much agreement — re-run with sharper Contrarian framing").
`
});
// ========== Step 8: Record ==========
const roundRecord = {
roundId: roundNum,
topic: roundTopic,
mode: mode,
timestamp: new Date().toISOString(),
messages: allMessages,
argumentGraph: argumentGraph,
positionShifts: positionShifts,
synthesis: JSON.parse(qualityCheck),
metadata: {
messageCount: allMessages.length,
participants: [...new Set(allMessages.map(m => m.from))],
referenceCount: argumentGraph.length
}
};
// Historian records (Standard/Deep only)
if (mode !== "lightweight") {
await Task({
team_name: teamName,
name: "historian",
subagent_type: "general-purpose",
prompt: `
Record this round's discussion for the argument graph.
【Round Record】
${JSON.stringify(roundRecord, null, 2)}
Save the following to the round file:
1. Complete message history with IDs and references
2. Argument graph edges (who challenged/supported whom)
3. Position shifts with triggers
4. Quality assessment
Also update a running "argument map" that shows the evolution of positions across rounds.
`
});
}
Write(`~/.claude/discussions/${discussionId}/rounds/${String(roundNum).padStart(3, '0')}.json`, roundRecord)
// ========== Step 9: Confirm Next Action ==========
const synthesis = roundRecord.synthesis;
const recommendation = synthesis.recommendation || "continue";
AskUserQuestion({
questions: [{
question: `Round ${roundNum} complete.\n\n` +
`**Quality Score:** ${synthesis.qualityScore?.overall || "N/A"}/5\n` +
`**Position Shifts:** ${positionShifts.length}\n` +
`**Recommendation:** ${recommendation} — ${synthesis.recommendationReason || ""}\n\n` +
`What would you like to do next?`,
header: "Round Complete",
options: [
{ label: "Follow recommendation", description: `${recommendation}` },
{ label: "Deep dive", description: synthesis.activeDisagreements?.[0]?.point || "Most contested topic" },
{ label: "Different angle", description: "Explore a different aspect" },
{ label: "Inject constraint", description: "Add a new requirement or assumption" },
{ label: "Synthesis phase", description: "Summarize the discussion" },
{ label: "Pause", description: "Resume later" }
],
multiSelect: false
}]
})
return roundRecord;
}
// Helper: Build position declaration prompt
function buildPositionDeclarationPrompt(expert, topic) {
return `
You are "${expert.name}".
【Your Profile】
- Areas of expertise: ${expert.expertise.join(", ")}
- Thinking style: ${expert.thinkingStyle}
- Natural bias: ${expert.bias}
- What you stand to lose from a bad decision: ${expert.stakes}
- Your known blind spots: ${expert.blindSpots?.join(", ") || "None declared"}
【Topic】
${topic}
【Task】
Declare your preliminary position BEFORE hearing from others.
Output format:
{
"position": "Your stance in 1-2 sentences",
"confidence": 0.0-1.0,
"conditions": "Under what assumptions this holds",
"wouldChangeIf": "What evidence would make you reconsider",
"keyRisk": "The biggest risk if your position is adopted"
}
Be honest about your confidence. Low confidence is fine — it signals where the group needs to dig deeper.
`;
}
// Helper: Broadcast message
function broadcastMessage(teamName, fromId, message, experts) {
for (const expert of experts) {
if (expert.id !== fromId && expert.id !== "historian") {
Teammate({
operation: "write",
target_agent_id: expert.id,
value: JSON.stringify({
type: "message",
from: fromId,
content: message
})
})
}
}
}
// Helper: Extract references from message content
function extractReferences(content) {
// Parse "r1-msg-001" style references from the text
const refs = [];
const pattern = /r\d+-msg-\d{3}/g;
let match;
while ((match = pattern.exec(JSON.stringify(content))) !== null) {
refs.push({ targetId: match[0], type: "references" });
}
return refs;
}{1-3句话总结刚刚完成的内容}
关键要点:{此步骤最重要的结论}
编排器不得静默执行所有步骤。每个步骤的结果必须立即呈现给用户。
```javascript
async function executeRound(discussionId, roundNum, roundTopic) {
const teamName = `discussion-${discussionId}`;
const manifest = loadManifest(discussionId);
const experts = loadPersonas(discussionId);
const mode = manifest.mode;
// 实时进度文件路径
const progressFile = `~/.claude/discussions/${discussionId}/progress.md`;
// 辅助函数:向用户报告进度并追加到进度文件
function reportProgress(step, stepName, summary, keyTakeaway) {
const progressEntry = `### 第${roundNum}轮 — 步骤${step}:${stepName}\n\n` +
`${summary}\n\n` +
`**关键要点**:${keyTakeaway}\n\n---\n\n`;
// 1. 直接打印给用户(在对话中输出文本)
output(progressEntry);
// 2. 追加到进度文件以便异步查看
Bash({ command: `echo '${escapeForShell(progressEntry)}' >> ${progressFile}` });
}
// 跟踪本轮的论点图谱
const argumentGraph = [];
let messageCounter = 0;
function nextMsgId() { return `r${roundNum}-msg-${String(++messageCounter).padStart(3, '0')}`; }
// 存储所有消息的数组
const allMessages = [];
// ========== 步骤1:立场声明(新增) ==========
// 每位动态专家在查看他人立场前先声明自己的立场
// 这避免了先发言者的锚定偏见
const positionDeclarations = [];
for (const expert of getDynamicExperts(experts)) {
Task({
team_name: teamName,
name: expert.id,
subagent_type: "general-purpose",
prompt: buildPositionDeclarationPrompt(expert, roundTopic),
run_in_background: true
})
}
// 收集立场声明
for (const expert of getDynamicExperts(experts)) {
const declaration = await collectStatement(expert.id);
const msgId = nextMsgId();
positionDeclarations.push({
id: msgId,
from: expert.id,
type: "position_declaration",
content: declaration, // { position, confidence, conditions, wouldChangeIf }
timestamp: new Date().toISOString()
});
allMessages.push(positionDeclarations[positionDeclarations.length - 1]);
}
// >>> 进度报告:立场声明 <<<
reportProgress(1, "立场声明",
positionDeclarations.map(d =>
`**${d.from}**: "${d.content.position}" (置信度: ${d.content.confidence})`
).join('\n'),
`${positionDeclarations.length}位专家已声明立场。 ` +
`置信度范围: ${Math.min(...positionDeclarations.map(d => d.content.confidence))}–${Math.max(...positionDeclarations.map(d => d.content.confidence))}`
);
// ========== 步骤2:Moderator开场 ==========
// Moderator现在掌握了所有立场,可以围绕实际分歧来构建讨论框架
// 而非泛泛而谈
const moderatorOpening = await Task({
team_name: teamName,
name: "moderator",
subagent_type: "general-purpose",
prompt: `
你是Moderator。构建本轮讨论的框架。
【讨论主题】
${roundTopic}
【立场声明】
${formatPositionDeclarations(positionDeclarations)}
【张力映射】
${JSON.stringify(manifest.tensionMap, null, 2)}
【先前讨论】
${previousRoundsSummary || "(新讨论)"}
【任务】
1. 识别立场真正分歧的地方(而非表面差异)
2. 提出2-3个针对真正分歧的具体问题
3. 根据张力映射将问题定向到特定专家
4. 设置本轮的分歧预算(目标:0-10分制中的3-6分)
不要提出泛泛的角度。利用立场声明找到真正的分歧点。
`
});
const moderatorMsgId = nextMsgId();
allMessages.push({
id: moderatorMsgId,
from: "moderator",
type: "opening",
content: moderatorOpening,
timestamp: new Date().toISOString()
});
// 广播给所有专家
broadcastMessage(teamName, "moderator", moderatorOpening, experts);
// >>> 进度报告:Moderator开场 <<<
reportProgress(2, "Moderator框架构建",
`Moderator识别了关键分歧点,并为专家提出了${mode === "lightweight" ? "1-2个" : "2-3个"}针对性问题。`,
moderatorOpening.substring(0, 200) + "..."
);
// ========== 步骤3:论证阶段 ==========
// 动态专家通过引用论据来论证自己的立场
// 必须通过ID引用先前的消息
for (const expert of getDynamicExperts(experts)) {
Task({
team_name: teamName,
name: expert.id,
subagent_type: "general-purpose",
prompt: buildExpertPrompt(expert, {
phase: "argumentation",
topic: roundTopic,
positionDeclarations: positionDeclarations,
moderatorOpening: moderatorOpening,
tensionMap: manifest.tensionMap,
instruction: `
论证你的立场。你必须:
1. 至少通过消息ID引用一位其他专家的立场(例如:"关于${positionDeclarations[0]?.id}...")
2. 在反驳前,先以最强形式呈现你反对的立场
3. 明确指出哪些证据会改变你的想法
4. 具体化——引用具体场景、数据或代码示例
不要只是同意他人。如果同意,请解释他们遗漏了哪些额外风险或细节。
`
}),
run_in_background: true
})
}
// 收集论点并构建论点图谱
const arguments = [];
for (const expert of getDynamicExperts(experts)) {
const argument = await collectStatement(expert.id);
const msgId = nextMsgId();
const msg = {
id: msgId,
from: expert.id,
type: "argument",
content: argument,
references: extractReferences(argument), // 解析引用的消息ID
timestamp: new Date().toISOString()
};
arguments.push(msg);
allMessages.push(msg);
// 构建论点图谱的边
for (const ref of msg.references) {
argumentGraph.push({
from: msgId,
to: ref.targetId,
relation: ref.type // "supports", "counters", "extends", "questions"
});
}
broadcastMessage(teamName, expert.id, argument, experts);
}
// >>> 进度报告:论证阶段 <<<
reportProgress(3, "专家论点",
arguments.map(a =>
`**${a.from}**: "${a.content.position}" — 引用: ${a.references.map(r => r.targetId).join(', ') || '无'}`
).join('\n'),
`${arguments.length}个论点已提交,包含${argumentGraph.length}个交叉引用。 ` +
`${argumentGraph.filter(e => e.relation === 'counters').length}个反论点, ` +
`${argumentGraph.filter(e => e.relation === 'supports').length}个支持论点。`
);
// ========== 步骤4:Contrarian压力测试 ==========
// Contrarian针对最强的共识,而非最弱的论点
const contrarianResponse = await Task({
team_name: teamName,
name: "contrarian",
subagent_type: "general-purpose",
prompt: `
你是Contrarian。
【讨论主题】
${roundTopic}
【目前所有论点】
${formatMessagesWithIds(allMessages)}
【论点图谱】
${JSON.stringify(argumentGraph, null, 2)}
【任务】
1. 识别大多数专家达成共识的点——这是你的主要目标
2. 挑战这个共识:它基于什么假设?如果这个假设不成立会怎样?
3. 找到支持共识的最弱证据
4. 提出一个共识会导致失败的具体场景
5. 如果已经存在真正的分歧,用新论点放大少数派立场
不要为了反对而反对。针对最危险的认知盲区。
挑战时请通过ID引用先前的消息。
`
});
const contrarianMsgId = nextMsgId();
allMessages.push({
id: contrarianMsgId,
from: "contrarian",
type: "stress_test",
content: contrarianResponse,
references: extractReferences(contrarianResponse),
timestamp: new Date().toISOString()
});
broadcastMessage(teamName, "contrarian", contrarianResponse, experts);
// >>> 进度报告:Contrarian压力测试 <<<
reportProgress(4, "Contrarian压力测试",
`Contrarian针对正在形成的共识,挑战了${extractReferences(contrarianResponse).length}个先前论点。`,
typeof contrarianResponse === 'string'
? contrarianResponse.substring(0, 200) + "..."
: JSON.stringify(contrarianResponse).substring(0, 200) + "..."
);
// ========== 步骤5:回应阶段 ==========
// 专家回应Contrarian——必须明确说明立场是否转变
for (const expert of getDynamicExperts(experts)) {
Task({
team_name: teamName,
name: expert.id,
subagent_type: "general-purpose",
prompt: buildExpertPrompt(expert, {
phase: "response",
topic: roundTopic,
allMessages: allMessages,
contrarianResponse: contrarianResponse,
contrarianMsgId: contrarianMsgId,
instruction: `
回应Contrarian的压力测试(${contrarianMsgId})。
你必须包含立场更新:
{
"positionShift": "none" | "minor" | "major",
"currentPosition": "你当前的立场",
"previousPosition": "本轮前你的立场(来自立场声明)",
"shiftReason": "具体是什么改变了你的想法(如果有的话)"
}
如果你的立场没有改变,请具体解释为什么Contrarian的论点不适用于你的情况。
`
}),
run_in_background: true
})
}
// 收集回应并跟踪立场转变
const responses = [];
const positionShifts = [];
for (const expert of getDynamicExperts(experts)) {
const response = await collectStatement(expert.id);
const msgId = nextMsgId();
responses.push({
id: msgId,
from: expert.id,
type: "response",
content: response,
references: extractReferences(response),
timestamp: new Date().toISOString()
});
allMessages.push(responses[responses.length - 1]);
// 跟踪立场转变
if (response.positionShift && response.positionShift !== "none") {
positionShifts.push({
type: "position_shift",
expert: expert.id,
from: response.previousPosition,
to: response.currentPosition,
trigger: contrarianMsgId,
reasoning: response.shiftReason
});
}
}
// >>> 进度报告:回应阶段与立场转变 <<<
reportProgress(5, "专家回应与立场转变",
responses.map(r =>
`**${r.from}**: 立场转变=${r.content.positionShift || '无'}` +
(r.content.positionShift !== '无' ? ` → "${r.content.currentPosition}"` : '')
).join('\n'),
positionShifts.length > 0
? `${positionShifts.length}次立场转变被检测到! ${positionShifts.map(s => `${s.expert}因${s.trigger}转变立场`).join('; ')}`
: `无立场转变——专家在Contrarian的挑战下坚持了自己的立场。`
);
// ========== 步骤6:跨领域视角(仅标准/深度模式) ==========
if (mode !== "lightweight") {
const crossDomainResponse = await Task({
team_name: teamName,
name: "cross-domain",
subagent_type: "general-purpose",
prompt: `
你是跨领域思考者。
【讨论主题】
${roundTopic}
【截至目前的讨论(带消息ID)】
${formatMessagesWithIds(allMessages)}
【本轮立场转变】
${JSON.stringify(positionShifts, null, 2)}
【任务】
1. 识别这场辩论中的潜在模式(而非表面主题)
2. 在完全不同的领域中找到解决过类似模式问题的案例
3. 详细解释类比:哪些部分对应,哪些不对应
4. 提出来自该类比领域的框架或原则
5. 诚实地说明类比的局限性
可考虑的领域:生物学、物理学、经济学、法学、军事战略、城市规划、博弈论、生态学。
引用你的类比所针对的具体消息ID。
`
});
const crossDomainMsgId = nextMsgId();
allMessages.push({
id: crossDomainMsgId,
from: "cross-domain",
type: "analogy",
content: crossDomainResponse,
references: extractReferences(crossDomainResponse),
timestamp: new Date().toISOString()
});
// >>> 进度报告:跨领域视角 <<<
reportProgress(6, "跨领域视角",
`跨领域思考者提供了来自其他领域的类比,引用了${extractReferences(crossDomainResponse).length}个先前消息。`,
typeof crossDomainResponse === 'string'
? crossDomainResponse.substring(0, 200) + "..."
: JSON.stringify(crossDomainResponse).substring(0, 200) + "..."
);
}
// ========== 步骤7:质量关卡与收敛检查 ==========
const qualityCheck = await Task({
team_name: teamName,
name: "moderator",
subagent_type: "general-purpose",
prompt: `
评估本轮讨论的质量并进行综合分析。
【所有消息】
${formatMessagesWithIds(allMessages)}
【论点图谱】
${JSON.stringify(argumentGraph, null, 2)}
【立场转变】
${JSON.stringify(positionShifts, null, 2)}
【质量关卡检查表】
每项按1-5分评分并解释:
1. 真正分歧:专家是否真正相互挑战,还是只是同意?
2. 证据质量:主张是否有具体内容(场景、数据、代码)支持?
3. 最强反驳:专家在反驳前是否准确呈现了对立观点?
4. 新颖见解:讨论是否产生了初始立场中没有的想法?
5. 立场演变:是否有专家基于论点改变了想法?
【综合任务】
{
"qualityScore": {
"genuineDisagreement": 1-5,
"evidenceQuality": 1-5,
"steelManning": 1-5,
"novelInsights": 1-5,
"positionEvolution": 1-5,
"overall": 1-5
},
"summary": "本轮总结(200-300字)",
"agreements": [{ "point": "...", "supporters": ["expert-ids"], "strength": "strong|moderate|weak" }],
"activeDisagreements": [{ "point": "...", "positions": [{"stance": "...", "advocates": ["expert-ids"]}] }],
"insights": [{ "insight": "...", "novelty": "high|medium|low", "source": "message-id" }],
"openQuestions": ["..."],
"positionShifts": [...],
"recommendation": "continue|deep-dive|different-angle|synthesize",
"recommendationReason": "为什么选择下一步"
}
如果整体质量<3分,请标记并说明问题所在(例如:"过于一致——重新运行并加强Contrarian的框架设计")。
`
});
// ========== 步骤8:记录 ==========
const roundRecord = {
roundId: roundNum,
topic: roundTopic,
mode: mode,
timestamp: new Date().toISOString(),
messages: allMessages,
argumentGraph: argumentGraph,
positionShifts: positionShifts,
synthesis: JSON.parse(qualityCheck),
metadata: {
messageCount: allMessages.length,
participants: [...new Set(allMessages.map(m => m.from))],
referenceCount: argumentGraph.length
}
};
// Historian记录(仅标准/深度模式)
if (mode !== "lightweight") {
await Task({
team_name: teamName,
name: "historian",
subagent_type: "general-purpose",
prompt: `
记录本轮讨论以用于论点图谱。
【本轮记录】
${JSON.stringify(roundRecord, null, 2)}
将以下内容保存到轮次文件:
1. 带ID和引用的完整消息历史
2. 论点图谱的边(谁挑战/支持了谁)
3. 带触发因素的立场转变
4. 质量评估
同时更新一个动态的“论点图谱”,展示多轮讨论中立场的演变。
`
});
}
Write(`~/.claude/discussions/${discussionId}/rounds/${String(roundNum).padStart(3, '0')}.json`, roundRecord)
// ========== 步骤9:确认下一步行动 ==========
const synthesis = roundRecord.synthesis;
const recommendation = synthesis.recommendation || "continue";
AskUserQuestion({
questions: [{
question: `第${roundNum}轮完成。\n\n` +
`**质量得分:** ${synthesis.qualityScore?.overall || "N/A"}/5\n` +
`**立场转变:** ${positionShifts.length}\n` +
`**推荐:** ${recommendation} — ${synthesis.recommendationReason || ""}\n\n` +
`你接下来想做什么?`,
header: "轮次完成",
options: [
{ label: "遵循推荐", description: `${recommendation}` },
{ label: "深入探讨", description: synthesis.activeDisagreements?.[0]?.point || "最具争议的主题" },
{ label: "换个角度", description: "探索不同的方面" },
{ label: "注入约束", description: "添加新的需求或假设" },
{ label: "综合阶段", description: "总结讨论内容" },
{ label: "暂停", description: "稍后恢复" }
],
multiSelect: false
}]
})
return roundRecord;
}
// 辅助函数:构建立场声明提示词
function buildPositionDeclarationPrompt(expert, topic) {
return `
你是"${expert.name}"。
【你的档案】
- 专业领域: ${expert.expertise.join(", ")}
- 思考风格: ${expert.thinkingStyle}
- 天然偏见: ${expert.bias}
- 决策错误的损失: ${expert.stakes}
- 已知盲区: ${expert.blindSpots?.join(", ") || "未声明"}
【讨论主题】
${topic}
【任务】
在听取他人意见前,声明你的初步立场。
输出格式:
{
"position": "你的立场(1-2句话)",
"confidence": 0.0-1.0,
"conditions": "此立场成立的假设条件",
"wouldChangeIf": "哪些证据会让你重新考虑",
"keyRisk": "如果采纳你的立场,最大的风险是什么"
}
诚实地表达你的置信度。低置信度是可以的——它表明团队需要深入挖掘的地方。
`;
}
// 辅助函数:广播消息
function broadcastMessage(teamName, fromId, message, experts) {
for (const expert of experts) {
if (expert.id !== fromId && expert.id !== "historian") {
Teammate({
operation: "write",
target_agent_id: expert.id,
value: JSON.stringify({
type: "message",
from: fromId,
content: message
})
})
}
}
}
// 辅助函数:从消息内容中提取引用
function extractReferences(content) {
// 从文本中解析"r1-msg-001"格式的引用
const refs = [];
const pattern = /r\d+-msg-\d{3}/g;
let match;
while ((match = pattern.exec(JSON.stringify(content))) !== null) {
refs.push({ targetId: match[0], type: "references" });
}
return refs;
}Phase 3: Synthesis
阶段3:综合分析
javascript
async function synthesizeDiscussion(discussionId) {
const teamName = `discussion-${discussionId}`;
const allRounds = loadAllRounds(discussionId);
const manifest = loadManifest(discussionId);
// Build cumulative argument graph
const fullArgumentGraph = allRounds.flatMap(r => r.argumentGraph || []);
const allPositionShifts = allRounds.flatMap(r => r.positionShifts || []);
// Historian synthesizes everything
const finalSynthesis = await Task({
team_name: teamName,
name: "historian",
subagent_type: "general-purpose",
prompt: `
You are the Historian. Synthesize the entire discussion.
【All Round Records】
${JSON.stringify(allRounds, null, 2)}
【Full Argument Graph】
${JSON.stringify(fullArgumentGraph, null, 2)}
【All Position Shifts】
${JSON.stringify(allPositionShifts, null, 2)}
【Original Problem Definition】
${JSON.stringify(manifest.problemDefinition, null, 2)}
【Synthesis Rules】
1. Every insight MUST be traceable to specific message IDs
2. Include a "minority report" for dissenting views that were outnumbered but not refuted
3. Distinguish between "resolved by argument" and "resolved by majority" — the latter is weaker
4. Rate confidence based on evidence quality, not on how many experts agreed
5. Open questions should include WHY they remain open (lack of evidence? fundamental uncertainty?)
【Output Format】
{
"executiveSummary": "Summary of the entire discussion (500-800 characters)",
"insights": [
{
"title": "Insight title",
"description": "Detailed description",
"confidence": "high/medium/low",
"confidenceReason": "Why this confidence level (evidence-based, not vote-based)",
"supportingEvidence": [{ "messageId": "r1-msg-003", "summary": "..." }],
"dissentingViews": [{ "messageId": "r2-msg-007", "summary": "...", "refuted": true/false }]
}
],
"agreements": [
{ "point": "Agreement point", "supporters": ["..."], "strength": "strong|moderate|weak" }
],
"minorityReport": [
{
"position": "Dissenting view",
"advocate": "expert-id",
"reason": "Why this was not adopted by majority",
"stillValid": true/false,
"note": "Why this deserves attention despite being minority"
}
],
"unresolvedDebates": [
{
"topic": "Point of contention",
"positions": [
{ "stance": "Position A", "advocates": ["..."], "arguments": ["..."] },
{ "stance": "Position B", "advocates": ["..."], "arguments": ["..."] }
],
"whyUnresolved": "Reason this couldn't be settled"
}
],
"positionEvolution": [
{
"expert": "expert-id",
"journey": ["Initial position", "After round 1", "Final position"],
"keyTurningPoints": ["message-ids that caused shifts"]
}
],
"openQuestions": [
{ "question": "...", "whyOpen": "...", "suggestedApproach": "..." }
],
"recommendations": [
{ "action": "...", "confidence": "high/medium/low", "risk": "...", "prerequisite": "..." }
],
"metaObservations": "Observations about the discussion process itself (quality, blind spots, what worked)"
}
`
});
// Save artifacts
const synthesis = JSON.parse(finalSynthesis);
Write(`~/.claude/discussions/${discussionId}/artifacts/synthesis.json`, synthesis)
Write(`~/.claude/discussions/${discussionId}/artifacts/synthesis.md`, formatSynthesisAsMarkdown(synthesis))
Write(`~/.claude/discussions/${discussionId}/artifacts/open-questions.md`, formatOpenQuestions(synthesis))
Write(`~/.claude/discussions/${discussionId}/artifacts/argument-graph.json`, fullArgumentGraph)
Write(`~/.claude/discussions/${discussionId}/artifacts/position-evolution.md`, formatPositionEvolution(synthesis))
return synthesis;
}javascript
async function synthesizeDiscussion(discussionId) {
const teamName = `discussion-${discussionId}`;
const allRounds = loadAllRounds(discussionId);
const manifest = loadManifest(discussionId);
// 构建累积论点图谱
const fullArgumentGraph = allRounds.flatMap(r => r.argumentGraph || []);
const allPositionShifts = allRounds.flatMap(r => r.positionShifts || []);
// Historian进行全面综合
const finalSynthesis = await Task({
team_name: teamName,
name: "historian",
subagent_type: "general-purpose",
prompt: `
你是Historian。综合整个讨论的内容。
【所有轮次记录】
${JSON.stringify(allRounds, null, 2)}
【完整论点图谱】
${JSON.stringify(fullArgumentGraph, null, 2)}
【所有立场转变】
${JSON.stringify(allPositionShifts, null, 2)}
【原始问题定义】
${JSON.stringify(manifest.problemDefinition, null, 2)}
【综合规则】
1. 每个见解必须可追溯到具体的消息ID
2. 包含“少数派报告”,记录被多数派否决但未被反驳的不同观点
3. 区分“通过论证解决”和“通过多数解决”——后者的可信度更低
4. 根据证据质量而非专家同意的数量来评估置信度
5. 未解决的问题应说明为什么仍未解决(缺乏证据?根本不确定性?)
【输出格式】
{
"executiveSummary": "整个讨论的总结(500-800字)",
"insights": [
{
"title": "见解标题",
"description": "详细描述",
"confidence": "high/medium/low",
"confidenceReason": "为什么是这个置信度(基于证据,而非投票)",
"supportingEvidence": [{ "messageId": "r1-msg-003", "summary": "..." }],
"dissentingViews": [{ "messageId": "r2-msg-007", "summary": "...", "refuted": true/false }]
}
],
"agreements": [
{ "point": "共识点", "supporters": ["..."], "strength": "strong|moderate|weak" }
],
"minorityReport": [
{
"position": "不同观点",
"advocate": "expert-id",
"reason": "为什么未被多数派采纳",
"stillValid": true/false,
"note": "为什么尽管是少数派仍值得关注"
}
],
"unresolvedDebates": [
{
"topic": "争议点",
"positions": [
{ "stance": "立场A", "advocates": ["..."], "arguments": ["..."] },
{ "stance": "立场B", "advocates": ["..."], "arguments": ["..."] }
],
"whyUnresolved": "为什么无法解决"
}
],
"positionEvolution": [
{
"expert": "expert-id",
"journey": ["初始立场", "第1轮后", "最终立场"],
"keyTurningPoints": ["导致转变的消息ID"]
}
],
"openQuestions": [
{ "question": "...", "whyOpen": "...", "suggestedApproach": "..." }
],
"recommendations": [
{ "action": "...", "confidence": "high/medium/low", "risk": "...", "prerequisite": "..." }
],
"metaObservations": "关于讨论过程的观察(质量、盲区、有效做法)"
}
`
});
// 保存产物
const synthesis = JSON.parse(finalSynthesis);
Write(`~/.claude/discussions/${discussionId}/artifacts/synthesis.json`, synthesis)
Write(`~/.claude/discussions/${discussionId}/artifacts/synthesis.md`, formatSynthesisAsMarkdown(synthesis))
Write(`~/.claude/discussions/${discussionId}/artifacts/open-questions.md`, formatOpenQuestions(synthesis))
Write(`~/.claude/discussions/${discussionId}/artifacts/argument-graph.json`, fullArgumentGraph)
Write(`~/.claude/discussions/${discussionId}/artifacts/position-evolution.md`, formatPositionEvolution(synthesis))
return synthesis;
}Phase 4: Checkpoint / Termination
阶段4:检查点 / 终止
javascript
async function checkpointDiscussion(discussionId) {
const teamName = `discussion-${discussionId}`;
// 1. Generate resume context (richer than before)
const resumeContext = await Task({
team_name: teamName,
name: "historian",
subagent_type: "general-purpose",
prompt: `
Generate the context needed to resume this discussion later.
Items to include:
1. Discussion theme and purpose (1 paragraph)
2. Key progress so far (bullet points)
3. Current topics and state
4. Summary of each participant's CURRENT position (after shifts)
5. Active disagreements and their state
6. Issues to address next time
7. Quality trajectory (improving or declining over rounds?)
Length: 1500-3000 characters
Format: Markdown
`
});
Write(`~/.claude/discussions/${discussionId}/context/summary.md`, resumeContext)
// 2. Update manifest
updateManifest(discussionId, {
lastActive: new Date().toISOString(),
status: "paused",
currentPhase: "checkpoint"
})
// 3. Shutdown all workers
const experts = loadPersonas(discussionId);
for (const expert of experts) {
Teammate({
operation: "requestShutdown",
target_agent_id: expert.id
})
}
// 4. Cleanup
Teammate({ operation: "cleanup" })
}
async function resumeDiscussion(discussionId) {
// 1. Load manifest
const manifest = Read(`~/.claude/discussions/${discussionId}/manifest.json`)
// 2. Recreate team
Teammate({
operation: "spawnTeam",
team_name: manifest.team_name
})
// 3. Load resume context
const context = Read(`~/.claude/discussions/${discussionId}/context/summary.md`)
// 4. Load last round for position continuity
const lastRound = loadLatestRound(discussionId);
// 5. Update manifest
updateManifest(discussionId, {
lastActive: new Date().toISOString(),
status: "active"
})
// 6. Notify Moderator of resumption (with richer context)
const reopening = await Task({
team_name: manifest.team_name,
name: "moderator",
subagent_type: "general-purpose",
prompt: `
Resuming the discussion.
【Previous Context】
${context}
【Last Round Synthesis】
${JSON.stringify(lastRound?.synthesis, null, 2)}
【Participants and Their Last Known Positions】
${manifest.personas.map(p => `- ${p.name}`).join('\n')}
【Tension Map】
${JSON.stringify(manifest.tensionMap, null, 2)}
Review the previous state. Specifically:
1. What was the most productive tension in the last session?
2. What open question is most important to address now?
3. Has anything in the tension map been resolved?
Propose the next round's topic and framing.
`
})
return reopening;
}javascript
async function checkpointDiscussion(discussionId) {
const teamName = `discussion-${discussionId}`;
// 1. 生成恢复上下文(比之前更丰富)
const resumeContext = await Task({
team_name: teamName,
name: "historian",
subagent_type: "general-purpose",
prompt: `
生成稍后恢复讨论所需的上下文。
需包含的内容:
1. 讨论主题和目的(1段)
2. 截至目前的关键进展(项目符号)
3. 当前主题和状态
4. 每位参与者的当前立场总结(转变后)
5. 未解决的分歧及其状态
6. 下次需要解决的问题
7. 质量趋势(多轮讨论中是提升还是下降?)
长度:1500-3000字
格式:Markdown
`
});
Write(`~/.claude/discussions/${discussionId}/context/summary.md`, resumeContext)
// 2. 更新manifest
updateManifest(discussionId, {
lastActive: new Date().toISOString(),
status: "paused",
currentPhase: "checkpoint"
})
// 3. 关闭所有工作进程
const experts = loadPersonas(discussionId);
for (const expert of experts) {
Teammate({
operation: "requestShutdown",
target_agent_id: expert.id
})
}
// 4. 清理
Teammate({ operation: "cleanup" })
}
async function resumeDiscussion(discussionId) {
// 1. 加载manifest
const manifest = Read(`~/.claude/discussions/${discussionId}/manifest.json`)
// 2. 重新创建团队
Teammate({
operation: "spawnTeam",
team_name: manifest.team_name
})
// 3. 加载恢复上下文
const context = Read(`~/.claude/discussions/${discussionId}/context/summary.md`)
// 4. 加载最后一轮以保持立场连续性
const lastRound = loadLatestRound(discussionId);
// 5. 更新manifest
updateManifest(discussionId, {
lastActive: new Date().toISOString(),
status: "active"
})
// 6. 通知Moderator恢复讨论(带更丰富的上下文)
const reopening = await Task({
team_name: manifest.team_name,
name: "moderator",
subagent_type: "general-purpose",
prompt: `
恢复讨论。
【先前上下文】
${context}
【最后一轮综合】
${JSON.stringify(lastRound?.synthesis, null, 2)}
【参与者及其最新立场】
${manifest.personas.map(p => `- ${p.name}`).join('\n')}
【张力映射】
${JSON.stringify(manifest.tensionMap, null, 2)}
回顾先前状态。特别关注:
1. 上一轮中最有效的张力是什么?
2. 现在最需要解决的未解决问题是什么?
3. 张力映射中的任何内容是否已解决?
提出下一轮的主题和框架。
`
})
return reopening;
}Data Structure
数据结构
~/.claude/discussions/{discussion-id}/
├── manifest.json # Metadata, personas, tension map, mode
├── progress.md # Live progress log (appended after each step)
├── personas/ # Expert definitions (with stakes and blind spots)
│ ├── expert-1.json
│ ├── contrarian.json
│ └── ...
├── rounds/ # Complete record of each round
│ ├── 001.json # Messages with IDs, argument graph, position shifts
│ ├── 002.json
│ └── ...
├── artifacts/ # Outputs
│ ├── synthesis.json # Structured synthesis with minority report
│ ├── synthesis.md # Markdown format
│ ├── open-questions.md # Unresolved questions with reasons
│ ├── argument-graph.json # Full argument graph across all rounds
│ └── position-evolution.md # How each expert's position changed
└── context/
└── summary.md # Resume context~/.claude/discussions/{discussion-id}/
├── manifest.json # 元数据、角色、张力映射、模式
├── progress.md # 实时进度日志(每个步骤后追加)
├── personas/ # 专家定义(包含利益相关和盲区)
│ ├── expert-1.json
│ ├── contrarian.json
│ └── ...
├── rounds/ # 每轮的完整记录
│ ├── 001.json # 带ID的消息、论点图谱、立场转变
│ ├── 002.json
│ └── ...
├── artifacts/ # 输出产物
│ ├── synthesis.json # 带少数派报告的结构化综合
│ ├── synthesis.md # Markdown格式
│ ├── open-questions.md # 未解决问题及原因
│ ├── argument-graph.json # 多轮完整论点图谱
│ └── position-evolution.md # 每位专家的立场变化
└── context/
└── summary.md # 恢复上下文Round JSON Structure (Message-based with References)
轮次JSON结构(带引用的消息式结构)
json
{
"roundId": 2,
"topic": "Microservice Transaction Management",
"mode": "standard",
"timestamp": "2026-01-29T10:30:00Z",
"messages": [
{
"id": "r2-msg-001",
"from": "database-expert",
"type": "position_declaration",
"content": {
"position": "I recommend the Saga pattern with orchestration",
"confidence": 0.7,
"conditions": "Assuming < 10 services",
"wouldChangeIf": "Orchestration overhead exceeds 30% of request latency",
"keyRisk": "Compensating transaction complexity grows quadratically"
},
"timestamp": "2026-01-29T10:30:00Z"
},
{
"id": "r2-msg-005",
"from": "contrarian",
"type": "stress_test",
"content": "Both experts agree on Saga, but neither addresses the case where...",
"references": [
{ "targetId": "r2-msg-001", "type": "counters" },
{ "targetId": "r2-msg-002", "type": "counters" }
],
"timestamp": "2026-01-29T10:33:00Z"
},
{
"id": "r2-msg-007",
"from": "database-expert",
"type": "response",
"content": {
"response": "The Contrarian raises a valid point about...",
"positionShift": "minor",
"currentPosition": "Saga with orchestration, but with circuit breakers for > 5 services",
"previousPosition": "Saga with orchestration",
"shiftReason": "Hadn't considered cascade failure in the compensation chain"
},
"references": [
{ "targetId": "r2-msg-005", "type": "responds_to" }
],
"timestamp": "2026-01-29T10:35:00Z"
}
],
"argumentGraph": [
{ "from": "r2-msg-005", "to": "r2-msg-001", "relation": "counters" },
{ "from": "r2-msg-005", "to": "r2-msg-002", "relation": "counters" },
{ "from": "r2-msg-007", "to": "r2-msg-005", "relation": "responds_to" }
],
"positionShifts": [
{
"expert": "database-expert",
"from": "Saga with orchestration",
"to": "Saga with orchestration + circuit breakers for > 5 services",
"trigger": "r2-msg-005",
"reasoning": "Cascade failure risk in compensation chain"
}
],
"synthesis": {
"qualityScore": {
"genuineDisagreement": 4,
"evidenceQuality": 3,
"steelManning": 4,
"novelInsights": 3,
"positionEvolution": 4,
"overall": 4
},
"summary": "Saga pattern consensus emerged but was stress-tested; circuit breaker addition shows genuine position evolution",
"agreements": [
{ "point": "Distributed 2PC should be avoided", "supporters": ["database-expert", "api-designer"], "strength": "strong" }
],
"activeDisagreements": [
{ "point": "Choreography vs Orchestration", "positions": [
{ "stance": "Orchestration", "advocates": ["database-expert"] },
{ "stance": "Choreography", "advocates": ["api-designer"] }
]}
],
"insights": [
{ "insight": "Compensation chain failure is a real risk at scale", "novelty": "high", "source": "r2-msg-005" }
],
"openQuestions": ["What is the maximum practical service count for orchestration-based Saga?"],
"recommendation": "deep-dive",
"recommendationReason": "Choreography vs Orchestration is unresolved and has significant implementation implications"
}
}json
{
"roundId": 2,
"topic": "微服务事务管理",
"mode": "standard",
"timestamp": "2026-01-29T10:30:00Z",
"messages": [
{
"id": "r2-msg-001",
"from": "database-expert",
"type": "position_declaration",
"content": {
"position": "我推荐带编排的Saga模式",
"confidence": 0.7,
"conditions": "假设服务数量<10个",
"wouldChangeIf": "编排开销超过请求延迟的30%",
"keyRisk": "补偿事务的复杂度呈二次增长"
},
"timestamp": "2026-01-29T10:30:00Z"
},
{
"id": "r2-msg-005",
"from": "contrarian",
"type": "stress_test",
"content": "两位专家都同意Saga模式,但都未解决...的情况",
"references": [
{ "targetId": "r2-msg-001", "type": "counters" },
{ "targetId": "r2-msg-002", "type": "counters" }
],
"timestamp": "2026-01-29T10:33:00Z"
},
{
"id": "r2-msg-007",
"from": "database-expert",
"type": "response",
"content": {
"response": "Contrarian提出了一个关于...的有效观点",
"positionShift": "minor",
"currentPosition": "带编排的Saga模式,但服务数量>5时添加断路器",
"previousPosition": "带编排的Saga模式",
"shiftReason": "未考虑补偿链中的级联故障"
},
"references": [
{ "targetId": "r2-msg-005", "type": "responds_to" }
],
"timestamp": "2026-01-29T10:35:00Z"
}
],
"argumentGraph": [
{ "from": "r2-msg-005", "to": "r2-msg-001", "relation": "counters" },
{ "from": "r2-msg-005", "to": "r2-msg-002", "relation": "counters" },
{ "from": "r2-msg-007", "to": "r2-msg-005", "relation": "responds_to" }
],
"positionShifts": [
{
"expert": "database-expert",
"from": "带编排的Saga模式",
"to": "带编排的Saga模式 + 服务数量>5时添加断路器",
"trigger": "r2-msg-005",
"reasoning": "补偿链中的级联故障风险"
}
],
"synthesis": {
"qualityScore": {
"genuineDisagreement": 4,
"evidenceQuality": 3,
"steelManning": 4,
"novelInsights": 3,
"positionEvolution": 4,
"overall": 4
},
"summary": "Saga模式的共识已形成但经过了压力测试;断路器的添加表明立场真正发生了演变",
"agreements": [
{ "point": "应避免分布式2PC", "supporters": ["database-expert", "api-designer"], "strength": "strong" }
],
"activeDisagreements": [
{ "point": "编排式 vs choreography式", "positions": [
{ "stance": "编排式", "advocates": ["database-expert"] },
{ "stance": "Choreography式", "advocates": ["api-designer"] }
]}
],
"insights": [
{ "insight": "补偿链故障在大规模场景下是真实风险", "novelty": "high", "source": "r2-msg-005" }
],
"openQuestions": ["基于编排的Saga模式的最大实用服务数量是多少?"],
"recommendation": "deep-dive",
"recommendationReason": "编排式 vs Choreography式仍未解决,且对实现有重大影响"
}
}Prompt Templates
提示词模板
Dynamic Expert Prompt
动态专家提示词
javascript
function buildExpertPrompt(expert, options) {
return `
You are participating in the discussion as "${expert.name}".
【Your Profile】
- Areas of expertise: ${expert.expertise.join(", ")}
- Thinking style: ${expert.thinkingStyle}
- Natural bias: ${expert.bias}
- Response tendency: ${expert.replyTendency}
- What you stand to lose from a bad decision: ${expert.stakes}
- Known blind spots: ${expert.blindSpots?.join(", ") || "None declared"}
【Current Phase】
${options.phase}
【Topic】
${options.topic}
【Position Declarations】
${options.positionDeclarations ? formatPositionDeclarations(options.positionDeclarations) : "(No declarations yet)"}
【Previous Statements (with message IDs)】
${options.allMessages ? formatMessagesWithIds(options.allMessages) : options.previousStatements ? formatStatements(options.previousStatements) : "(First statement)"}
${options.contrarianResponse ? `
【Contrarian's Stress Test (${options.contrarianMsgId})】
${options.contrarianResponse}
` : ""}
【Relevant Tensions】
${options.tensionMap ? options.tensionMap
.filter(t => t.between.includes(expert.id))
.map(t => `You and ${t.between.find(e => e !== expert.id)} disagree on: ${t.axis}`)
.join('\n') : "(None)"}
【Task】
${options.instruction}
【Referencing Rules】
- When responding to someone's point, reference their message ID: "Regarding r1-msg-003..."
- When supporting a claim, cite the specific message
- When disagreeing, first steel-man the position you're countering
【Output Format】
{
"position": "Your stance on this topic (1-2 sentences)",
"reasoning": "Detailed analysis with specific evidence",
"proposals": ["Concrete proposals"],
"references": [
{ "targetId": "message-id", "relation": "supports|counters|extends|questions", "comment": "Why" }
],
"counterpoints": ["Rebuttals or supplements to others (with message IDs)"],
"questions": ["Additional questions to consider"],
"codeOrDiagrams": "Code examples or diagrams (optional)"
}
`;
}javascript
function buildExpertPrompt(expert, options) {
return `
你以"${expert.name}"的身份参与讨论。
【你的档案】
- 专业领域: ${expert.expertise.join(", ")}
- 思考风格: ${expert.thinkingStyle}
- 天然偏见: ${expert.bias}
- 回应倾向: ${expert.replyTendency}
- 决策错误的损失: ${expert.stakes}
- 已知盲区: ${expert.blindSpots?.join(", ") || "未声明"}
【当前阶段】
${options.phase}
【讨论主题】
${options.topic}
【立场声明】
${options.positionDeclarations ? formatPositionDeclarations(options.positionDeclarations) : "(尚无声明)"}
【先前陈述(带消息ID)】
${options.allMessages ? formatMessagesWithIds(options.allMessages) : options.previousStatements ? formatStatements(options.previousStatements) : "(首次陈述)"}
${options.contrarianResponse ? `
【Contrarian的压力测试(${options.contrarianMsgId})】
${options.contrarianResponse}
` : ""}
【相关张力】
${options.tensionMap ? options.tensionMap
.filter(t => t.between.includes(expert.id))
.map(t => `你与${t.between.find(e => e !== expert.id)}在以下方面存在分歧: ${t.axis}`)
.join('\n') : "(无)"}
【任务】
${options.instruction}
【引用规则】
- 回应某人的观点时,引用他们的消息ID: "关于r1-msg-003..."
- 支持主张时,引用具体消息
- 反对时,先以最强形式呈现你要反驳的立场
【输出格式】
{
"position": "你对该主题的立场(1-2句话)",
"reasoning": "带具体证据的详细分析",
"proposals": ["具体建议"],
"references": [
{ "targetId": "message-id", "relation": "supports|counters|extends|questions", "comment": "原因" }
],
"counterpoints": ["对他人观点的反驳或补充(带消息ID)"],
"questions": ["需要考虑的额外问题"],
"codeOrDiagrams": "代码示例或图表(可选)"
}
`;
}Important Notes
重要注意事项
Cost Awareness
成本意识
- Team-based approach has higher overhead than direct launch
- Use lightweight mode for quick checks; reserve deep mode for high-stakes decisions
- Approximate costs per mode:
- Lightweight: 3-5 Task calls/round
- Standard: 5-8 Task calls/round
- Deep: 8-12 Task calls/round
- 基于团队的方法比直接启动开销更高
- 快速检查使用轻量模式;高风险决策保留深度模式
- 各模式的大致成本:
- 轻量模式: 每轮3-5次Task调用
- 标准模式: 每轮5-8次Task调用
- 深度模式: 每轮8-12次Task调用
Live Progress Reporting
实时进度报告
- After each step in a round, the orchestrator MUST output a brief summary to the user
- This includes: who said what (1-2 sentences), position shifts detected, key takeaways
- The same information is appended to in the discussion directory
progress.md - Users can also check from another terminal
~/.claude/discussions/{id}/progress.md - Progress output should be concise (3-5 lines per step) — not a full dump of the expert's output
- The goal is to let the user follow along and decide whether to intervene early
- 在每轮的每个步骤完成后,编排器必须向用户输出简要摘要
- 内容包括:谁提出了什么(1-2句话)、检测到的立场转变、关键要点
- 相同信息会追加到讨论目录中的
progress.md - 用户也可以从其他终端查看
~/.claude/discussions/{id}/progress.md - 进度输出应简洁(每个步骤3-5行)——不要输出专家的完整输出
- 目的是让用户能够跟进进展并决定是否提前干预
Quality Over Quantity
质量优先于数量
- A 2-round discussion with genuine disagreement beats a 5-round discussion with polite agreement
- Monitor the quality score — if it drops below 3, the discussion structure needs adjustment
- Position shifts are the strongest signal of a productive discussion
- 2轮带有真正分歧的讨论胜过5轮礼貌性同意的讨论
- 监控质量得分——如果低于3分,讨论结构需要调整
- 立场转变是讨论富有成效的最强信号
Leveraging Messaging
利用消息机制
- Use to share statements
Teammate({ operation: "write" }) - Experts can respond based on received messages
- Enables true dialogue
- 使用来分享陈述
Teammate({ operation: "write" }) - 专家可以根据收到的消息做出回应
- 实现真正的对话
Importance of Cleanup
清理的重要性
- Always →
requestShutdownwhen discussion endscleanup - Leaving teams running wastes resources
- 讨论结束时始终执行→
requestShutdowncleanup - 让团队持续运行会浪费资源
Evidence & Traceability
证据与可追溯性
- Save all statements with unique message IDs
- Every claim should reference the message it responds to
- The argument graph enables post-hoc analysis of how conclusions were reached
- Position evolution tracking shows which arguments were actually persuasive
- 保存所有陈述并分配唯一的消息ID
- 每个主张都应引用它所回应的消息
- 论点图谱支持对结论如何达成的事后分析
- 立场演变跟踪显示哪些论点真正具有说服力
Anti-Patterns to Avoid
需避免的反模式
- "I agree, and also..." — If all experts agree, the Contrarian isn't doing their job
- Generic analogies — Cross-Domain should cite specific cases, not vague similarities
- Unfalsifiable positions — Every position must have a condition
wouldChangeIf - Authority-based arguments — "Best practice says..." is not evidence. Show WHY it's best practice
- Premature synthesis — Don't synthesize before real disagreements have been explored
- “我同意,而且...”——如果所有专家都同意,说明Contrarian没有履行职责
- 泛泛的类比——跨领域角色应引用具体案例,而非模糊的相似性
- 无法证伪的立场——每个立场必须有条件
wouldChangeIf - 基于权威的论点——“最佳实践说...”不是证据。要说明为什么它是最佳实践
- 过早综合——在真正的分歧被探索之前不要进行综合
Usage Example
使用示例
User: /swarm-discussion "Microservice Transaction Management"
System:
1. Analyze topic → define experts with tension map
2. Show experts:
- Distributed Systems Designer (stakes: system reliability)
vs. API Designer (stakes: developer experience) ← designed tension
- Database Expert (stakes: data consistency)
vs. Operations Engineer (stakes: operational simplicity) ← designed tension
- Contrarian, Cross-Domain (fixed)
3. User confirms → "Start" (Standard mode)
4. Round 1:
- All experts: Position declarations (parallel, BEFORE seeing others)
- Moderator: Frame based on actual disagreements
- Experts: Argue with citations (parallel)
- Contrarian: Target the strongest consensus
- Experts: Respond with position shift tracking
- Cross-Domain: Analogies addressing specific messages
- Moderator: Quality gate + convergence check
5. Quality score: 4/5, recommendation: "deep-dive on choreography vs orchestration"
6. User: "Follow recommendation"
7. Round 2, 3, ...
8. Synthesis phase → artifacts/ (includes minority report, argument graph, position evolution)
9. Checkpoint → cleanup
User: /swarm-discussion --mode lightweight "Should we use GraphQL or REST for this API?"
→ Quick 1-2 round discussion with 2 experts + Moderator + Contrarian用户: /swarm-discussion "微服务事务管理"
系统:
1. 分析主题 → 定义带张力映射的专家
2. 展示专家:
- 分布式系统设计师(利益相关:系统可靠性)
vs. API设计师(利益相关:开发者体验) ← 设计的张力
- 数据库专家(利益相关:数据一致性)
vs. 运维工程师(利益相关:运维简洁性) ← 设计的张力
- Contrarian、跨领域角色(固定)
3. 用户确认 → "开始"(标准模式)
4. 第1轮:
- 所有专家: 立场声明(并行,在查看他人立场前)
- Moderator: 基于实际分歧构建框架
- 专家: 带引用的论证(并行)
- Contrarian: 挑战最强的共识
- 专家: 回应并跟踪立场转变
- 跨领域角色: 针对具体消息的类比
- Moderator: 质量关卡 + 收敛检查
5. 质量得分: 4/5,推荐: "深入探讨编排式 vs Choreography式"
6. 用户: "遵循推荐"
7. 第2、3轮...
8. 综合阶段 → artifacts/(包含少数派报告、论点图谱、立场演变)
9. 检查点 → 清理
用户: /swarm-discussion --mode lightweight "我们应该为这个API使用GraphQL还是REST?"
→ 快速1-2轮讨论,包含2位专家 + Moderator + Contrarian