Ischca

swarm-discussion

by @Ischca in Tools
0
0
# Install this skill:
npx skills add Ischca/swarm-discussion-skill --skill "swarm-discussion"

Install specific skill from multi-skill repository

# Description

|

# SKILL.md


name: swarm-discussion
description: |
未解決問題の探索的議論パターン。
「正解がないときは、多様な視点をぶつけて盲点を炙り出す」Staff+エンジニアの思考を再現。
チームベース + メッセージングで、専門家同士が直接対話する「真のマルチエージェント議論」を実現。


swarm-discussion

「複数の専門家が議論するように問題を突き詰める」パターン

Staff+エンジニアの思考パターン

「正解がないときは、多様な視点をぶつけて盲点を炙り出す」

未解決問題や前例のない課題に対して、複数の専門家がチームとして参加し、
メッセージングで相互に反論・補足し合う「真の議論」を行う。

特徴

  • チームベースアーキテクチャ: Teammate API でチームを構成
  • メッセージングによる対話: 専門家同士が直接やり取り
  • 発言→反論→再反論: 単なる並列発言ではなく、真の議論
  • 動的専門家生成: テーマに応じて適切な専門家を定義
  • 完全な証跡保存: 全メッセージを保存
  • ユーザー参加型: 方向性確認にAskUserQuestionを活用

アーキテクチャ

┌─────────────────────────────────────────────────────────────────┐
│                  Discussion Team                                 │
│                  team_name: discussion-{id}                      │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐   │
│  │ Expert 1   │ │ Expert 2   │ │ Contrarian │ │Cross-Domain│   │
│  │            │◄──────────────►│            │◄─────────────►│   │
│  │  inbox ◄───┼──── messages ──┼──► inbox   │  messages    │   │
│  └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘   │
│        │              │              │              │            │
│        └──────────────┴──────┬───────┴──────────────┘            │
│                              │                                   │
│                    ┌─────────▼─────────┐                         │
│                    │    Moderator      │                         │
│                    │  - 論点提示       │                         │
│                    │  - 議論調整       │                         │
│                    │  - 収束判断       │                         │
│                    └─────────┬─────────┘                         │
│                              │                                   │
│                    ┌─────────▼─────────┐                         │
│                    │    Historian      │                         │
│                    │  - 発言記録       │                         │
│                    │  - 統合・要約     │                         │
│                    └───────────────────┘                         │
└─────────────────────────────────────────────────────────────────┘

ロール設計

固定ロール

ロール 役割 特徴
Moderator 議論進行、論点提示、収束判断 議論の司会者
Historian 発言記録、統合、要約生成 記録係
Contrarian 前提を疑う、反論を提示 常に反対意見を探す
Cross-Domain 異分野からのアナロジー 別視点を持ち込む

動的生成ロール(テーマに応じて3-4名)

テーマを分析し、適切な専門家を定義。各専門家は以下の属性を持つ:

{
  "id": "database-expert",
  "name": "データベース専門家",
  "expertise": ["RDB", "NoSQL", "分散DB"],
  "thinkingStyle": "pragmatic",
  "bias": "実用性とパフォーマンスを重視",
  "replyTendency": "具体的な実装例を示す"
}

議論フロー

Phase 1: 初期化

// 1. 議論IDを生成
const discussionId = slugify(topic);  // e.g., "microservice-transaction"

// 2. チームを作成
Teammate({
  operation: "spawnTeam",
  team_name: `discussion-${discussionId}`
})

// 3. ディレクトリ構造を作成
Bash({
  command: `mkdir -p ~/.claude/discussions/${discussionId}/{personas,rounds,artifacts,context}`
})

// 4. テーマを分析して専門家を定義(Orchestratorが実行)
const dynamicExperts = analyzeTopicAndDefineExperts(topic);
// → [{ id, name, expertise, thinkingStyle, bias, replyTendency }, ...]

// 5. 固定ロールを追加
const fixedRoles = [
  { id: "moderator", name: "Moderator", role: "議論進行" },
  { id: "historian", name: "Historian", role: "記録係" },
  { id: "contrarian", name: "Contrarian", role: "反論者" },
  { id: "cross-domain", name: "Cross-Domain", role: "異分野視点" }
];

