Fulcrum:ローカルファースト・エージェントコントロールプレーン
並列 AI コーディングエージェントのフリートに向けた、タスク管理・WIP 制限・ハイブリッドメモリ検索・Chief-of-Staff コンテキストを提供するローカルファーストの制御基盤。
ほとんどの作業日に5つの AI コーディングエージェントを並列で動かしている。Claude Code、Codex、Gemini CLI、Pi、OpenCode—それぞれ優秀で、それぞれ完全に他の何をやっているかを知らない。Fulcrum 以前の「オーケストレーションレイヤー」は付箋と祈りだった。誇張じゃない。文字通り付箋があった。
なぜ作ったか
問題は個々のエージェントが悪いことじゃない。彼らは素晴らしい。問題は単一の生産的なエージェントセッションと、脳を溶かさずに管理できるマルチエージェントワークフローのギャップだ。
評価したすべてのベンダーフレームワークは、一つのプロバイダーにロックされているか(ハードノー)、時間をまたぐセッションには役に立たないステートレスなリクエスト・レスポンスループのために設計されているか、作業中コンテキストを信頼できないクラウドバックエンドを必要とするかのどれかだった。ローカルで動いて、ラップトップの再起動を生き延びて、新しいターミナルタブを開くたびにプロジェクト全体の歴史をゼロから説明する必要がないものが欲しかった。
だから使いたいものを作った。Fulcrum と名付けた、なぜなりエージェントはレバーで、コントロールプレーンが実際にレバレッジがかかる場所を決めるからだ。
どう動くか
Fulcrum は MCP サーバーを公開する—Anthropic が Claude Code の標準ツール呼び出しサーフェスとして提供する Model Context Protocol だ。接続するすべてのエージェントが同じプリミティブのセットにアクセスできる:タスク管理、ランライフサイクルトラッキング、ハイブリッドメモリストア。
ストレージレイヤーは FTS5 全文検索付きの SQLite で、セマンティック検索用のベクターインデックスで拡張されている。エージェントが何かを想起したいとき—「先週火曜日に認証スキーマについて何を決めたか?」—Fulcrum は3ステージの検索を実行する:FTS5 キーワードマッチ、ベクターコサイン類似度、クエリで言及されたエンティティをまたぐグラフトラバーサル。結果は重み付き Reciprocal Rank Fusion で融合され、エージェントのコンテキストウィンドウに届く前に信頼度フロアでフィルタリングされる。
メモリには3層がある。L0 は生ダンプ—逐語的、イミュータブル、追記のみ。L1 は LLM キュレーターが信頼度スコア、保持ティア、L0 ソースへのバックリファレンスを持ってメンテナンスするキュレーション済みウィキページ。L2 は L1 上のベクターインデックス。Fulcrum に何かを想起させると、L0 由来の来歴が添付された L1 ページが得られるので、クレームを生成したセッションのトランスクリプトまで常にトレースできる。
タスク管理は WIP 制限を強制する。チームが5つのことに深く取り組んでいて誰かが6つ目を始めようとすると、Fulcrum は押し返す。これは大げさじゃない—エージェントのコンテキスト分断を防ぐために見つけた最も効果的な単一のことだ。12個のオープンタスクをジャグリングしているエージェントは2つに集中しているエージェントより悪い出力を生む。
Chief-of-Staff の役割はオーケストレーションティアだ:アクティブなタスク、実行中のエージェント、最近のイベントからワールドステートスナップショットを構築し、それらのスナップショットを使ってスペシャリスト役割に作業をディスパッチする。COS はコードを書けない。スペシャリスト役割はサブオーケストレーションを生成できない。役割階層はプロンプトレイヤーじゃなくツールレイヤーで強制される。
面白いところ
開発中に最も驚いたこと:最も難しい部分はメモリ検索じゃなかった。ランライフサイクルだった。
エージェントはクラッシュする。ターミナルが閉じる。ラップトップの蓋が下がる。2時間前に「進行中」だったランは complete_agent_run の呼び出しを完了しないかもしれない。Fulcrum にはセッション開始時に動くステールラン掃除機があり、最後のハートビートがステールネス閾値より古いランを中断する。これがなければ、ワークスペースの状態はファントム実行中エージェントで埋まり、Chief-of-Staff はゴーストに基づいて計画の決断をし始める。
もう一つの非自明なこと:5つの並列エージェントがすべて少し異なる角度から同じアーキテクチャ決断を捉える可能性があるとき、メモリ書き込みパスを冪等にすることは聞こえるよりずっと難しい。キュレーターの仕事は重複排除、上書き、一貫した L1 サーフェスのメンテナンス—これは生の L0 レイヤーが高い書き込みボリュームを許容し、キュレーションパスがコンフリクト解決を優雅に処理する必要があることを意味する。
メモリレイヤーをデータベースよりも新聞アーカイブとして考えるようになってきた:生ダンプは日刊版(決して捨てない)、キュレーション済みページは百科事典(新しい証拠が届いたときに更新される)、信頼度スコアはクレームが時間をかけて持ちこたえてきたかについての編集委員会のコンセンサスだ。
変えたいこと
ベクターインデックスは現在ワークスペースごとで、これは間違いだ。クロスワークスペース検索—「先月の支払いサービスリポジトリで似たような問題を解決した」—は本当に役立つだろうし、検索パイプラインはすでにそこにある。スコープを正しく配線しただけでいい。
キュレーターのコンフリクト解決ロジックも強化したい。今は2つのエージェントが同じエンティティについて矛盾した情報を捉えた場合、キュレーターは信頼度の高いバージョンを選ぶ。実際にはうまく動くが、少数意見をサイレントに捨てる。正しい動作はおそらく矛盾をフラグ付きペアとして表面化させ、人間か COS が明示的に解決できるようにすることだ。
ディスパッチパス—COS が実際にスペシャリスト役割のために Claude Code サブプロセスを生成する—は今のところ fire-and-forget だ。COS が何が起きているかを観察できる適切な stdout ストリーミングが欲しい、ハートビートが冷たくなるのを待たずにランが横道にそれているときに介入できるよう。
Fulcrum はエージェントを本気で動かし始めたときから存在していてほしかったインフラの部分だ。構築することで、マルチエージェントオーケストレーションはほとんどが分散システムの問題で、その上に LLM 固有の懸念の薄いレイヤーがあること、そして分散システムの問題が最初に噛みつくことを教わった。