Multi-Repo Agent Orchestrator
複数リポで別々に走る Claude/Codex セッションを横断で束ねる "上位 AI assistant (Orchestrator)" のアーキテクチャ解説. 5 層構成, repo-initiated 通信, 全 markdown 設計, 知識層の RAG 的運用, 耐障害ルーティングを構成図中心に説明し, Inflection Pi / Nous Hermes Agent と位置づけを比較する.
近頃よくある取り組みだが, PC 上のあらゆる作業に AI Agent を介入させるように仕事の再構築を進めている. 再構築を進めるうちに, 複数のプロジェクトが同時進行する状況で, CLAUDE.md/AGENT.md, skills の仕様判断, その他の規約やコンテキストの設定を共有し自動化したいという欲求が出てきた.
複数 Agent の並行管理自体は, Remote Control や cmux などの導入で軽くなってきたが, それぞれの repo で独立していると初期設定や知識層の反映に手間がかかる. どの repo で起動しても, 作業目標ごとに知識と規約を引き継ぐのがボトルネックとなってきた.
そのために, 複数リポで別々に走らせている十数個の Claude/Codex セッションを, 横断で監視, 記録, タスク配分, 知識集約する上位レイヤ(Agent Orchestrator)を自作した. 各リポの Agent は賢いが, それらを束ねる視点 (誰が何を進行中か, 知見の横断再利用, タスクの配分) は別レイヤの問題で, そこを担うのがこの Orchestrator である.
このような用途なら, 既存の AI Assistant tool として有名な Pi (Inflection) や Hermes Agent (Nous Research) がある. わざわざ車輪の再発明をしなくても, 既存アーキテクチャを採用すれば類似の効果は得られる.
Pi は製品 / UX 層, Hermes Agent はモデル + 単一 agent 層に当たる. どちらも記憶や知識の集約・反映の仕組みを持ち (Hermes Agent は永続メモリ + skills, Pi は会話文脈), 私の理解では orchestrator 的な役割もある程度こなす一般ツールである.
| Inflection Pi | Hermes Agent (Nous) | 本 Orchestrator | |
|---|---|---|---|
| 位置づけ | 個人向け会話コンパニオン | 単一の自律エージェント基盤 | 複数 agent を束ねる上位レイヤ |
| モデル | 自社 Inflection 2.5 (閉) | 自社 Hermes (開 weights) | モデル非依存 (Claude/Codex を使う) |
| エージェント数 | 1 (話し相手) | 1 (記憶 + skills + 自動化) | N (リポごとの coding agent を協調) |
| メモリ | 会話文脈 | 永続メモリ | vault (RAG 知識 + 規約 + タスク) を横断共有 |
| 実行 | クラウド | ローカル可 (Ollama 等) | ローカル (launchd), 他リポ FS は触らない |
| 主眼 | 共感 / 対話 | 一個の強い agent | 横断 routing / 知識 curation / 規約 |
それでも自作したのは, 次の二点を得たかったところによる.
- 記憶層が小さい: 既製ツールの記憶は基本的に単一 agent スコープで, 複数リポ・複数分野にまたがる横断知識ベース (本プロジェクトの vault) としては手狭. RAG として手入れする前提の corpus を, agent の外側に独立して持ちたい.
- 作業ごとに分人的な役割分担がある: 研究, 講義, 開発, 私生活で必要な人格・文脈・規約は異なる. すべてを単一 agent に集約するより, agent ごとの個別コンテキストと, 横断の共通知識とを併存させたい. 一個の強い agent を作る (Hermes Agent の方向) のではなく, 弱くてもよいので多数の agent をそれぞれの分人として保ちつつ, 共通の知識層で束ねる, という選択である.
あと単純に, 自分で弄れる範囲が大きい方が楽しい. 普通は Hermes Agent を入れておけばほとんどこと足りると思う.
なお,以下の構成は最終的には,ネットワーク上の常時稼働Agentに引き継ぐが現在は試験的に,全てローカルで完結させている.
全体構成: 5 層
Orchestrator は管理対象リポの上位に立ち, launchd で毎時巡回するバッチと対話セッションの二面で動く. 処理は 5 層に分かれ, 各リポの Agent とは共有キュー (inbox/outbox) だけで接続する.
なお, この対話セッションの側は後に, 各リポの Agent を cmux のタブで起動・操舵し, 変更操作だけを承認ゲートに通す対話型 coordinator へ発展させた. その仕組みは続編 cmux で起動した repo agent の変更操作だけを承認ゲートに通す対話型 coordinator に書いた.
Orchestrator 自身は判断と記録に徹し, 各リポでの実作業はそのリポの Agent が担う. Orchestrator は司令塔兼書記であって, 現場では手を動かさない.
管理対象: 複数リポをカテゴリで束ねる
以下は匿名化したリポの構造を表している. 各リポは runtime (claude / codex), cadence (毎時 / 日次 / 週次), category, techs をメタデータに持ち, これが後段の routing と知識索引のキーになる. 設定は 1 枚の YAML に集約し, パーサも 1 本に統一している.
構造は二段に分かれる. 作業レイヤの頂点に Orchestrator が立って十数リポを束ね, その系全体をさらに外側から評価するのが existential (Vault) である.
Orchestrator と existential (Vault) は層が違う. Orchestrator は作業レイヤの頂点として十数リポの routing / 知識 / タスクを束ねるが, existential はその Orchestrator を含む系全体を外側から評価する. existential には now.md をはじめ思想 / 現状 / 価値観の single source があり, 個々の作業や routing が自分の価値観と現状に整合しているかを問う. Orchestrator が「何を / どう進めるか」を扱うのに対し, existential は「そもそもその方向で良いか」を扱う. now.md 自体は Orchestrator 経由で必要な agent にも配信される.
各リポも Orchestrator を通じて連携できるようにしている. 例えば, 最近開発を進めている paper 層は, 文献管理に特化したパイプラインを持つ. 論文 PDF を原典として取り込み, それを md に抽出・要約 (図表や式の扱いも含む) してから, 引用情報を bib (引用データベース) に落とす. この PDF → md → bib の流れが research 層の執筆へ供給され, 「読んだ論文がそのまま引用可能な形で原稿に届く」状態が構築されている.
通信モデル: repo-initiated
Orchestrator は管理対象リポの FS を直接書き換えない. これが一番大事な制約だ. 通信はすべて repo 側から共有キューへの push / pull に固定する.
境界を push/pull のキューに固定すると, どちらが何を書いたかが常に明確になり, 片方が壊れてももう片方は動き続ける. 上位が下位のコードを勝手に上書きしない, という規律でもある.
なお, このハブは repo ↔︎ Orchestrator の汎用レーンであり, repo から repo への有向のタスク連鎖は運ばない. そちらは後日追加した別機構で, 続編 中央 immutable queue で運ぶ repo 間の Agent タスク連鎖 に書いた.
データ表現: (今のところ)すべて markdown
状態, タスク, 知識, 規約 - Orchestrator が扱うデータは全部 Obsidian による markdown + frontmatter で持つ. DB も独自フォーマットも使わない. 狙いは移行容易性で, 別マシン (常時起動の Mac mini を想定) へ移すとき, データ表現が markdown のままなら差し替えるのは通信層だけで済む.
\text{Phase 1 (file)} \;\longrightarrow\; \text{Phase 2 (MCP)} \;\longrightarrow\; \text{Phase 3 (LAN MCP)}
通信を進化させても vault の中身は変わらない. markdown のままなので, そのまま人間が読める利点も大きい.
markdown / Obsidian を選んだ主な理由は, もともと個人の知識管理を Obsidian で行っていたことにある. 設計として一から選んだというより, 既存資産 (過去の日記やメモ) をそのまま agent に読ませられる連続性が大きい. 実際 existential (Vault) では過去の日記やメモを文脈として読ませている. そのため, 人間が文章を読む面は当面 Obsidian 固定で行く予定だ. 一方, 人間が読まない orchestrator 層の内部表現 (state や中間データ) は markdown に縛る必然がなく, より効率的な手段があれば置き換える. markdown は人間も読む層の共通項として残す.
知識層 = 自前 RAG
このプロジェクトで一番効いている知識層は, 実質 RAG (Retrieval-Augmented Generation) の自前運用である. ただし主眼は “貯める” ことより “腐らせない” ことにある.
- ingestion: Agent が知見を
[pattern][gotcha][howto][reference][domain]のタグ付きで報告 → 1 件 1 markdown を_staging/<tag>/に保存. source repo, category, techs, confidence をメタデータに持つ. - index: 埋め込みベクトルではなく, タグ + メタデータ + 全文キーワードの軽量索引.
by-category/by-tech/の逆引きで横断取得 (ベクトル化は移行後の検討). - retrieval: 必要時に
pull_relevant_knowledge/search_knowledge. スコアは自リポとの親和度, 新しさ, 過去の使用回数の重み付き和:
\mathrm{score}(n) \;=\; w_c\,[\,c_n = c_q\,] \;+\; w_t\,\lvert T_n \cap T_q \rvert \;+\; w_r\,\mathrm{recency}(n) \;+\; w_u\,\mathrm{usage}(n)
- curation (本題): corpus をただ増やすとノイズで検索精度が落ちる. 引かれた note は本フォルダへ昇格, 古い / 撤回された note は
_stale/へ隔離 (黙って消さないので追跡可). retrieval のログ (usage signal) が次の curation を駆動する. 一度踏んだ gotcha を別リポの Agent が二度踏まないのは, corpus が増えるからでなく手入れされているからだ.
なお, ここで扱っているのはあくまで Agent のための 知識層である. 人間 (私) 自身の学習を同じ枠組み (queue + 巡回) で回す層は, 続編 AIと連携した個人の学習層 (Learn) に書いた.
タスク管理層: Todoist
知識層と並ぶもう一つの管理層がタスクで, ここは Todoist を hub にしている. 人間と agent が同じタスクを同じ場所で見るための層である.
設計は単純で, source of truth は git 追跡の vault/tasks 側に置く. sync_tasks がそれを各リポの Todoist project に push し, agent は pull_my_tasks で自分宛てを取得する. どの project に置くかで担当 repo が決まる (置き場所で routing するので, ラベル付けは最小限). フィールド単位で真の側を分けており, 本文 / 詳細 / リンクは vault が真, 完了状態 / 期限は Todoist が真 (モバイルで完了する運用が多いため). 人間から見ると, Todoist が全リポのタスクを横断で俯瞰し操作する一枚の窓になる.
耐障害ルーティング
Agent のセッションで MCP server が一時的に繋がらないと, Agent は submit 系ツールを呼べず共有 inbox に素のファイルでフォールバックしてくる. これを要約に溶かさず, 種別ごとに振り分ける.
ツールが落ちても, 依頼は種別に応じて確実に拾われる. 賢いコンポーネントほど, 正常時の動作だけでなく壊れ方まで設計しておく必要がある.
という感じで色々やってみているが, なんとなく機能してきたのでまとめました記事でした. 毎日変わっているのであくまで暫定版ですが.