const allExperts = [...dynamicExperts, ...fixedRoles];

// 6. ユーザーに専門家構成を確認
AskUserQuestion({
  questions: [{
    question: `以下の専門家で議論を開始しますか?\n${allExperts.map(e => `- ${e.name}`).join('\n')}`,
    header: "専門家確認",
    options: [
      { label: "開始する (推奨)", description: "この構成で議論開始" },
      { label: "変更したい", description: "専門家を追加・変更" }
    ],
    multiSelect: false
  }]
})

// 7. 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. 各専門家の定義を保存
for (const expert of allExperts) {
  Write(`~/.claude/discussions/${discussionId}/personas/${expert.id}.json`, expert)
}

// 9. 議論タスクを作成
TaskCreate({
  subject: `Discussion: ${topic}`,
  description: `専門家: ${allExperts.map(e => e.name).join(", ")}`,
  activeForm: "議論チームを準備中"
})

Phase 2: ラウンド実行(発言→反論→収束)

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

  // 1. ラウンドタスクを作成
  TaskCreate({
    subject: `Round ${roundNum}: ${roundTopic}`,
    description: "専門家が議論中",
    activeForm: `Round ${roundNum} 議論中`
  })
  TaskUpdate({ taskId: roundTaskId, status: "in_progress" })

  // 2. 全メッセージを格納する配列
  const allMessages = [];

  // ========== Step 1: 初期発言フェーズ ==========
  // Moderatorが論点を提示
  const moderatorOpening = await Task({
    team_name: teamName,
    name: "moderator",
    subagent_type: "general-purpose",
    prompt: `
あなたはModeratorです。以下の論点について議論を開始してください。

【論点】
${roundTopic}

【これまでの議論】
${previousRoundsSummary || "(新規議論)"}

【タスク】
1. 論点を明確に提示してください
2. 議論の観点を2-3個提案してください
3. 各専門家への問いかけを含めてください
    `
  });

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

  // 全専門家にModeratorの開始メッセージを送信
  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
      })
    })
  }

  // 動的専門家が初期発言(並列)
  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: "この論点について、あなたの専門性から見解を述べてください。"
      }),
      run_in_background: true
    })
  }

  // 発言を収集
  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]);

    // 他の専門家に発言を共有
    broadcastMessage(teamName, expert.id, statement, experts);
  }

  // ========== Step 2: 反論フェーズ ==========
  // Contrarianが反論
  const contrarianResponse = await Task({
    team_name: teamName,
    name: "contrarian",
    subagent_type: "general-purpose",
    prompt: `
あなたはContrarianです。

【論点】
${roundTopic}

【これまでの発言】
${formatStatements(initialStatements)}

【タスク】
1. 各発言の前提を疑ってください
2. 見落とされているリスクや例外を指摘してください
3. 「本当にそうか?」という観点から反論してください
4. 建設的な疑問を投げかけてください
    `
  });

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

  // Contrarianの反論を全員に共有
  broadcastMessage(teamName, "contrarian", contrarianResponse, experts);

  // ========== Step 3: 再反論・補足フェーズ ==========
  // 動的専門家がContrarianに応答(並列)
  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: "Contrarianの反論に対して、反論または受け入れてください。立場を明確にしてください。"
      }),
      run_in_background: true
    })
  }

  // 再反論を収集
  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: 異分野視点 ==========
  const crossDomainResponse = await Task({
    team_name: teamName,
    name: "cross-domain",
    subagent_type: "general-purpose",
    prompt: `
あなたはCross-Domain Thinkerです。

【論点】
${roundTopic}

【これまでの議論】
${formatStatements(allMessages)}

【タスク】
1. この問題を別の分野(生物学、経済学、物理学など)に類推してください
2. 他分野で類似の問題がどう解決されているか示してください
3. 新しいフレームワークや視点を提案してください
    `
  });

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

  // ========== Step 5: 収束 ==========
  // Moderatorが議論を整理
  const synthesis = await Task({
    team_name: teamName,
    name: "moderator",
    subagent_type: "general-purpose",
    prompt: `
このラウンドの議論を整理してください。

【全発言】
${formatStatements(allMessages)}

【出力形式】
{
  "summary": "このラウンドの要約(200字程度)",
  "agreements": ["合意点1", "合意点2"],
  "disagreements": ["対立点1", "対立点2"],
  "insights": ["発見された洞察1", "洞察2"],
  "openQuestions": ["未解決の問い1", "問い2"],
  "nextTopicSuggestions": ["次の論点候補1", "候補2"]
}
    `
  });

  // ========== Step 6: 記録 ==========
  // Historianが完全な記録を作成
  const roundRecord = {
    roundId: roundNum,
    topic: roundTopic,
    timestamp: new Date().toISOString(),
    messages: allMessages,  // 全メッセージを保存
    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)

  // タスク完了
  TaskUpdate({ taskId: roundTaskId, status: "completed" })

  // ========== Step 7: 次のアクションを確認 ==========
  AskUserQuestion({
    questions: [{
      question: "次にどうしますか?",
      header: "進行",
      options: [
        { label: "深堀りする", description: synthesis.nextTopicSuggestions[0] || "最重要論点" },
        { label: "別の論点へ", description: "他の論点を選択" },
        { label: "もう1ラウンド議論", description: "同じ論点で継続" },
        { label: "統合フェーズへ", description: "議論をまとめる" },
        { label: "一時中断", description: "後で再開" }
      ],
      multiSelect: false
    }]
  })

  return roundRecord;
}

