AgentSkillsCN

swarm-discussion

针对尚未解决的问题,探索性讨论模式。 效仿Staff+工程师的思考方式:“当没有明确答案时,不妨通过多元视角的碰撞,直面那些尚未被察觉的盲点。” 真正的多智能体对话,让专家们通过团队协作与消息传递架构,直接展开深度交流。

SKILL.md
--- frontmatter
name: swarm-discussion
description: |
  Exploratory discussion pattern for unsolved problems.
  Replicate the thinking of Staff+ engineers: "When there's no clear answer, expose blind spots by confronting diverse perspectives."
  True multi-agent discussions where experts directly engage with each other through team-based + messaging architecture.

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
  • Statement → Rebuttal → Counter-rebuttal: True discussion, not just parallel statements
  • Dynamic Expert Generation: Automatically define appropriate experts based on the topic
  • Complete Evidence Preservation: Save all messages
  • User Participation: Use AskUserQuestion for direction confirmation

Architecture

code
┌─────────────────────────────────────────────────────────────────┐
│                  Discussion Team                                 │
│                  team_name: discussion-{id}                      │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐   │
│  │ Expert 1   │ │ Expert 2   │ │ Contrarian │ │Cross-Domain│   │
│  │            │◄──────────────►│            │◄─────────────►│   │
│  │  inbox ◄───┼──── messages ──┼──► inbox   │  messages    │   │
│  └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘   │
│        │              │              │              │            │
│        └──────────────┴──────┬───────┴──────────────┘            │
│                              │                                   │
│                    ┌─────────▼─────────┐                         │
│                    │    Moderator      │                         │
│                    │  - Present topics │                         │
│                    │  - Facilitate     │                         │
│                    │  - Convergence    │                         │
│                    └─────────┬─────────┘                         │
│                              │                                   │
│                    ┌─────────▼─────────┐                         │
│                    │    Historian      │                         │
│                    │  - Record         │                         │
│                    │  - Synthesize     │                         │
│                    └───────────────────┘                         │
└─────────────────────────────────────────────────────────────────┘

Role Design

Fixed Roles

RoleResponsibilityCharacteristic
ModeratorFacilitate discussion, present topics, determine convergenceDiscussion facilitator
HistorianRecord statements, synthesize, generate summariesRecord keeper
ContrarianQuestion assumptions, present counterargumentsAlways seeks opposing views
Cross-DomainProvide analogies from other fieldsBrings alternative perspectives

Dynamically Generated Roles (3-4 based on topic)

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"
}

Discussion Flow

Phase 1: Initialization

javascript
// 1. Generate discussion ID
const discussionId = slugify(topic);  // e.g., "microservice-transaction"

// 2. Create team
Teammate({
  operation: "spawnTeam",
  team_name: `discussion-${discussionId}`
})

// 3. Create directory structure
Bash({
  command: `mkdir -p ~/.claude/discussions/${discussionId}/{personas,rounds,artifacts,context}`
})

// 4. Analyze topic and define experts (executed by Orchestrator)
const dynamicExperts = analyzeTopicAndDefineExperts(topic);
// → [{ id, name, expertise, thinkingStyle, bias, replyTendency }, ...]

