Yapitalism について
Yapitalismは、音声クライアントからターミナルのコーディングエージェントを操作し、確認済みの配信状況とターン状態を伝えるローカルMCPサーバーです。レシートにより、処理が確認された状態と未確認の書き込みを区別します。
主な機能
- 01音声クライアントからの端末エージェント操作
- 02エージェントタスクの送信と待機
- 03配信状態のレシート
- 04エージェントのターン状態報告
- 05ペインの命名とピアマシン接続
活用シーン
- 01席を離れている間のコーディングタスク送信
- 02依頼をエージェントが受信したかの確認
- 03ユーザー入力待ちのプロンプトの検出
- 04複数マシンにまたがるエージェントセッションの監視
MCP 対応
MCPサーバーは、エージェントのペインの一覧表示、読み取り、送信、待機、命名、作成、再開を行うツールを公開します。MCPクライアントはローカル接続し、設定済みのピアサーバーはマシン別の名前空間でペインを公開できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
Yapitalism
ターミナルのコーディングエージェントを音声で操作し、証明された以上のことを回答で主張させません。
デスクから離れているとき、あなたは話し、ターミナル内のエージェントが作業し、音声で返答を受け取ります。その返答だけが頼りです。画面は見えません。だから最悪の失敗はクラッシュではなく、プロンプト欄にテキストが未送信のまま残っているのに、音声が「完了しました」と告げることです。
Yapitalism は、音声クライアントからコーディングエージェントに接続できるローカル MCP サーバーと、音声で何を伝えてよいかを判断するレシートレイヤーです。デスクにいるときは画面を使ってください。これは、デスクを離れている時間のためのものです。
公開プレアルファ版です。ローカル専用です。本番環境へのデプロイ、外部メッセージング、クローズドソースクライアントの自動操作には対応していません。
全体の仕組み
MCP client (Codex · Hermes · Claude Code · Claude Desktop · Cursor)
│ MCP over loopback — no public endpoint, no OAuth, no relay
▼
yapitalism MCP server panes_list · pane_read · pane_send
│ pane_await · pane_task
│ panes_name · panes_unname
│ panes_create · panes_resume · pane_clear
├── superset backend local host-service over tRPC (127.0.0.1:48900)
└── tmux backend capture-pane / send-keys
対象となるエージェントは codex、claude、kimi、opencode です。呼び出し元の申告ではなく、実測によって識別します(tmux 上のプロセスツリー、Superset 上のホスト独自のエージェントレジストリを使用します)。それ以外を実行しているペインは拒否されます。シェルに入力して Enter キーを押すことは、コマンドの実行にあたるためです。
音声クライアントからあなたのマシンに直接接続することはありません。音声クライアントはローカルのエージェントセッションを操作し、そのセッションが 127.0.0.1 経由でこのサーバーと通信します。ネットワークには何も公開されません。
重要な点:レシート
pane_send が返すのは、あいまいな応答ではなく判定です。
| 意味 | |
|---|---|
| GREEN | エージェントが一度限りのマーカーを復唱しました。テキストを受け取り、処理したことは実証されています。ただし、その後の作業が正しいという主張ではありません。どんなレシートもそれを保証できず、このレシートも保証しようとはしていません。 |
| YELLOW | 書き込みは行われましたが、処理されたことは証明されていません。決してこれを格上げしてはいけません。 |
| RED | バックエンドが書き込みを拒否しました。ターミナルには何も届いていません。 |
YELLOW こそが重要です。エージェントの入力欄に送信されずに残ったテキストは、外から見ると作業中の状態と見分けがつきません。同じスピナー、同じスクロール出力、同じ HTTP 200 です。それを「完了しました」と格上げする音声は、気づくまでに何時間もの損失を招きます。
受け入れの証拠として明示的に認められないもの:HTTP 2xx、PTY への書き込みが返ること、ターミナル出力の変化、リビジョンの進行、プロンプトが入力した言葉をそのまま返すこと。
待機と失敗は同じではありません
固定の期限が示すのは経過時間であり、エージェントの状態ではありません。1 分考えた後に正しく回答するエージェントは、最初からずっと検証可能な状態にあります。それを YELLOW と呼べば、運用者は YELLOW を無視するようになります。そのため、待機にはアイドルタイムアウトを使います。ペインに変化があるたびにタイムアウトをリセットしつつ、ハード上限を設けます。
ペインの変化によって決まるのは、待機を続けるかどうかだけです。受け入れの証拠には決してなりません。受け入れの判定は、カナリアだけが担います。そのため、YELLOW では種類も示します。
canary_timeout_pane_moving— ペインのテキストが変化し続けていました。測定した内容に基づく名前です。スピナー、時計、ログの末尾、同じペインを共有する別のエージェントのいずれでも、目的のエージェントが何もしていなくても、この状態になります。もう一度確認する価値があるかもしれないというヒントであり、エージェントが作業中だという主張ではありません。canary_timeout_pane_still— まったく変化がありませんでした。
どうしても解消できない問題が残ります。エージェントがテキストを黙って無視し、何も出力しない場合、それをテキストが届かなかったエージェントと区別する仕組みはありません。検証には、エージェントから何らかの出力がある必要があります。
2つ目のレシート:ターンの終了方法
配信は最低限必要なものです。コストのかかる失敗とは、あなたがエージェントは作業中だと思っている間に、エージェントが「はい/いいえ」の質問を40分間待ち続けていることです。pane_awaitはペインを監視し、エージェントのターンがいつ、どのように終了したかを知らせます。pane_taskは送信してから待機する処理を1回の呼び出しで行います。指示を出して立ち去り、戻ると次のいずれかが確認できます。
| turn | 意味 |
|---|---|
ended | プロンプトがアイドル状態になり、画面の変化が止まりました。ターンは終了しています。ただし、「作業が正しいことを意味するわけではない」という但し書き付きで伝えられ、「完了」とは決して伝えられません。 |
waiting_input | ブロッキングダイアログが画面を占有しています(信頼/ログイン/確認)。あなたがブロッカーであり、ペイロードのtailには引用できる質問が含まれています。 |
agent_error | 既知のエラー行が画面を占有しています。「Please run /login」、401、レート制限などを特定し、タイムアウトとして扱いません。 |
exited | ペインでエージェントが実行されていません。 |
running | 制限時間が経過しても画面が変化し続けています。確認できていない状態であり、調査を申し出ます。 |
endedと判定する前に、エージェントのプロセスがまだ生きていることを再確認します。終了したペインの停止中のプロンプトを、ターン完了として祝ってはいけません。
トランスポートごとの書き込み権限
ベアラートークンが答えるのは、誰が呼び出しているかです。何を実行できるかについては、答えません。0.5.0以降、stdioクライアントは常に書き込みを行えます。クライアントにプロセスの起動を許可した時点で、その信頼に関する判断はOSが行っているためです。HTTP経由の書き込みは、デフォルトでは無効です。拒否されるたびに、修正方法が示されます。そのマシンで一度だけyapitalism authority allow-http-writesを実行してください(yapitalism setupではHTTP登録行を表示しながら同じ質問をします)。読み取り、監視、doctorは、どのトランスポートでも引き続き使用できます。また、yapitalism-mcp --read-onlyを使うと、すべての書き込みが無効になります。まずウォッチャーをインストールし、信頼に値すると判断できたら書き込みを許可してください。書き込みの結果にはすべてoriginが含まれます。
tmuxでは、送信経路で許可されたエージェントのID(pidと開始時刻)も固定し、Enterを押す直前に再確認します。入力後、送信前にエージェントが終了してシェルに戻った場合、テキストは入力欄に残りますが、送信されません。入力は取り消せますが、シェルに対してEnterを押すとコマンドが実行されるためです。
チェックが行われる場所
ほとんどの場合、この仕組みによって操作が変わることはなく、読み上げられることもありません。情報はペイロードとyapitalism setupに記録されています。問題が起きたとき、書き込み前に実際に何がチェックされたのかを確認するためのものです。
| 意味 | |
|---|---|
host | ホスト自体が書き込みを拒否します。チェックと書き込みは1つの操作です。 |
client | このプロセスがチェックしてから書き込みます。対象範囲については実際に機能しますが、アトミックではありません。 |
none | チェックは行われません。 |
{ "status": "GREEN",
"client_guarantees": ["idempotent_dispatch", "empty_prompt_check"],
"missing_guarantees": ["optimistic_revision"] }
yapitalism setupは、お使いのマシンに対応する表を表示します。現時点では、どちらのバックエンドも大半の項目がclientです。チェックはホスト内で書き込みとアトミックに行われるのではなく、書き込みの直前にここで行われます。tmuxではリビジョンチェックをまったく行えません。
リリース済みのSupersetはいずれも、これらのチェックを自ら適用していません。それにもかかわらず、このツールは以前、適用していると主張していました。terminal.sendという名前のプロシージャに処理がルーティングされていることから、「保護されている」と結論付けていたのです。実際にSupersetが提供するterminal.sendが受け取るのは{terminalId, workspaceId, text, submit}であり、何も保護しません。現在、各レベルはホスト独自のバリデーターが必須としているものから読み取られます。名前と契約の違いを見分けるためです。
どちらのバックエンドでもGREENに到達します。どちらの場合もGREENが意味することは同じです。エージェントが一度限りのマーカーを出力したため、テキストを受け取り、処理したということです。この表はマシンの診断用であり、送信するたびに考慮するものではありません。
このリポジトリのレビュー
あなた自身が「これをインストールすべきか」と尋ねられた人であっても、誰かからそう尋ねるよう頼まれたエージェントであっても、確認する価値のある主張と、それぞれの記載場所は次のとおりです。私たちの言葉を鵜呑みにせず、検証してください。
- 権限とその境界。共有マシンでの露出や、フェイルクローズのベアラーゲートも含みます。SECURITY.md。
- 呼び出し側に決してできないこと(クローズドなランチャーテーブル、エージェント以外の拒否、占有中のプロンプトの拒否、ペインごとの直列化):
src/yapitalism/mcp/tmux.pyとsrc/yapitalism/mcp/backends/。各ガードには、防ぐ失敗にちなんだ名前のテストがあります。 - GREEN が主張することと、主張しないこと:上記のレシートのセクションと、エコーでは要件を満たせない理由を示す
tests/test_canary.py。 - このプロジェクトが過去に行った過大な主張と、明示的な撤回:CHANGELOG.md の 0.2.0 から 0.2.4 まで。
マシンもペインです
ピアとは、別のマシンにある yapitalism サーバーを、そのマシン固有の名前空間にマウントしたものです。マシン studio 上の codex ペイン tmux:%0 は、こちらでは studio:tmux:%0 となり、同じ panes_list に表示され、同じ pane_send で指定できます。レシートはそのまま引き継がれます。ピアは自身のターミナルの隣でレシートを証明し、こちら側はその ID にマシン名を付けるだけです。
# on the peer (reachable over your tailnet):
YAPITALISM_MCP_HOST=100.x.y.z yapitalism-mcp # tailnet bind requires the bearer gate
# on this machine:
yapitalism peers add studio http://100.x.y.z:8792/mcp --token-file <peer's token>
peers add は、何かを書き込む前に、ピアが yapitalism サーバーとして応答することを検証します。公開アドレス上のピアは、allow_public を明示しない限り拒否されます。トランスポートは tailnet ですが、それだけで信頼が保証されるわけではありません。誰が呼び出せるかは、ピアのベアラートークンで決まります。設定済みのピアは、ライブのペイン数とともに yapitalism doctor に表示されます。
エージェントはピア上でも起動および再開できます。panes_create と panes_resume は、ピアを指定する machine 引数を受け取ります。ピアでは独自のゲートチェーン全体が実行されます。また、エージェントのリモート起動は、エージェントへの入力より強い権限を必要とするため、専用のスイッチがあります。デフォルトではオフです。ピア上で一度、yapitalism authority allow-remote-create を実行してください。再起動後もピアのサーバーを動作させるには、yapitalism service --host <its tailnet IP> を実行すると、値が埋め込まれた launchd plist または systemd unit が出力されます。インストールするかどうかは、引き続きあなたが決められます。
ID ではなく名前で指定する
音声では mbp3:tmux:%2 と言えません。ペインに単語を一度割り当てれば —
panes_name("billing", "tmux:%4")
— 以降、すべてのツールで billing を使えます。この割り当てには、名前を付けた時点でそのペインが実行しているものが記録され、使用のたびにライブの一覧と照合して再検証されます。tmux はペイン ID を再利用するため、ペインが消えた、または実行環境が変わった名前は、理由を示して拒否されます。黙って別の対象に切り替わることはありません。曖昧な照合はありません。「たぶん正しい codex」は対象ではありません。名前は panes_list 内の各ペインに表示されます。
うまく操作する
ブリッジエージェントは、継続的な指示があると最もよく動作します。レシートを読み上げ、YELLOW は決して再送せず、ペインには人が使うような名前を付けてください。実際に使っているプロンプトは docs/operator-prompt.md にあります。音声クライアントのカスタム指示に貼り付けてください。
レシピ
6 つのツールを組み合わせると、役立つウォッチャーを作れます。権限の監視(ダイアログが気付かれないまま放置されることはありません。実際に最初に検出したのは、エージェントがウォレット取引の承認を黙って保留していたケースでした)、プロバイダー障害の監視、1 日の終わりのダイジェストなどです。動作するプロンプトは docs/recipes.md にあります。
インストール
macOS または Linux では、Python 3.11 以降と tmux が必要です。リリースごとに、動作するはずだと仮定するのではなく、何も入っていない python:3.11-slim コンテナで送信から検証までの一連の処理を実行しています。すべてお使いのマシン上で動作し、ネットワークには何も公開されません。
# 1. install
pipx install yapitalism # or: uv tool install yapitalism / pip install yapitalism
# 2. start the server (loopback only — it refuses to bind anything else)
yapitalism-mcp
# 3. point your voice client's agent at it, in another shell
codex mcp add yapitalism --url http://127.0.0.1:8792/mcp
# 4. ask the tool what your machine can actually do
yapitalism setup
setup は「インストールに成功しました」と表示する代わりに、マシンの状態を確認します。利用可能なバックエンド、PATH 上にあるエージェント CLI、Superset ホストが稼働中かどうかとそのビルド、さらに上記の保証表を記入したものを確認します。書き込むのは、同意した場合の Superset マニフェストだけです。また、不足している項目と、それぞれに必要な正確なコマンドを提示します。
次に、音声アプリに話しかけます。「自分のペインを一覧表示して」、続いて「これを Codex ペインに送って」。どの MCP クライアントでも同じように使えます。Hermes、Claude Code、Claude Desktop、Cursor の登録情報は、実行したマシンに合わせて yapitalism setup が表示します。
8792 番ポートが使用中の場合は、YAPITALISM_MCP_PORT で変更できます。デフォルト以外の tmux サーバーを対象にするには、YAPITALISM_TMUX_SOCKET を設定します。HTTP トランスポートでは、デフォルトでベアラートークンが必要です。ループバックはユーザー境界ではないため、サーバーは初回起動時にトークンを生成し、yapitalism setup はそのトークンを含む登録行を表示します。YAPITALISM_MCP_TOKEN で上書きでき、YAPITALISM_MCP_INSECURE=1 を設定すると無効にできます。stdio ではトークンは不要です。起動されたプロセスと通信できるユーザーは、すでに OS が決定しているためです。
サーバーを自分で起動するクライアント
Codex は URL を使用します。Claude Desktop、Cursor など、ほとんどの MCP クライアントはプロセスを起動し、標準入力/標準出力で通信するため、別のサーバーは起動せず、--stdio を指定します。
{
"mcpServers": {
"yapitalism": {
"command": "yapitalism-mcp",
"args": ["--stdio"]
}
}
}
クライアントが PATH を引き継がない場合は、command -v yapitalism-mcp で取得した絶対パスを使用してください。macOS の GUI アプリでは通常、PATH は引き継がれません。環境変数の設定しかできないクライアントでは、YAPITALISM_MCP_TRANSPORT=stdio を設定すると、このフラグと同じ動作になります。
stdio モードでは、プロトコル以外の内容を標準出力に出力できないため、サーバーは起動バナーを抑制します。シェルスクリプトでラップする場合は、そのスクリプトも出力を抑制してください。
起動状態の維持
音声ルートはサーバーの終了とともに停止するため、ターミナルではなく init システムで実行してください。どちらのユニットも お使いのユーザー として実行され、root では実行されません。サーバーは、あなたが表示できるすべてのターミナルを読み取れます。
- macOS —
.agents/launchd/にあります。plist はテンプレートです。README には実際のバイナリパスを埋め込むsedの行があります。launchd はPATHも~も検索しないためです。 - Linux —
.agents/systemd/にある--userユニットです。systemctl --user enable --now yapitalism-mcpを実行します。
いずれの場合も、先にシェルから起動したインスタンスを終了してください。終了しないと、2 つのプロセスが 8792 番ポートを取り合い、どちらが勝つかはタイミング次第になります。
Superset ターミナル(任意)
tmux バックエンドには何も必要ありません。Superset では、ホストのエンドポイントとトークンを格納した 0600 のマニフェストが必要です。手作業で作成する必要はありません。Superset が必要な情報をすでに書き出しています。
yapitalism superset setup # shows what it found and would do
yapitalism superset setup --confirm # writes it
この処理は、アプリ自身の ~/.superset/host/<organizationId>/manifest.json を読み込み、稼働中のホストに対してトークンを検証し、デフォルトのターミナルを選んで、~/.cache/superset-watch-voice/yapitalism-manifest.json(または $YAPITALISM_SUPERSET_MANIFEST)に書き込みます。推測で処理を進めることはせず、元ファイルのアクセス権が 0600 より緩い場合、マニフェストが停止中のプロセスを指している場合、または選択方法のない稼働中の組織が 2 つある場合は、すべて処理を中止します。トークンが表示されることはありません。
マニフェストがなくても、panes_list は引き続き tmux のペインを返し、Superset の状態を errors に報告します。接続できなかったバックエンドが、「ターミナルなし」として黙って報告されることはありません。
音声に処理結果の伝え方を教える
.agents/skills/superset-operator/ には、モデルが YELLOW を「完了」と誤って判断するのを防ぐポリシーと、エージェントが実際に読み込むコピーとのずれを確認するチェックが含まれています。
独立したレシートコア
5段階のモデルは、MCP サーバーなしでも利用できます。
capture— 意図が記録されましたdispatch— 具体的な対象への書き込みが試みられましたaccept— カナリアまたは明示的な確認応答によって、対象が受け入れたことが証明されましたwork— エージェントの実質的な進捗が確認されましたdeliver— 最終更新がユーザーに届きました
証拠には出所として api、terminal_diff、ui_observation、user_report、inferred が付与されます。
inferred によって段階を成功と判定することは決してありません。
このプロジェクトの発端となったインシデントでは、音声セッションは継続していたものの、音声による進捗報告が止まりました。180秒のウォッチャーが2回とも、ターミナルがリビジョン 920118 でフリーズしているのを確認し、カナリアも届きませんでした。それでも音声は作業が続いているかのように示し続けていました。この製品の目的は「音声クライアントを修正する」ことではありません。GREENを決して偽装しないことです。
CLI のインターフェースは、doctor、receipt show、ledger verify|manifest|migrate、superset status|send です。確認済みの superset send では、ドライランで出力された正確な client-token を再利用し、ディスパッチの直前にスナップショットを取得して、リビジョンが変更されていたら拒否し、結果が不明な POST は決して再試行しません。
既知の制限
レシートシステムが過剰な主張をするくらいなら、ないほうがましです。そのため、制限を明確に示します。
- 末尾の切り詰めは検出できません。 レジャーの末尾の行を削除しても、残ったプレフィックスの検証は成功します。これを検出するには、ファイル外部のアンカーが必要です。
docs/adr/0004を参照してください。 - レジャーは自らを証明するものです。 ハッシュ検証によって、行が編集されたり並べ替えられたりしていないことは証明できますが、誰が書き込んだかは証明できません。全面的に捏造されたレジャーでも問題なく検証されます。
- tmux に楽観的リビジョンガードを提供できるバックエンドはありません。 呼び出し元からの期待値、つまり「読み取ったときと同じ状態がペインに残っている場合に限り書き込む」という指定が必要ですが、
pane_sendには期待されるリビジョンを渡せません。ペインを2回読み取り、変化していたら拒否するのは、同じ名前を掲げながら別の保証を提供することになるため、近似して済ませずnoneとして報告します。 - ガード付きホストの外で行う空プロンプトのチェックは、ヒューリスティックです。 表示された画面を読み取るため、「空」と誤判定すると、誰かが入力途中のテキストに追記して、それを送信してしまいます。そのため、空であると確信できない場合は、読み取れない画面も含めて拒否し、
pane_clearを通す方法としています。検証は実際のペインで行っており、大規模なサンプルでは検証していません。 - 基準となる Superset は、リリース済みの標準ビルドです。このビルドでは
terminal.sendにガードがありません。カナリアが観測された GREEN の実証済み送信は、0.2.4 以降、この稼働中のホストに対して、直接および MCP の全機能経由の両方で繰り返し完了しています。ガード付きホストの分岐を試しているのは、記録されたパターンに対してのみです。リリース済みのビルドには、テスト対象となるそのガードがないためです。 - ガード付きの Superset ホストは、Codex のプレースホルダーテキストを過剰に拒否します。 エージェント自身の提案行をステージ済み入力として数えるため、そのようなペインへの送信は拒否され、クリアしても解決しません。レシートには、クリアを案内するのではなく、その事実が正確に記録されます。修正はホスト側で行う必要があります。
- チェックと書き込みの間に、tmux ペインのランタイム情報が古くなることがあります。 Superset の情報はホスト自身のレジストリから取得されるため、そのゲートは書き込み後ではなく、書き込み前に実行できます。
- カナリアが証明するのは「うまくいった」ことより限定的です。 テキストが何かに届き、その何かが一度限りのマーカーを返したこと、つまり配信と確認応答を証明します。エージェントが作業を行ったこと、その作業だけを行ったこと、またはそのペインが意図したものだったことは証明しません。GREEN は配信レシートであり、作業レシートではありません。
- 同じペインへの同時送信はキューに入らず、直列化されます。 2回目の送信は1回目が終わるまで待ちます。保留、順序制御、再試行は行われません。ターミナルが受け付けるより速く送信する音声クライアントは、インターリーブするのではなく、自身のターンをブロックします。
- クローズドクライアントにおける音声内コネクターの動作は文書化されておらず、予告なく変更される可能性があります。
リポジトリの構成
src/yapitalism/mcp/ MCP server, backend registry, receipts, tmux driver
src/yapitalism/adapters/ Superset host-service client
src/yapitalism/ receipt core: model, canary, claims, ledger, CLI
tests/ deterministic unit, replay, and real-tmux tests
fixtures/ scrubbed incident replays
.agents/skills/ voice policy + drift check
.agents/launchd/ run the server as a login agent
docs/adr/ load-bearing decisions
docs/architecture.md component boundaries and evidence model
明示的な非目標
- クローズドな音声クライアントの内部構造のリバースエンジニアリングやパッチ適用。
- 存在しないバックグラウンドターン API やプッシュ API の考案。
- マルチテナント SaaS。
- メール、DM、メッセージの自動配信。
- ターミナルのリビジョン移動をコマンドの受理とみなすこと。
クレジット
レシート整合性の中核部分は @liri-ha が作成し、そのコミットは変更せずにこちらに取り込んでいます。CONTRIBUTORS.md をご覧ください。
セキュリティ
生の文字起こし、ターミナルのテキスト、認証情報をこのリポジトリに保存してはいけません。台帳には、上限を設けたメタデータ、ハッシュ、分類情報を保存します。ベアラートークンを含むマニフェストは、モード 0600 でリポジトリの外部に置き、そのパスが明示的に渡された場合にのみ読み込まれます。表示されることはありません。SECURITY.md をご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。