// ヘルパー関数: メッセージをブロードキャスト
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)

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

  // Historianが全体を統合
  const finalSynthesis = await Task({
    team_name: teamName,
    name: "historian",
    subagent_type: "general-purpose",
    prompt: `
あなたはHistorianです。議論全体を統合してください。

【全ラウンドの記録】
${JSON.stringify(allRounds, null, 2)}

【出力形式】
{
  "executiveSummary": "議論全体の要約(500字程度)",
  "insights": [
    {
      "title": "洞察のタイトル",
      "description": "詳細な説明",
      "confidence": "high/medium/low",
      "supportingEvidence": ["根拠となる発言"],
      "dissentingViews": ["反対意見があれば"]
    }
  ],
  "agreements": [
    { "point": "合意点", "supporters": ["賛成者"] }
  ],
  "unresolvedDebates": [
    {
      "topic": "対立点",
      "positions": [
        { "stance": "立場A", "advocates": ["主張者"], "arguments": ["論拠"] },
        { "stance": "立場B", "advocates": ["主張者"], "arguments": ["論拠"] }
      ]
    }
  ],
  "openQuestions": ["未解決の問い"],
  "recommendations": ["推奨アクション"]
}
    `
  });

  // 成果物を保存
  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: チェックポイント / 終了

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. 次回取り組むべき課題

長さ: 1000-2000文字程度
形式: 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. manifest を更新
  updateManifest(discussionId, {
    lastActive: new Date().toISOString(),
    status: "active"
  })

  // 5. Moderatorに再開を通知
  const reopening = await Task({
    team_name: manifest.team_name,
    name: "moderator",
    subagent_type: "general-purpose",
    prompt: `
議論を再開します。

【前回までのコンテキスト】
${context}

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

前回の状態を確認し、次のステップを提案してください。
    `
  })

  return reopening;
}

データ構造

~/.claude/discussions/{discussion-id}/
├── manifest.json           # メタデータ
├── personas/               # 専門家定義
│   ├── expert-1.json
│   ├── contrarian.json
│   └── ...
├── rounds/                 # 各ラウンドの完全な記録
│   ├── 001.json            # 全メッセージを含む
│   ├── 002.json
│   └── ...
├── artifacts/              # 成果物
│   ├── synthesis.json      # 構造化された統合
│   ├── synthesis.md        # Markdown形式
│   └── open-questions.md   # 未解決の問い
└── context/
    └── summary.md          # 再開用コンテキスト

ラウンドJSONの構造(メッセージベース)