// 5. Add fixed roles
const fixedRoles = [
  { 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 = [...dynamicExperts, ...fixedRoles];

// 6. Confirm expert composition with user
AskUserQuestion({
  questions: [{
    question: `Start discussion with the following experts?\n${allExperts.map(e => `- ${e.name}`).join('\n')}`,
    header: "Confirm Experts",
    options: [
      { label: "Start (Recommended)", description: "Begin with this composition" },
      { label: "Modify", description: "Add or change experts" }
    ],
    multiSelect: false
  }]
})

// 7. Save manifest.json
Write(`~/.claude/discussions/${discussionId}/manifest.json`, {
  id: discussionId,
  title: topic,
  created: new Date().toISOString(),
  status: "active",
  currentPhase: "initial",
  currentRound: 0,
  team_name: `discussion-${discussionId}`,
  personas: allExperts
})

// 8. Save each expert definition
for (const expert of allExperts) {
  Write(`~/.claude/discussions/${discussionId}/personas/${expert.id}.json`, expert)
}

// 9. Create discussion task
TaskCreate({
  subject: `Discussion: ${topic}`,
  description: `Experts: ${allExperts.map(e => e.name).join(", ")}`,
  activeForm: "Preparing discussion team"
})

Phase 2: Round Execution (Statement → Rebuttal → Convergence)

javascript
async function executeRound(discussionId, roundNum, roundTopic) {
  const teamName = `discussion-${discussionId}`;
  const experts = loadPersonas(discussionId);

  // 1. Create round task
  TaskCreate({
    subject: `Round ${roundNum}: ${roundTopic}`,
    description: "Experts are discussing",
    activeForm: `Round ${roundNum} in progress`
  })
  TaskUpdate({ taskId: roundTaskId, status: "in_progress" })

  // 2. Array to store all messages
  const allMessages = [];

  // ========== Step 1: Initial Statement Phase ==========
  // Moderator presents the topic
  const moderatorOpening = await Task({
    team_name: teamName,
    name: "moderator",
    subagent_type: "general-purpose",
    prompt: `
You are the Moderator. Please start the discussion on the following topic.

【Topic】
${roundTopic}

【Previous Discussion】
${previousRoundsSummary || "(New discussion)"}

【Task】
1. Clearly present the topic
2. Suggest 2-3 discussion angles
3. Include questions for each expert
    `
  });

  allMessages.push({
    from: "moderator",
    type: "opening",
    content: moderatorOpening,
    timestamp: new Date().toISOString()
  });

  // Send Moderator's opening message to all experts
  for (const expert of experts.filter(e => e.id !== "moderator" && e.id !== "historian")) {
    Teammate({
      operation: "write",
      target_agent_id: expert.id,
      value: JSON.stringify({
        type: "round_start",
        topic: roundTopic,
        moderator_opening: moderatorOpening
      })
    })
  }

  // Dynamic experts make initial statements (parallel)
  const initialStatements = [];
  for (const expert of experts.filter(e => !["moderator", "historian", "contrarian", "cross-domain"].includes(e.id))) {
    Task({
      team_name: teamName,
      name: expert.id,
      subagent_type: "general-purpose",
      prompt: buildExpertPrompt(expert, {
        phase: "initial",
        topic: roundTopic,
        moderatorOpening: moderatorOpening,
        instruction: "Share your perspective on this topic from your area of expertise."
      }),
      run_in_background: true
    })
  }

  // Collect statements
  for (const expert of dynamicExperts) {
    const statement = await collectStatement(expert.id);
    initialStatements.push({
      from: expert.id,
      type: "initial_statement",
      content: statement,
      timestamp: new Date().toISOString()
    });
    allMessages.push(initialStatements[initialStatements.length - 1]);

    // Share statement with other experts
    broadcastMessage(teamName, expert.id, statement, experts);
  }

  // ========== Step 2: Rebuttal Phase ==========
  // Contrarian provides counterarguments
  const contrarianResponse = await Task({
    team_name: teamName,
    name: "contrarian",
    subagent_type: "general-purpose",
    prompt: `
You are the Contrarian.

【Topic】
${roundTopic}

【Previous Statements】
${formatStatements(initialStatements)}

【Task】
1. Question the assumptions of each statement
2. Point out overlooked risks or exceptions
3. Challenge from a "Is that really true?" perspective
4. Raise constructive questions
    `
  });

  allMessages.push({
    from: "contrarian",
    type: "counterpoint",
    content: contrarianResponse,
    timestamp: new Date().toISOString()
  });

  // Share Contrarian's rebuttal with everyone
  broadcastMessage(teamName, "contrarian", contrarianResponse, experts);

  // ========== Step 3: Counter-Rebuttal Phase ==========
  // Dynamic experts respond to Contrarian (parallel)
  for (const expert of dynamicExperts) {
    Task({
      team_name: teamName,
      name: expert.id,
      subagent_type: "general-purpose",
      prompt: buildExpertPrompt(expert, {
        phase: "rebuttal",
        topic: roundTopic,
        previousStatements: initialStatements,
        contrarianResponse: contrarianResponse,
        instruction: "Respond to Contrarian's rebuttal - either counter or accept. Make your position clear."
      }),
      run_in_background: true
    })
  }

  // Collect rebuttals
  const rebuttals = [];
  for (const expert of dynamicExperts) {
    const rebuttal = await collectStatement(expert.id);
    rebuttals.push({
      from: expert.id,
      type: "rebuttal",
      content: rebuttal,
      timestamp: new Date().toISOString()
    });
    allMessages.push(rebuttals[rebuttals.length - 1]);
  }

  // ========== Step 4: Cross-Domain Perspective ==========
  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】
${formatStatements(allMessages)}

【Task】
1. Draw analogies from other fields (biology, economics, physics, etc.)
2. Show how similar problems have been solved in other domains
3. Propose new frameworks or perspectives
    `
  });

  allMessages.push({
    from: "cross-domain",
    type: "analogy",
    content: crossDomainResponse,
    timestamp: new Date().toISOString()
  });

  // ========== Step 5: Convergence ==========
  // Moderator synthesizes the discussion
  const synthesis = await Task({
    team_name: teamName,
    name: "moderator",
    subagent_type: "general-purpose",
    prompt: `
Synthesize this round's discussion.

【All Statements】
${formatStatements(allMessages)}

【Output Format】
{
  "summary": "Summary of this round (about 200 characters)",
  "agreements": ["Agreement 1", "Agreement 2"],
  "disagreements": ["Disagreement 1", "Disagreement 2"],
  "insights": ["Discovered insight 1", "Insight 2"],
  "openQuestions": ["Unresolved question 1", "Question 2"],
  "nextTopicSuggestions": ["Next topic candidate 1", "Candidate 2"]
}
    `
  });

  // ========== Step 6: Record ==========
  // Historian creates complete record
  const roundRecord = {
    roundId: roundNum,
    topic: roundTopic,
    timestamp: new Date().toISOString(),
    messages: allMessages,  // Save all messages
    synthesis: JSON.parse(synthesis),
    metadata: {
      messageCount: allMessages.length,
      participants: [...new Set(allMessages.map(m => m.from))]
    }
  };

  Write(`~/.claude/discussions/${discussionId}/rounds/${String(roundNum).padStart(3, '0')}.json`, roundRecord)

  // Complete task
  TaskUpdate({ taskId: roundTaskId, status: "completed" })

  // ========== Step 7: Confirm Next Action ==========
  AskUserQuestion({
    questions: [{
      question: "What would you like to do next?",
      header: "Progress",
      options: [
        { label: "Deep dive", description: synthesis.nextTopicSuggestions[0] || "Most important topic" },
        { label: "Different topic", description: "Select another topic" },
        { label: "Another round", description: "Continue on same topic" },
        { label: "Synthesis phase", description: "Summarize the discussion" },
        { label: "Pause", description: "Resume later" }
      ],
      multiSelect: false
    }]
  })

  return roundRecord;
}

// Helper function: 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
        })
      })
    }
  }
}

Phase 3: Synthesis

javascript
async function synthesizeDiscussion(discussionId) {
  const teamName = `discussion-${discussionId}`;
  const allRounds = loadAllRounds(discussionId);

  // 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)}

【Output Format】
{
  "executiveSummary": "Summary of the entire discussion (about 500 characters)",
  "insights": [
    {
      "title": "Insight title",
      "description": "Detailed description",
      "confidence": "high/medium/low",
      "supportingEvidence": ["Supporting statements"],
      "dissentingViews": ["Dissenting views if any"]
    }
  ],
  "agreements": [
    { "point": "Agreement point", "supporters": ["Supporters"] }
  ],
  "unresolvedDebates": [
    {
      "topic": "Point of contention",
      "positions": [
        { "stance": "Position A", "advocates": ["Advocates"], "arguments": ["Arguments"] },
        { "stance": "Position B", "advocates": ["Advocates"], "arguments": ["Arguments"] }
      ]
    }
  ],
  "openQuestions": ["Unresolved questions"],
  "recommendations": ["Recommended actions"]
}
    `
  });

  // 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))

  return synthesis;
}

