council について
councilは、orca orchestrationを通じて段階的なLLMパネルを実行するエージェントスキルです。匿名評価、議長による統合、決定論的な記録と版管理されたHTMLレポートを備えています。
主な機能
- 013段階のパネルワークフロー
- 02匿名の相互評価
- 03決定論的な集計と異論提示
- 04JSONとMarkdownの記録
- 05オフラインの版管理HTMLレポート
活用シーン
- 01複数モデルで高リスクの質問を検討
- 02著者を伏せて回答を比較
- 03評価順位の監査記録を保持
- 04パネル結果をHTMLレポート化
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rheinmir/ setup --skill councilインストール後、Claude Code で/councilを入力して読み込まれたか確認します。
詳細
スキル:council
🧭 各 seat のバックエンド(安価なモデルか Claude)を選び、複数の seat を並行して実行する(1 seat あたり 1 worktree — 1 フォルダーで複数の opencode を実行しない)場合は、orca-dispatch-reference を参照してください(唯一の信頼できる情報源)。
Andrej Karpathy の llm-council
(https://github.com/karpathy/llm-council) の3ステージ — Stage 1「First
Opinions」、Stage 2「Review」(匿名化された相互順位付け)、Stage 3「Final Response」
(chairman)— を orca オーケストレーションに接続した、決定論的なハーネスです。
内容
目的と背景
- 目的: Karpathy 方式の3ステージ LLM 評議会を orca オーケストレーション上で実行します — N 個の seat が独立して回答し、匿名で相互評価し、chairman が統合します — 決定論的な transcript と必須の HTML レポート(Stage 4)も備えています。
- 利用する場面: 1つのモデルの回答だけではリスクがあり、パネルでの評価と、誰が何を評価したかの監査証跡が必要な難しい質問に使います。匿名化により、自分の回答を優遇するバイアスを取り除きます。単純な質問にすばやく答える場合は、モデルを1つだけ使ってください。呼び出し方:「評議会を実行」「llm-council」「複数モデルのパネル」「これらの回答を匿名で相互評価」「アンサンブル+chairman」、または
/council。 - 対象外: 1つの回答で済む単純な質問には使いません。
council.pyはモデルを呼び出しません。seat に割り当てるモデルの選択は行いません(これはアダプターharness/council.config.yamlの役割です)。レポートに transcript 以外の新たな判断を加えることもありません。
メンタルモデル
役割分担:
harness/scripts/council.pyは決定論的なプロトコルを担い、モデルを呼び出すことはありません。匿名化(作成者を除去し、安定した sha256 順で A/B/C を割り当てる)、平均順位による集計、異論の提示、アンカーガード(シードに基づく審査員ごとの提示順 —Math.randomは使いません)、および json+md transcript を処理します。- orca オーケストレーション はモデルによる生成を担います。各 seat の回答、各審査員の順位付け、chairman による統合を生成します。他のマルチエージェント・ウェーブと同様に、これらをディスパッチします(
orca-workflow、orchestrationを参照)。 harness/council.config.yamlは唯一のアダプターです(verified: false)。各 seat を埋めるモデル、審査員モデル、chairman を指定します。すべての値には# ASSUMPTION (not verified)が付いています。エンジンがこれらの値によって処理を分岐することはなく、transcript に記録するだけです。この1つのファイルを編集して評議会を確定します。
question → Stage 1 answers.json → Stage 2a blind packet (A/B/C + presentation order) → Stage 2b judges.json → Stage 2c transcript (mean-rank, dissent, chairman_brief) → Stage 3 chairman_synthesis → Stage 4 HTML report versioned
入力と出力の仕様
| フィールド | 必須? | 意味 | |
|---|---|---|---|
| 入力 | 質問 | はい | すべての seat に同じ質問を使います。レポートに表示するには --question を指定します |
| 入力 | harness/council.config.yaml | はい | seats / judges / chairman(verified: false) |
| 入力 | roster persona(--case / --profile / --personas) | いいえ | Stage 1 のプロンプトに追加する視点 |
| 入力 | --seed N | いいえ | アンカーガードのシードです。anchor_seed を上書きします |
| 出力 | answers.json · judges.json | はい | [{"id","author","text"}] · [{"judge","ranking":[...]}] |
| 出力 | scratchpad/council-<slug>/council.packet.{json,md} + council.transcript.{json,md} | はい | ブラインドパケット、合意、勝者、異論、chairman_brief、chairman_synthesis |
| 出力 | llmwiki/html/council/council-report-NNN-seed<seed>.html | はい(必須) | バージョン管理されたレポート。上書きされません。latest.html がポインターになります |
ルールと機能
- RULE-01 (MUST): 言語(必須): すべての seat/judge/chairman は、完全な声調記号付きのベトナム語で回答する必要があります。この文をすべての Stage-1/Stage-2/Stage-3 プロンプトに挿入してください。
- RULE-02 (MUST): 実行結果は常に
scratchpad/council-<slug>/の下に出力します。run/直下やリポジトリルートのフォルダーには出力しないでください。 - RULE-03 (MUST): ガードとして使うのは除外ではなく盲検化です。judge に見えるのは、各自の提示順に従った A/B/C のラベルだけです。
- RULE-04 (MUST): Roster には常に少なくとも1組の対立するペアを設定します。mean-rank が同点にならないよう、人数は奇数(3/5)にします。
- RULE-05 (MUST): Stage-4 の HTML は常にレンダリングします。レンダラーのエラーは WARN にとどめ、
rankコマンドやtranscript.{json,md}を決して失敗させません。 - RULE-06 (MUST):
council.pyはモデルを呼び出しません。エンジンは設定値に応じて分岐せず、設定値は transcript に記録するだけです。 - 機能:オーケストレーション層を通じたモデル生成のディスパッチ(seat/judge/chairman)、プロトコルのローカルでの決定論的計算、transcript と HTML のファイル出力、レポート用のネットワーク通信/CDN 不使用。
失敗時の境界
council.py selftestが終了コード 0 を返さない、またはorca status --jsonに実行中のランタイムが表示されない場合 → blocked。council を実行しないでください。- Seat の回答に声調記号がない場合 → レポートにも声調記号がなくなります(忠実にレンダリングされます)→ RULE-01 を再度伝え、その seat を再実行してください。
- Judges が不足している場合 →
rankは盲検パケットを出力して停止します(partial、Stage 2b 待ち)。 - HTML レンダラーのエラー → WARN。transcript は出力されます(Stage 4 は partial。
renderを再実行してください)。 - Roster に対立するペアがない場合 → stderr に警告します。case/persona の入力ミスには、最も近い候補を提案し、無言で失敗することはありません。
方法
メインワークフロー
| Step | Type | Inputs | Action | Outputs/exit | Failure/next |
|---|---|---|---|---|---|
| W01 | deterministic | repo, runtime | 前提条件:council.py selftest、orca status --json、config に seats/judges/chairman が設定されていること | 条件を満たす | 不足 → blocked |
| W02 | effect | 質問(+レンズ) | Stage 1 — seat ごとに worker を1つディスパッチし、answers.json を収集 | answers.json | seat のエラー/声調記号なし → seat を再実行 |
| W03 | deterministic | answers.json | Stage 2a — council.py prepare | 盲検パケット | — |
| W04 | effect | packet | Stage 2b — 提示順に従った盲検回答を使って judge をディスパッチし、judges.json を収集 | judges.json | — |
| W05 | deterministic | answers + judges | Stage 2c — council.py rank(Stage-4 HTML も自動で書き込み) | transcript + report | レンダリングエラー → WARN、B02 |
| W06 | effect | chairman_brief | Stage 3 — chairman をディスパッチし、chairman_synthesis を transcript に貼り付け | transcript が完成 | — |
| W07 | deterministic | transcript | Stage 4 — レポートに synthesis を含めるため、council.py render <transcript.json> を実行 | 新しいバージョンの report | エラー → WARN、transcript はそのまま |
各ステップの詳細(W01–W07 の正本):
前提条件
python3 harness/scripts/council.py selftestが終了コード 0 を返します(エンジンが正常です)。orca status --jsonに実行中のランタイムが表示され、オーケストレーションが有効になっています。harness/council.config.yamlに Seats/judges/chairman が設定されています。
プロトコル(各ステージを orca のディスパッチに対応付け)
Stage 1 — 最初の意見(オーケストレーションが生成)
council.config.yaml の seat ごとに worker を1つディスパッチし、全 seat に同じ質問を渡します。
言語(必須): すべての seat/judge/chairman は、完全な声調記号付きのベトナム語 で回答する必要があります(正しい綴りで、声調記号とサーカムフレックスをすべて付けます)。声調記号のない ベトナム語(ASCII)を絶対に書かないでください。
council.pyは入力テキストを そのままレンダリングします(ensure_ascii=False、正規化なし)。seat の回答に声調記号がなければ、レポート にも声調記号がありません。この文をすべての Stage-1/Stage-2/Stage-3 プロンプトに挿入してください。
orca orchestration task-create --spec "Answer: <question>" --json
orca orchestration dispatch --task <task_id> --to <seat_handle> --inject --json
orca orchestration check --wait --types worker_done --timeout-ms 300000 --json
回答を answers.json — [{"id","author","text"}, ...] にまとめます。author は seat id(実際の識別情報。次の段階で削除されます)です。
ステージ 2a — ブラインドパケット(council.py は決定論的です)
python3 harness/scripts/council.py prepare answers.json --config harness/council.config.yaml --out scratchpad/council-<slug>/
<slug> = この実行の短い名前(例:release-gate)。必ず scratchpad/
配下に置きます(リポジトリごとの慣例に従い、gitignore 対象です)。run/ 直下や
リポジトリルートのフォルダーには置かないでください。こうした場所に置くと、クリーンアップ
されない未追跡ファイルが散らかります(教訓 170726。過去のセッションでこの例を
文字どおりコピーした結果、リポジトリルートに run-council*/ ディレクトリが 6 つ
残っていました)。scratchpad/council-<slug>/council.packet.{json,md} に、作成者を
除いたうえで A/B/C としてラベルを付け直した回答と、アンカーガードによる各審査員の
提示順を書き込みます。位置バイアスを相殺するため、各審査員には対応する行の順番で
回答を提示します。
ステージ 2b — レビュー(オーケストレーションで生成)
council.config.yaml にある各審査員に、その審査員の提示順でブラインド回答を
送ります。ラベルを最良のものから順に並べて返すよう依頼します。
結果を judges.json に収集します — [{"judge","ranking":["B","A","C"]}, ...]。
ガードとなるのは除外ではなく、ブラインドであることです。審査員が参加者の一人であっても、 自分の回答を見分けられなければ、えこひいきはできません。
ステージ 2c — 集計(council.py は決定論的です)
python3 harness/scripts/council.py rank answers.json --judges judges.json --config harness/council.config.yaml --out scratchpad/council-<slug>/
scratchpad/council-<slug>/council.transcript.{json,md} に、平均順位による合意、
優勝回答、異論テーブル(最も意見が分かれた回答)、chairman_brief を書き込みます。
ステージ 3 — 最終回答(オーケストレーションで生成)
トランスクリプトの chairman_brief(合意順+解決すべき異論点)を議長に送ります。
その統合結果が最終回答です。記録用に、これをトランスクリプトの
chairman_synthesis に貼り付けてから、council.py render <transcript.json> を実行し、
統合結果を表示したステージ 4 の HTML を再生成します(rank 実行時に自動生成される
レポートでは、rank が回答と審査員の結果のみから再構築するため、統合結果は空です)。
ステージ 4 — HTML レポート(必須。council.py 内でオフライン描画)
必ず描画します — フラグは不要で、外部スキルにも依存しません。 rank が
成功するたびに、render_report_html(t, personas)(council.py 内に実装)が
バージョン付きの .html ファイルを 1 つ出力します —
llmwiki/html/council/council-report-NNN-seed<seed>.html
(NNN は増加し、上書きはしません → 実行ごとに変更されない記録を 1 つ作成)と、
便利なポインターとして latest.html(gitignore 対象。差分の発生を回避)を出力します。
CDN は使用しません(システムフォントとインライン SVG のファビコン/粒状テクスチャを使用)
→ オフライン対応です。docs-site-macos との結合もありません。入力は直前に構築した
トランスクリプト(t)のみです → 新しい情報を作り出すことはなく、各 seat の文字列は
その場で html.escape に渡されます(HTML インジェクション対策)。描画全体は
try/except で囲みます。レンダラーのエラーは WARN のみで、rank コマンドや
transcript.{json,md} が失敗することは決してありません(Taleb の
ブラスト半径ガード)。委員の名前と視点は council.personas.yaml から取得します。
質問は --question が渡された場合に表示します(空の場合は、プレースホルダーを
表示する代わりに、レポートから質問の行を非表示にします)。
ページには、次の順序で正確に 3 つのセクションがあります。
- 評議会の意見。 各 seat にカードを 1 枚表示します(枠の色は
sha256(author)で決まり、 合意順位とメダルに従って並べます)。回答の(1)(2)(3)はリスト形式に自動整形されます。 データ元:t["answers"]+t["aggregate"]。 - 非公開投票(ブラインド投票)。 匿名の A/B/C ラベルを使用した投票テーブルです。
審査員ごとに 1 行を設け、ラベルによる順位とアンカーガードの提示順を表示します。
A/B/C と作成者の対応は、セクションの最後でのみ公開します。
データ元:
t["judge_rankings"]+t["anchor_guard"]。 - 最終ダッシュボード。 KPI(優勝回答/最も意見が分かれた回答/合意)、
平均順位による合意テーブルを表示します。また、
chairman_synthesisがトランスクリプトに 貼り付けられている場合は、目立つように表示します(rank による再構築は回答と審査員の 結果のみを元にするため、議長が記入するまではこのフィールドは空です。その場合、 統合結果のブロックは自動的に非表示になります)。 データ元:t["winner"]/t["most_contested"]/t["aggregate"]。
すべての数値は、決定論的に生成されたトランスクリプトから取得するため、レポートは 表示レイヤーにすぎず、新たな判断を加えることはありません。同じトランスクリプトなら、 同じ HTML が生成されます。
ブランチ
| ID | 種類 | ガード | 動作 | スキップ/失敗 | 再合流 |
|---|---|---|---|---|---|
| B01 | user_optional | 多様な視点を求める(プロバイダーが少ない) | ペルソナのロスター(下記の「ペルソナレンズ」セクション)を抽選し、レンズを Stage-1 プロンプト(動的)または設定ファイルの persona: フィールド(固定)に挿入します。ロスターと理由はトランスクリプトに記録します | 抽選しない場合 → seat = 純粋なモデル | W02 |
| B02 | recovery | HTML レポートにエラーがある、または chairman_synthesis を表示する必要がある | council.py render <transcript.json> を再実行 → 新しいバージョン付きファイル | レンダラーでもエラー → WARN、トランスクリプトを正とします | 終了 |
| B03 | conditional_required | --judges を指定せずに rank を実行 | ブラインドパケットのみを生成して停止 | — | W04 |
検証と停止条件
必須:selftest(12 checks)により、同じ answers.json + judges.json + seed からバイト単位で同一のトランスクリプトが生成されることを確認します。レポートはトランスクリプトの表示レイヤーにすぎません。要レビュー:chairman による synthesis の品質。synthesis を含むレポートが生成されたら W07 で停止します。
例
- 成功例: 「run a council: monorepo を分割すべきか」を
roster --case decisionで 3 席にし → 3 つの seat がベトナム語の正しいダイアクリティカルマーク付きで回答 →prepareが A/B/C を生成 → 3 人の judge が rank →rank --out scratchpad/council-monorepo/が winner + dissent を出力 → chairman がまとめる →renderが synthesis を含むcouncil-report-NNN-seed<seed>.htmlを書き込みます。 - 境界/失敗例:
council.py selftestの終了コードが 0 以外 → W01 で停止し、seat は一つも dispatch しません。rank中にレンダラーでエラーが発生 → WARN のみ。council.transcript.jsonは引き続き書き込まれ、後からrenderを再実行します。
参考 — ペルソナレンズ — 「偉人」の視点(任意、追加機能)
デフォルトでは、各 seat は 1 つの MODEL が回答します。ペルソナレイヤーは視点の多様性を追加します。各 seat が 1 つの
レンズ(Feynman / Munger / Taleb / Rams など)を装着します。モデルの多様性が限られる(プロバイダーが少ない)場合に重要です。エンジンの council.py は変更しません。ペルソナは Stage-1 プロンプトに挿入するテキストにすぎません。
名前や構文を忘れた場合: council.py roster --list(または引数なしの roster)で、すべての case(用途別)・profile・18 のペルソナが表示されます。用途に応じて --case を選べばよく、名前を覚える必要はありません。
名前を間違えて覚えていても正確に呼び出せます: 名前と id の両方に一致し、大文字・小文字は区別しません(--personas Feynman,Taleb は有効です)。入力を間違えると、最も近い候補が提示されます(--case risks → 「'risk' のことですか?」)。何も表示せずに失敗することはありません。
case に応じて 3~5 人を抽選(純粋なコード、ログ記録可能):
python3 harness/scripts/council.py roster --list # catalog: case/profile/persona
python3 harness/scripts/council.py roster --case risk # 3 ghế, có ≥1 cặp đối-trọng
python3 harness/scripts/council.py roster --case ml-ai --size 5 # 5 ghế
python3 harness/scripts/council.py roster --profile lean # 5 người execution-lean
python3 harness/scripts/council.py roster --personas feynman,taleb,rams --json
- Case タグ:
design · strategy · debug · risk · product · decision · simplify · ml-ai(表はharness/council.personas.yamlにあります)。 - ルール: ロスターには常に対立するペアを 1 組以上組み込みます(エコーチェンバーを防止)。不足している場合は stderr に警告を出します。mean-rank が引き分けにならないよう、人数は奇数(3/5)にします。
- ライブラリー:18 のペルソナ + 13 組の対立ペア(出典:
github.com/0xNyk/council-of-high-intelligence)。
プロトコルでの使用方法: ロスターを抽選した後、各ペルソナを 1 つの seat に割り当てます。方法は 2 つあります。
- 動的(推奨): オーケストレーターが
roster --jsonの出力を取得し、各 seat の Stage-1 プロンプトにレンズを挿入します。「<name> の視点から回答してください:<lens>。<sig>。」 - 固定:
harness/council.config.yamlの各 seat にpersona:フィールドを設定します。
ロスターと抽選理由(case、tension のペア)は監査可能なようにトランスクリプトに記録されます(柱 5)。「どのモデルが seat を埋めるか」は、引き続き council.config.yaml の verified で隔離された unknown です。ペルソナレンズはこれとは独立しています。
参考 — council.py コマンド
| コマンド | 説明 |
|---|---|
rank <answers.json> --judges <judges.json> | 集計をすべて実行 → transcript.json + .md |
rank <answers.json> --judges <j> | + バージョン付き llmwiki/html/council/council-report-NNN-seed<seed>.html を自動で書き込みます(Stage-4、必須) |
rank <answers.json>(judges なし) | ブラインドパケットを出力して終了します |
prepare <answers.json> | ブラインドパケットのみ(Stage 2a) |
render <transcript.json> | 既存の transcript から Stage-4 HTML を再レンダリングします(例:chairman_synthesis の貼り付け後)→ 新しいバージョン付きファイル |
roster --case <tag> / --profile <p> / --personas a,b,c | 3~5 個のペルソナレンズを選びます(純粋なルックアップ、対立するペアを 1 組以上含む)。--size 3|5、--json |
selftest | 適合性ベクトル。決定性と正確性を検証します |
フラグ:--seed N(アンカーガードのシード。設定の anchor_seed を上書きします)、
--out DIR(transcript json/md)、--config harness/council.config.yaml、
--question "..."(レポートに実際に表示する質問。空の場合は質問行を非表示にします)。
Stage-4 HTML は常にバージョン付きで llmwiki/html/council/ に書き込まれます。フラグは不要です。
参考 — アダプターの境界(今作って後で適応)
- 契約(今構築・テスト済み): json スキーマ(
answers.json、judges.json、transcript)と、council.pyのすべての決定論的な操作。 - 隔離(
verified: false):harness/council.config.yaml内のモデル ID。計算はこれらに依存しません。 - 後で適応(ファイル 1 つ): 設定内の審査席/審査員/議長を編集し、実際の評議会を実行してから、
verified: trueに切り替えます。エンジンの変更は不要です。
参考 — 決定性の保証
同じ answers.json + judges.json + seed を使うと、実行ごとにバイト単位で同一の transcript が生成されます。匿名化は入力順や作者ではなく sha256(id) に依存するため、回答の順序も作者も漏れません。アンカーガードのシードは引数から審査員ごとに設定され、グローバル RNG は使用しません。selftest ですべてを検証できます(12 項目)。