{
  "roundId": 2,
  "topic": "マイクロサービスのトランザクション管理",
  "timestamp": "2026-01-29T10:30:00Z",
  "messages": [
    {
      "from": "moderator",
      "type": "opening",
      "content": "本ラウンドでは...",
      "timestamp": "2026-01-29T10:30:00Z"
    },
    {
      "from": "database-expert",
      "type": "initial_statement",
      "content": {
        "position": "Sagaパターンを推奨する",
        "reasoning": "分散トランザクションは...",
        "proposals": ["Choreography型Saga", "Orchestration型Saga"],
        "codeExample": "..."
      },
      "timestamp": "2026-01-29T10:31:00Z"
    },
    {
      "from": "contrarian",
      "type": "counterpoint",
      "content": "Sagaパターンには補償トランザクションの複雑さという問題が...",
      "timestamp": "2026-01-29T10:33:00Z"
    },
    {
      "from": "database-expert",
      "type": "rebuttal",
      "content": "確かに複雑だが、適切な設計により...",
      "timestamp": "2026-01-29T10:35:00Z"
    },
    {
      "from": "cross-domain",
      "type": "analogy",
      "content": "これは金融の決済システムにおける...",
      "timestamp": "2026-01-29T10:37:00Z"
    }
  ],
  "synthesis": {
    "summary": "Sagaパターンの採用で概ね合意、ただし補償トランザクションの設計が課題",
    "agreements": ["分散トランザクションは避けるべき"],
    "disagreements": ["Choreography vs Orchestration"],
    "insights": ["金融システムの決済パターンが参考になる"],
    "openQuestions": ["補償トランザクションの自動生成は可能か?"]
  }
}

プロンプトテンプレート

動的専門家プロンプト

function buildExpertPrompt(expert, options) {
  return `
あなたは「${expert.name}」として議論に参加しています。

【あなたのプロフィール】
- 専門領域: ${expert.expertise.join(", ")}
- 思考スタイル: ${expert.thinkingStyle}
- 自然なバイアス: ${expert.bias}
- 回答傾向: ${expert.replyTendency}

【現在のフェーズ】
${options.phase}

【論点】
${options.topic}

【これまでの発言】
${options.previousStatements ? formatStatements(options.previousStatements) : "(最初の発言)"}

${options.contrarianResponse ? `
【Contrarianからの反論】
${options.contrarianResponse}
` : ""}

【タスク】
${options.instruction}

【出力形式】
{
  "position": "この論点に対するあなたの立場(1-2文)",
  "reasoning": "詳細な考察",
  "proposals": ["具体的な提案"],
  "counterpoints": ["他者への反論や補足"],
  "questions": ["追加で検討すべき問い"],
  "codeOrDiagrams": "コード例や図(オプション)"
}
  `;
}

注意事項

コスト意識

  • チームベースは直接起動よりオーバーヘッドが大きい
  • 1ラウンドあたり 5-10 回の Task/Teammate 呼び出し
  • 深い議論が必要な場合のみ使用

メッセージングの活用

  • Teammate({ operation: "write" }) で発言を共有
  • 専門家は受信したメッセージを踏まえて反論可能
  • 真の対話が実現

クリーンアップの重要性

  • 議論終了時は必ず requestShutdowncleanup
  • チームを放置するとリソースが残る

証跡の重要性

  • messages 配列に全発言を時系列で保存
  • 後から議論の流れを完全に再現可能

使用例

ユーザー: /swarm-discussion "マイクロサービスのトランザクション管理"

システム:
1. チーム作成: discussion-microservice-transaction
2. 専門家定義:
   - 分散システム設計者
   - データベース専門家
   - 運用エンジニア
   - Contrarian(固定)
   - Cross-Domain(固定)
3. ユーザーに確認 → 「開始する」
4. Round 1:
   - Moderator: 論点を提示
   - 専門家: 初期発言(並列)
   - Contrarian: 反論
   - 専門家: 再反論
   - Cross-Domain: 異分野視点
   - Moderator: 収束・整理
5. ユーザーに次のアクションを確認
6. Round 2, 3, ...
7. 統合フェーズ → artifacts/synthesis.md
8. チェックポイント → cleanup

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.