Phase 4: Checkpoint / Termination

javascript
async function checkpointDiscussion(discussionId) {
  const teamName = `discussion-${discussionId}`;

  // 1. Generate resume context
  const resumeContext = await Task({
    team_name: teamName,
    name: "historian",
    subagent_type: "general-purpose",
    prompt: `
Generate the minimum 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 participants' main positions
5. Issues to address next time

Length: 1000-2000 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. Update manifest
  updateManifest(discussionId, {
    lastActive: new Date().toISOString(),
    status: "active"
  })

  // 5. Notify Moderator of resumption
  const reopening = await Task({
    team_name: manifest.team_name,
    name: "moderator",
    subagent_type: "general-purpose",
    prompt: `
Resuming the discussion.

【Previous Context】
${context}

【Participants】
${manifest.personas.map(p => `- ${p.name}`).join('\n')}

Review the previous state and suggest next steps.
    `
  })

  return reopening;
}

Data Structure

code
~/.claude/discussions/{discussion-id}/
├── manifest.json           # Metadata
├── personas/               # Expert definitions
│   ├── expert-1.json
│   ├── contrarian.json
│   └── ...
├── rounds/                 # Complete record of each round
│   ├── 001.json            # Contains all messages
│   ├── 002.json
│   └── ...
├── artifacts/              # Outputs
│   ├── synthesis.json      # Structured synthesis
│   ├── synthesis.md        # Markdown format
│   └── open-questions.md   # Unresolved questions
└── context/
    └── summary.md          # Resume context

Round JSON Structure (Message-based)

json
{
  "roundId": 2,
  "topic": "Microservice Transaction Management",
  "timestamp": "2026-01-29T10:30:00Z",
  "messages": [
    {
      "from": "moderator",
      "type": "opening",
      "content": "In this round...",
      "timestamp": "2026-01-29T10:30:00Z"
    },
    {
      "from": "database-expert",
      "type": "initial_statement",
      "content": {
        "position": "I recommend the Saga pattern",
        "reasoning": "Distributed transactions are...",
        "proposals": ["Choreography-based Saga", "Orchestration-based Saga"],
        "codeExample": "..."
      },
      "timestamp": "2026-01-29T10:31:00Z"
    },
    {
      "from": "contrarian",
      "type": "counterpoint",
      "content": "The Saga pattern has the problem of compensating transaction complexity...",
      "timestamp": "2026-01-29T10:33:00Z"
    },
    {
      "from": "database-expert",
      "type": "rebuttal",
      "content": "True it's complex, but with proper design...",
      "timestamp": "2026-01-29T10:35:00Z"
    },
    {
      "from": "cross-domain",
      "type": "analogy",
      "content": "This is similar to settlement systems in finance...",
      "timestamp": "2026-01-29T10:37:00Z"
    }
  ],
  "synthesis": {
    "summary": "General agreement on adopting Saga pattern, but compensating transaction design remains a challenge",
    "agreements": ["Distributed transactions should be avoided"],
    "disagreements": ["Choreography vs Orchestration"],
    "insights": ["Financial settlement patterns are a useful reference"],
    "openQuestions": ["Is automatic generation of compensating transactions possible?"]
  }
}

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}

【Current Phase】
${options.phase}

【Topic】
${options.topic}

【Previous Statements】
${options.previousStatements ? formatStatements(options.previousStatements) : "(First statement)"}

${options.contrarianResponse ? `
【Contrarian's Rebuttal】
${options.contrarianResponse}
` : ""}

【Task】
${options.instruction}

【Output Format】
{
  "position": "Your stance on this topic (1-2 sentences)",
  "reasoning": "Detailed analysis",
  "proposals": ["Concrete proposals"],
  "counterpoints": ["Rebuttals or supplements to others"],
  "questions": ["Additional questions to consider"],
  "codeOrDiagrams": "Code examples or diagrams (optional)"
}
  `;
}

Important Notes

Cost Awareness

  • Team-based approach has higher overhead than direct launch
  • 5-10 Task/Teammate calls per round
  • Use only when deep discussion is needed

Leveraging Messaging

  • Use Teammate({ operation: "write" }) to share statements
  • Experts can respond based on received messages
  • Enables true dialogue

Importance of Cleanup

  • Always requestShutdowncleanup when discussion ends
  • Leaving teams running wastes resources

Importance of Evidence

  • Save all statements chronologically in the messages array
  • Enables complete reconstruction of discussion flow later

Usage Example

code
User: /swarm-discussion "Microservice Transaction Management"

System:
1. Create team: discussion-microservice-transaction
2. Define experts:
   - Distributed Systems Designer
   - Database Expert
   - Operations Engineer
   - Contrarian (fixed)
   - Cross-Domain (fixed)
3. Confirm with user → "Start"
4. Round 1:
   - Moderator: Present topic
   - Experts: Initial statements (parallel)
   - Contrarian: Rebuttal
   - Experts: Counter-rebuttals
   - Cross-Domain: Alternative perspective
   - Moderator: Convergence/synthesis
5. Confirm next action with user
6. Round 2, 3, ...
7. Synthesis phase → artifacts/synthesis.md
8. Checkpoint → cleanup