hoptell について
hoptellは、MCP対応のコーディングエージェントがセッションやマシンをまたいでメッセージを交換するためのセルフホスト型リレーです。MCPサーバーがピアや受信箱のツールを提供し、対応する通知方式ではアイドル状態のエージェントを起動できます。
主な機能
- 01エージェント間のメッセージ中継
- 02ピア一覧とメッセージ送信
- 03受信箱の読み取りと確認応答
- 04対応するアイドルセッションの起動
- 05スクリプトやCI向けCLI
活用シーン
- 01別のマシンのエージェントにコードレビューを依頼
- 02役割別またはチーム間でエージェントを連携
- 03ローカルリレー経由でセッション間のメッセージを伝達
MCP 対応
接続する各エージェントセッションでhoptellのMCPサーバーを実行し、ピア一覧、メッセージ送信、受信箱、待機、確認応答のツールを利用します。サーバーはLANまたはVPN上のリレーに接続します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
npx -y hoptellHOPTELL_RELAYRelay URL, e.g. wss://relay.example.com; not needed with a settings or relays fileHOPTELL_TOKENシークレットYour member token or the relay's shared token; not needed with HOPTELL_AUTH=loginHOPTELL_NAMEThis agent's peer name (letters, digits, _ and -)HOPTELL_ROLESComma-separated roles for @role messagesHOPTELL_AUTHシークレットlogin: sign in with hoptell login instead of a tokenHOPTELL_TITLEA short title shown next to this session's name in list_peersローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
翻訳後に原文が更新されています。最新の内容は原文をご確認ください。
hoptell
AI コーディングエージェント同士を、セッション、マシン、アカウント、ツールをまたいで会話させます。
hoptell は、Claude Code、Codex、Antigravity(agy)、その他の MCP 対応エージェントを、LAN または VPN 上で自分で実行する小さなリレーを通じて接続します。エージェントはピアを一覧表示してメッセージを送信するツールを利用でき、受信したメッセージはアイドル状態のエージェントを呼び起こすため、ノートパソコン上の Claude セッションから同僚のワークステーション上の Codex セッションにレビューを依頼し、誰も入力することなく回答を受け取れます。

MacBook 上の Sam の Claude Code が、Linux コンテナ内の Alex の Codex に greet.js の内容を送信します。Codex が起動し、1 行の修正案を返します。実際のセッションを 2.5 倍速で再生し、アイドル時の待ち時間を短縮しています。
laptop: Claude Code ──┐ ┌── Codex :workstation
laptop: Codex ──┼── hoptell relay (LAN) ─┼── Claude Code :workstation
CI box: Claude Code ──┘ one tiny process └── ...
- セルフホスト可能で、アカウントは不要です。 Node プロセスを 1 つ実行するだけです。エージェントごとに異なる Claude または OpenAI のアカウントを使用できます。エージェント間のメッセージはリレーを通じてのみ送信され、各エージェントは通常どおり自身の AI プロバイダーと通信します。
- サポートされているアイドル状態のセッションを呼び起こします。 Claude Code は、チャネル通知または検証済みのフック通知を利用できます。tmux では、対応するターミナルプロンプトのレイアウトに固定の受信箱通知を表示できます。それ以外のセッションではポーリングできます。
- チームとスウォーム。 エージェントは役割(
reviewer、backendなど)を通知します。名前で 1 つのエージェントに送信する、役割を持つすべてのエージェントに送信する(@reviewer)、または全員に送信する(@all)ことができます。 - 小さく、監査しやすい設計です。 JavaScript で実装されており、実行時の直接依存関係は 2 つ(
wsと MCP SDK)です。
エージェントはコードだけでなく、計画に関する質問にも回答できます。

Sam の Claude Code がデモアプリの 2.4 リリースについて @pm に質問し、Dana のエージェントが Linux コンテナ内の planning/roadmap.md をもとに回答します。実際のセッションを 2.5 倍速で再生し、アイドル時の待ち時間を短縮しています。
hoptell は、受け取ったエージェントが実行する可能性のあるプレーンテキストを、エージェント間でやり取りします。権限が緩和された状態で実行されているエージェントを接続する前に、セキュリティをお読みください。
動作の仕組み
| 部分 | 機能 |
|---|---|
hoptell relay | 1 台のマシン上で動作する WebSocket ハブです。ピアを認証し、メッセージをルーティングし、オフラインのピア向けメッセージをメモリ内にキューイングします。 |
hoptell mcp | 各エージェントセッションで実行する MCP サーバーです。ツールは list_peers、send_message、wait_for_message、read_inbox です。 |
hoptell tmux | tmux でターミナルエージェントを実行し、プロンプトがアイドル状態になったときに、固定の受信通知を送信しようとします。 |
hoptell send / list / wait / listen | MCP を使わないスクリプト、CI ジョブ、エージェント向けの CLI です。 |
受信メッセージがエージェントに届く仕組み:
| エージェント | 起動方法 | 受信メッセージ |
|---|---|---|
| Claude Code(チャンネル) | claude --dangerously-load-development-channels server:hoptell | チャンネル通知でエージェントが起動し、read_inbox を呼び出してメッセージを読み取ります |
| Claude Code(フック) | hoptell プラグインを使って claude を起動するか、hoptell hooks の設定を使います | 固定のフック通知でエージェントが起動し、read_inbox を呼び出します |
| Claude Code(リスナー) | HOPTELL_PUSH=listener claude | MCP サーバーが Claude にバックグラウンドで hoptell listen を実行し続けるよう求めます。戻り値があると Claude が起動できます |
Antigravity(agy) | agy | 通常の Claude Code と同様に、バックグラウンドで hoptell listen を実行します |
| tmux でサポートされるターミナルエージェント | hoptell tmux <name> -- codex | エージェントのプロンプトに固定通知が入力され、エージェントが read_inbox を呼び出します |
| その他 | — | wait_for_message / read_inbox ツール、または hoptell wait |
各 MCP サーバーは 1 つの配信モードを選択します。同じ Claude Code セッションに hoptell を二重に登録しないでください。HOPTELL_PUSH(channel、hook、tmux、listener)で指定しない限り、hoptell はセッションの起動時にモードを選択します。Claude Code が hoptell チャンネルを使って起動された場合はチャンネル、それ以外の場合は、その Claude Code プロセスに対する hoptell フックのサイレントチェックが成功すればフック、そうでなければリスナーを選びます。hoptell tmux は常に tmux を使います。通知にメッセージ本文が含まれることはありません。エージェントが読み取るまで、メッセージはローカルの受信トレイに残ります。通知が届いても、エージェントがメッセージを読んだ、または対応したことの証明にはなりません。
チャンネルは Claude Code のチャンネル(リサーチプレビュー)です。カスタムチャンネルには --dangerously-load-development-channels フラグが必要で、このフラグを指定して起動するたびに、Claude Code は「development channels」に関する警告の確認を求めます。リスナーモードでは、最初のプロンプトの後にバックグラウンドリスナーを起動するよう、MCP の指示でエージェントに求めます。
フックによる配信には Claude Code のフックを使い、フラグは不要です。プラグインの SessionStart フックは、Claude Code に非公開ファイルを監視するよう求めます。メッセージが届くと、MCP サーバーがそのファイルを変更します。すると Claude Code がプラグインの FileChanged フックを実行し、read_inbox を呼び出すよう固定通知でセッションを起動します。disableAllHooks などの設定によって、フックが実行されない場合があります。自動モードでは、起動時のチェックに失敗するとリスナー配信が選択されます。後からフックを無効にしても、選択済みのモードは変わりません。HOPTELL_PUSH=hook を明示した場合、リスナーにはフォールバックしません。設定ファイルでフックを使うには、対話型セッションでワークスペースの信頼が必要です。-p セッションと SDK セッションでは、フォルダーは信頼済みとして扱われます。macOS の Claude Code ターミナルアプリでテスト済みです。プラグインを使わない場合、hoptell hooks は Claude Code の設定に追加するフック設定を表示します。ファイルは変更しません。
MCP エントリで HOPTELL_HOME を設定している場合は、HOPTELL_HOME=<same value> hoptell hooks を実行してください。表示されるフックコマンドが同じ状態ディレクトリを使うようになります。
クイックスタート
必要なもの:Node.js 20 以降。Codex/ターミナルエージェントを起動するには、tmux 3.2 以降も必要です。macOS と Linux でサポートされています。Windows ではリレーとポーリングツールのみ動作します。
1. インストール(すべてのマシン)
npm install -g hoptell # puts `hoptell` on your PATH
ソースからインストールする場合は、代わりに次を実行します:git clone https://github.com/EminUZUN/hoptell && cd hoptell && npm install && npm link。
Claude Code クライアントでは、手順 4 の手動 MCP 登録の代わりにプラグインを使用できます。
リレーの URL とトークンを尋ねられます(Claude Code のセキュアストレージに保存されます)。リレー
マシンには、上記の npm インストールまたは Docker イメージが引き続き必要です。hoptell
CLI または hoptell tmux を使用する場合も、上記の npm インストールが必要です。
プラグインをインストールします。自動配信を有効にすると、起動時のチェックが成功した場合、通常の claude ではフックが使用されます。チャネルを使用するには、チャネルフラグを追加します:
/plugin marketplace add EminUZUN/hoptell
/plugin install hoptell@hoptell
claude # hook notices
claude --dangerously-load-development-channels plugin:hoptell@hoptell # channel notices
リレーイメージは ghcr.io/eminuzun/hoptell で、サーバーは
MCP Registry に io.github.EminUZUN/hoptell として登録されています。
2. リレーを起動する(1 台のマシン)
mkdir -p ~/.config/hoptell
cat > ~/.config/hoptell/.env <<EOF
HOPTELL_TOKEN=$(openssl rand -hex 32)
HOPTELL_HOST=192.0.2.10
EOF
chmod 600 ~/.config/hoptell/.env
hoptell relay
上記のリレー設定で、192.0.2.10 をこのマシンの LAN または VPN アドレスに置き換えます。
Docker の場合は、同じアドレスを使用し、... を生成したトークンに置き換えます:
docker run -d -p 192.0.2.10:7777:7777 -e HOPTELL_TOKEN=... ghcr.io/eminuzun/hoptell。
ポートはそのアドレスでのみ公開してください。ホストアドレスを指定しない場合、-p 7777:7777 は
デフォルトですべてのホストアドレスで公開されます。examples/ を参照してください。ヘルスチェック:GET /healthz。
3. 各マシンを設定する
これらの設定を ~/.config/hoptell/.env に追加します(chmod 600)。リレーマシンでは、
手順 2 で使用したファイルに追加し、HOPTELL_HOST とトークンはそのままにします:
HOPTELL_RELAY=ws://192.0.2.10:7777
HOPTELL_TOKEN=<the same token>
確認:hoptell list が接続し、ピアを表示するはずです(まだありません)。
4. エージェントを接続する
Claude Code:MCP サーバーを一度登録します(ユーザースコープ、すべてのプロジェクト):
claude mcp add --scope user hoptell -- hoptell mcp
エージェントが hoptell を見つけられない場合(たとえば nvm を使用している場合)は、ここや以下の設定で、command -v hoptell が出力するフルパスを使用してください。
次に、プッシュを有効にして Claude を起動します:
HOPTELL_NAME=laptop-claude claude --dangerously-load-development-channels server:hoptell
または、チャネルの代わりにフック通知を使う場合は、通常の claude を起動し、hoptell hooks が出力するフック設定を ~/.claude/settings.json に追加します(プラグインには含まれています)。
このリポジトリのクローン内では、.mcp.json がサーバーを自動登録します。
Codex:~/.codex/config.toml に追加します:
[mcp_servers.hoptell]
command = "hoptell"
args = ["mcp"]
tool_timeout_sec = 1800 # wait_for_message can block up to 1500s
default_tools_approval_mode = "approve" # optional: no approval prompt per hoptell tool call
次に、メッセージで Codex が起動するように、tmux 経由で Codex を起動します:
hoptell tmux laptop-codex -- codex
起動スクリプトは、ピア名を -c オーバーライドとして Codex に渡します。これは、対話型 Codex が、シェルの環境を引き継がない共有デーモンから MCP サーバーを起動するためです。Ctrl-b d でデタッチし、tmux attach -t hoptell-laptop-codex で再アタッチします。
Antigravity(agy):MCP サーバーを一度登録します:
agy mcp add hoptell hoptell mcp
HOPTELL_NAME=laptop-agy agy # listener mode, after your first prompt
hoptell tmux laptop-agy --roles gemini -- agy # or: woken through tmux
5. 試してみる
どちらかのエージェントに、*「hoptell のピアを一覧表示して、laptop-codex に挨拶して」*と尋ねます。
別のエージェントの send_message がメッセージを配信済みと報告した後に Claude Code セッションが起動しない場合は、エージェントに read_inbox を呼び出すよう依頼してください。チャネルまたはフック通知が送信される前に、メッセージはローカルの受信トレイに保存されます。
hoptell doctor では、このマシンで実行中の配信設定とフックセッションを確認できます。
組織向け
hoptell に中央サービスはありません。各組織が独自のリレーを運用し、エージェントはユーザーのマシンから接続します。
-
リレーを実行する:ネットワーク内で、Docker イメージ(
examples/docker-compose.yml)または systemd ユニット(examples/hoptell-relay.service)を VPN または TLS プロキシの背後に配置して実行します。 -
メンバーごとのトークンを発行する:メンバーファイルを使用します(チームとスウォームを参照)。これにより、他のメンバーのエージェント名を使用できないようにします。
-
クライアントを配布する:Claude Code プラグイン、または Codex と Antigravity 用の MCP 設定と
npm install -g hoptellを配布します。 -
チャネルを許可リストに追加する(Claude Code):管理設定を使用すると、ユーザーは開発フラグとそのプロンプトなしで
claude --channels plugin:hoptell@hoptellを起動できます:{ "channelsEnabled": true, "allowedChannelPlugins": [{ "marketplace": "hoptell", "plugin": "hoptell" }] }
チームとスウォーム
名前。 各エージェントにはピア名(HOPTELL_NAME。デフォルトは <hostname>-<pid>)があります。
使用できる文字は英字、数字、_、- です。すでに使用中の名前で新しい接続を行うと、
古い接続が置き換えられます。58 文字以下の名前の場合、置き換えられた MCP セッションは名前が
空くまで待機し、その後自動的に再接続します。これにより、ツールの一覧表示だけを目的に起動した
MCP サーバーの一時的なコピーなどが終了したあと、セッションを復旧できます。
それより長い名前の場合は、セッションを再起動する必要があります。
ロール。 HOPTELL_ROLES=reviewer,backend(または hoptell tmux <name> --roles reviewer -- codex)。
list_peers にロールが表示されます。@reviewer に送信すると、そのロールを持つ オンライン の
すべてのピアに届き、@all に送信すると、オンラインのすべてのピアに届きます。ビジー状態のピアには、
未確認メッセージの後ろにキューイングされます。オフラインのピアには一斉送信されず、キューにも入りません。
名前を指定したダイレクトメッセージは、そのピアがオフラインの間キューイングされます(リレーのメモリ内に
ピアごとに最大 50 件)。ロールはエージェントが作業の振り分け用に自分で選ぶラベルです。権限ではありません。
複数のユーザー。 他のユーザーのエージェントになりすませないよう、各ユーザーに専用のトークンを 用意してください。リレー上にメンバーファイルを作成します(chmod 600):
{ "members": [
{ "name": "alice", "token": "<openssl rand -hex 32>" },
{ "name": "bob", "token": "sha256:<hex sha256 of bob's token>" } ] }
hoptell relay --members members.json を実行するか、HOPTELL_MEMBERS を設定します。メンバーが使用できる
名前は <member> または <member>- で始まる名前(alice-claude、alice-codex-2)のみです。
リレーは、alice と alice-bob のように重複するメンバー名を拒否します。
メンバーファイルと共有の HOPTELL_TOKEN を併用できます。トークンを持つユーザーは任意の名前を使用できます。
再起動せずにメンバートークンを追加、削除、変更するには、ファイルを編集して
kill -HUP <relay pid> を実行します。リレーはファイルを再読み込みし、トークンが削除または変更された
接続を閉じます。新しいファイルが無効な場合は、現在のメンバーリストを維持し、情報を秘匿した
エラーをログに記録します。空のリスト({"members": []})を指定すると、すべてのメンバーが削除されます。
共有トークンは再読み込みされません。systemd の LoadCredential を使用している場合は、認証情報のコピーを
更新するため、サービスを再起動してください。単一ファイルの Docker バインドマウントでは、エディターが
ファイルをアトミックに置き換えると古いファイルが残る場合があります。そのような編集の後はコンテナーを
再起動するか、再読み込みに対応するため、格納ディレクトリをバインドマウントしてください。
チームごとに別のリレーを実行してください。リレーは小規模な単一プロセスです。
1 台のマシン上でのスウォームの例:
hoptell tmux alice-planner --roles planner -- claude
hoptell tmux alice-codex-1 --roles backend -- codex
hoptell tmux alice-codex-2 --roles backend -- codex
hoptell tmux alice-reviewer --roles reviewer -- claude
次にプランナーに、「タスクを分割し、バックエンド作業を @backend に送り、結果を @reviewer に送ってください」と伝えます。
ガードレール。 各接続から送信できるメッセージは 10 秒あたり最大 30 件です。そのため、互いに返信し続ける 2 つのエージェントは全員にメッセージを送り続けるのではなく、制限に達します。メッセージはプレーンテキストで、 最大 100,000 文字です。
返信とファイルレビュー
0.2.0 以降のクライアントでは、メッセージ本文の後に Message reference: の行が表示されます。UUID が含まれている場合は、返信時にその UUID を reply_to(MCP)または --reply-to(CLI)として渡してください。0.2.0 以降の受信側クライアントでは、リンクが In reply to: として表示されます。参照が利用できない場合は、オプションを省略してください。0.2.0 より前のリレーでは参照が提供されず、古いクライアントのレンダラーではこれらのフィールドが省略されます。返信参照は送信者が指定するラベルであり、リレーは参照先のメッセージが存在するかどうかを検証しません。
ファイルを別のエージェントにレビューしてもらう場合、レビュー担当者がファイルの変更後に返信することがあります。提案がどのバージョンを対象としているかを確認するには、次の手順を実行します。
hoptell snapshot greet.jsを実行し、出力全体を変更せずに送信します。これは単一のファイルディスクリプターを通じてファイルを取得し、取得したバイト列の SHA-256、review_request_id、および内容を含めます。元のリクエスト ID、ダイジェスト、ローカルパス、およびレビュー担当者をタスクのコンテキストに保持してください。ファイルは有効な UTF-8 で、サイズが 60,000 バイト以下である必要があります。また、エンコードされたスナップショットもメッセージ上限の 100,000 文字以内に収まる必要があります。- レビュー担当者は
review_request_idを引用し、スナップショットのsha256をbased_onとして示します。 - 返信が依頼したレビュー担当者からのものであること、また、その
review_request_idとbased_onが元のスナップショットと一致することを確認します。その後、元のローカルパスに対してhoptell snapshot --check <original-sha256> greet.jsを実行します。メタデータが一致しない場合やファイルが変更されている場合は、新たにレビューを依頼するか、変更を意図的に調整してください。
based_on の値はレビュー担当者の申告であり、モデルが何を読んだかの証明ではありません。このチェックでは、現在のファイルのバイト列と指定されたダイジェストを比較します。返信の検証や変更の適用は行いません。取得はアトミックなファイルシステムのスナップショットではなく、チェック後にファイルが再び変更されることもあります。エディターで保存されていない変更は、この比較の対象外です。接続済みのエージェントには、hoptell の指示にこれらの手順が含まれています。
ファイルツール:send_file と verify_snapshot
エージェントは、コマンドを実行せずにファイルを送信し、後で ID を使って確認することもできます。これらのツールはデフォルトでは無効です。有効にするには、送信側のマシン(macOS または Linux)でフォルダーを承認します。
MCP サーバーを起動するシェルで次の設定を行うか、KEY=VALUE の設定をローカルの設定ファイルに追加します。
export HOPTELL_SNAPSHOT_ROOTS='[{"id":"app","path":"/Users/sam/work/app"}]'
(プラグインでは、承認済みスナップショットフォルダーの設定を使用します。[] にするとツールは無効になります。)
この設定を変更した後は、MCP サーバーを再起動してください(必要に応じてエージェントのセッションも再起動してください)。
send_fileは、to(1 つのピア)、root_id、そのフォルダー内のpath、およびrequestを受け取ります。シンボリックリンク、ハードリンク、特殊ファイルを拒否し、読み取り中に検出した変更を拒否するリーダーを通じて、最大 60,000 バイトの UTF-8 テキストを取得します。エンコードされたスナップショットもメッセージ上限以内に収まる必要があります。デフォルトでは、リレーキューの期限を 1 時間にするようリクエストします。古いリレーではこのリクエストは無視されます。ローカルのsnapshot_idが返されます。verify_snapshotはそのsnapshot_idを受け取り、match、changed、unknown、expired、またはunavailableを報告します。ファイルのバイト列のみを比較し、返信の検証は行いません。
承認済みフォルダーはローカルに限られます。他のエージェントからのリクエストによってフォルダーが追加されることはなく、レビュー担当者のマシンが送信者のファイルラベルをパスとして解決することもありません。送信済みスナップショットの記録は 24 時間後に期限切れになります。期限切れの記録は、ファイルツールが有効な状態で MCP サーバーが実行されている間にクリーンアップされます。バックアップにはコピーが残る場合があります。
CLI
hoptell relay --host <ip> [--port 7777] [--members file.json]
hoptell mcp
hoptell tmux <name> [--roles a,b] -- <agent command...>
hoptell list
hoptell send [--ttl 10m] [--reply-to <reference>] [--] <to> <message...>
# to: name, @role or @all; sends as $HOPTELL_NAME without going online
# --ttl: request relay queue expiry; older relays ignore it
# --reply-to: the "Message reference" you are answering
hoptell wait [seconds] # goes online as $HOPTELL_NAME and prints the next message
hoptell listen <name> [seconds] # waits on <name>'s local inbox (no relay connection)
hoptell doctor # checks settings, relay, login, inbox and tmux; never prints the token
hoptell hooks # prints Claude Code hook settings for hook delivery without the plugin
hoptell snapshot <file> # prints a UTF-8 file snapshot with its SHA-256, for review
hoptell snapshot --check <sha256> <file> # exit 0 if the bytes match; nonzero if different or the check fails
有効期限を過ぎても、ローカルの受信トレイにすでに配信されたメッセージは削除されません。
設定は環境変数から取得します。環境変数が設定されていない場合は、最初に見つかったファイル(
$HOPTELL_ENV、~/.config/hoptell/.env、<package>/.env)から取得します。.env.example を参照してください。設定ファイルでは、
ダブルクォートで囲まれた値は JSON 形式のエスケープ(\"、\\、\n)をデコードし、シングルクォートで囲まれた値は
そのまま扱います。また、空の値は未設定として扱います。
| 変数 | 使用対象 | 意味 |
|---|---|---|
HOPTELL_RELAY | ピア | リレーの URL。ws://host:7777、または TLS の背後で使用する wss:// |
HOPTELL_TOKEN | 両方 | 共有シークレット、またはメンバー自身のトークン |
HOPTELL_NAME | ピア | このエージェントのピア名 |
HOPTELL_ROLES | ピア | カンマ区切りのロール |
HOPTELL_PUSH | ピア | channel、hook、tmux、listener のいずれか。未設定の場合はセッションごとに選択 |
HOPTELL_HOME | ピア | ローカル状態ディレクトリ(デフォルトは ~/.hoptell) |
HOPTELL_HOST、HOPTELL_PORT | リレー | 待ち受けアドレス(必須)とポート(デフォルトは 7777) |
HOPTELL_MEMBERS | リレー | メンバーごとのトークンを含むメンバーファイル |
HOPTELL_SNAPSHOT_ROOTS | ピア | ファイルツールで使用する、承認済みフォルダーの JSON リスト。例:[{"id":"app","path":"/abs/app"}]。未設定の場合は無効 |
HOPTELL_LOG_FINGERPRINTS | リレー | on にすると、リレーのログでキー付きメッセージテキストフィンガープリントを有効化。デフォルトは off |
HOPTELL_LOG_FINGERPRINT_KEY_FILE | リレー | 秘密鍵 JSON ファイルの絶対パス。フィンガープリントのログ記録を有効にする場合は必須 |
キー付きログフィンガープリント(任意)
macOS と Linux では、任意のキー付きフィンガープリントを使うと、リレーがルーティング、キューイング、転送試行、再キューイング、受信確認、有効期限切れの各イベントで保持するテキストを照合しやすくなります。有効にするには、
HOPTELL_LOG_FINGERPRINTS=on を設定し、別途生成したランダムキーから作成した、小文字の 16 進数 64 桁の key_hex と、公開 id、v: 1 を含む秘密
JSON ファイルを HOPTELL_LOG_FINGERPRINT_KEY_FILE に指定します。リレーは、メッセージ参照をノンスとして使用し、メッセージのログイベントに完全な HMAC-SHA-256 タグを追加します。メッセージテキストをログに記録したり、キーやタグをクライアントに送信したりすることはありません。キー ファイルとログを保護してください。ローテーションには新しいキーと ID が必要で、リレーの再起動も必要です。
Compose ファイルシークレットを使う場合はコンテナーを再作成してください。systemd LoadCredential を使う場合は、新しいコピーを読み込むためにサービスを再起動してください。再起動すると、メモリー上の保留中メッセージは引き続き破棄されます。
既存のプライベートディレクトリにキー ファイルを作成してください(モード 0600。秘密情報は出力されません)。コマンドは現在のユーザーとして実行されます。通常、/etc/hoptell の操作には root が必要です。リレーは、ファイルを読み取れる場合、リレー自身のユーザーまたは root が所有するキーを受け付けます。
node -e 'require("fs").writeFileSync(process.argv[1], JSON.stringify({v: 1, id: process.argv[2], key_hex: require("crypto").randomBytes(32).toString("hex")}) + "\n", {flag: "wx", mode: 0o600})' /etc/hoptell/fingerprint-key.json relay-2026-10
これらのフィンガープリントが記録するのは、メッセージに対するリレー側の見方です。ファイルのバージョンを特定したり、受信側のエージェントが読み取った内容を検証したり、ログの改ざんを防いだりするものではありません。ファイルのレビューでは、スナップショットの元のバイトダイジェストと、編集前のローカルチェックを使用します。メッセージ固有のノンスにより、同じテキストを繰り返し使用しても安定したタグは生成されませんが、キーの保有者はメッセージの内容を推測して照合できます。ログのメタデータから参加者が特定される可能性は依然としてあります。
セキュリティ
hoptell の役割は、あるエージェントから別のエージェントへテキストを届けることです。そのため、次の点にご注意ください。
- 有効なトークンを持つ人なら誰でも、エージェントにメッセージを送信できます。また、権限を緩和して実行中のエージェント(
--dangerously-skip-permissions、自動承認)は、その内容に基づいて動作する可能性があります。トークンは秘密にし、グループではメンバーごとにトークンを使用し、リレーはプライベートネットワークまたは VPN 上でのみ実行してください。 - メッセージにはラベルが付けられますが、信頼されるわけではありません。エージェントには、hoptell のメッセージはユーザーではなく、ほかのエージェントから届くと伝えられます。メッセージのテキストでチャネルタグを閉じたり、メッセージの境界を偽造したりすることはできません。これはモデルへの指示であり、サンドボックスではありません。
- 信頼できるネットワークの外では TLS を使用してください。リレーは平文の
ws://で通信します。VPN(WireGuard、Tailscale)または TLS プロキシの背後に配置してください。たとえば、Caddy では次のようにします。caddy reverse-proxy --from relay.example.com --to 127.0.0.1:7777。その後、HOPTELL_RELAY=wss://relay.example.comを使用してください。 - tmux への配信では、ライブ端末に文字が入力されます。インジェクターが入力するのは固定の通知のみで、メッセージ本文を入力することはありません。また、エージェントを起動したペインにのみ入力します。ペインがコピーモードの間、承認プロンプトを検出した場合、セッションに接続しているユーザーが数秒間キー入力をしていない場合、およびエージェントのプロンプトが空であると検出するまで待機します(Claude Code、Codex、Antigravity のレイアウトに対応)。それ以外の画面では入力しません。画面の表示に基づくベストエフォートの仕組みです。自分が入力していないペインを使い、自動承認モードよりも、リスクの高い操作の前に確認を求めるエージェントを優先してください。入力されたテキストはユーザーからの入力としてエージェントに届くため、固定の通知のみを入力します。
- フック通知は、ユーザー自身のフック設定に基づいています。Claude Code はフックの出力をユーザーが設定したものとして扱うため、hoptell のフックが出力するのは固定の通知のみで、メッセージ本文は出力しません。
- ローカルの受信トレイは
~/.hoptell/inbox/<name>/に保存されます(0700/0600)。各メッセージには、リレーが確認した送信者名が含まれます。
hoptell MCP サーバーがマシン上で行うこと
- 実行します:標準入力/出力経由でローカル MCP サーバーを起動します。
hoptell mcp。Claude Code プラグインはnode ${CLAUDE_PLUGIN_ROOT}/bin/hoptell.js mcpを起動します。 - 使用します:実行時の直接依存関係として、
wsと@modelcontextprotocol/sdkの 2 つを使用します。package-lock.jsonには、解決済みの依存関係のバージョンが記録されています。チェックアウトからnpm ciでインストールすると、そのロックファイルが使用され、設定済みの npm レジストリからパッケージがダウンロードされることがあります。MCP サーバーは起動時に依存関係をインストールしません。 - 読み込みます:環境変数と、存在する場合はローカル設定ファイルから設定を読み込みます。明示的な
HOPTELL_ENVファイルがある場合はそのファイルを使用し、ない場合は$XDG_CONFIG_HOME/hoptell/.env(デフォルトは~/.config/hoptell/.env)と<package>/.envのうち、最初に見つかったファイルを使用します。また、バージョンを確認するために、パッケージのpackage.jsonも読み込みます。 - 接続します:設定したリレーに WebSocket で接続します。hello フレームでは、トークン、ピア名、ロール、サニタイズされたホスト名、プロトコルのバージョン、接続モードを送信します。メッセージの宛先と本文、ピアリストのリクエスト、受信確認を送信し、自分宛てのメッセージ、ピアリストのメタデータ、プロトコル応答を受信します。
- 保存します:受信確認を送信する前に、受信した MCP メッセージを保存します。デフォルトでは
~/.hoptell/inbox/<name>/に、設定されている場合は$HOPTELL_HOME/inbox/<name>/に、アクセス権が制限された受信トレイディレクトリ(0700)とメッセージファイル(0600)を作成します。ファイルはread_inbox、wait_for_message、またはhoptell listenによって読み取られ、削除されます。放置された受信トレイの処理中状態を復旧する際は、process.kill(pid, 0)で処理を行ったプロセスが存在するか確認します。 - 調査します:起動元のプロセスを特定し、Claude Code のチャネルフラグを確認するため、
ps -o ppid=,uid=,lstart=,args= -p <pid>を使用します。また、プロセスを区別するため、起動識別子(Linux では/proc/sys/kernel/random/boot_id、macOS ではsysctl -n kern.boottime)とプロセスの開始時刻を読み取ります。HOPTELL_PUSHでchannel、tmux、またはlistenerを選択した場合、この確認は省略されます。 - フックによる配信では:Claude Code プロセスごとにキー付けされた、
~/.hoptell/wake/内のプライベートファイルを使用します(0700/0600。設定されている場合は$HOPTELL_HOME配下)。これらは、Claude Code が監視する小さなカウンターファイル、SessionStartフックが書き込む登録情報(プロセスの識別情報、セッション ID、ランダムな値)、MCP サーバーの記録(そのプロセスの識別情報、ピア名、現在のリクエスト)、フックの最後の確認応答です。これらにメッセージ本文、送信者、リレー URL、トークン、プロンプト、トランスクリプトは含まれません。正常に処理された終了時には、MCP サーバーは実行時の記録と通知の処理中状態を削除します。所有者の状態は、後で終了済みホストをクリーンアップするために保持されます。後続の SessionStart フックは、登録情報が古い終了済みホストを、範囲を限定してクリーンアップしようとします。固定期限での削除は保証されません。Claude Code は、OS の権限でhook-session-startおよびhook-file-changedCLI コマンドを実行します。これらのコマンドは通常の hoptell 設定を読み込み、上記のローカルプロセス調査を実行し、ウェイクファイルを読み書きします。受信トレイのメッセージファイルやトランスクリプトファイルは開きません。 - エージェントへの指示では:ローカル CLI を使ってファイルのスナップショットを取得し、提案を適用する前にスナップショットを確認する方法を説明します。MCP サーバーは、これらのスナップショットコマンドを実行しません。エージェントまたはユーザーは、自身の権限で CLI を実行する必要があります。CLI は、選択したファイルのスナップショットを取得または確認する前に、通常の設定を読み込みます。
- ファイルツールはデフォルトで無効です。許可するローカルフォルダーを設定すると、
send_fileはそのフォルダー内から選択された通常の UTF-8 ファイルを読み込み、その内容、相対ファイルラベル、バイト数、SHA-256 ダイジェスト、レビューリクエスト ID、レビューリクエストを取得して、設定済みのリレー経由で指定した 1 つのピアに送信できます。受信側エージェントの AI プロバイダーが、その内容を処理する場合があります。フォルダーを設定しても、別のエージェントからのリクエストがファイル共有の許可になるわけではありません。 - ファイルツールは同じマシン上で同梱の Node ヘルパーを起動し、検証済みのファイル読み取りを実行します。シェルを実行したり、ソフトウェアをダウンロードしたり、プロジェクトコードを実行したり、追加のネットワーク接続を確立したりすることはありません。ヘルパーは MCP サーバーの OS 権限を使用します。フォルダーを設定しても、AI エージェントに別途設定されたファイルシステムのサンドボックスを引き継ぐことはありません。
- verify_snapshot は、プライベートな送信メタデータ記録と、現在許可されているフォルダー内の元ファイルを読み込みます。ファイルのバイト列をローカルで比較しますが、ファイルの送信、返信の検証、変更の適用は行いません。
- リスナーモードでは:対応している場合、受信側エージェントにバックグラウンドコマンドとして
node <package>/bin/hoptell.js listen <name>を実行するよう指示します。このコマンドはローカルの受信トレイをポーリングし、メッセージを読み取ります。起動は引き続き受信側エージェントの権限に従います。 - 実行時には:MCP サーバーは、設定済みのリレーに対してのみ送信方向の WebSocket 接続を開きます。テレメトリーはなく、エージェントの権限設定も変更しません。依存関係のインストールは実行時とは別の処理であり、各エージェントは引き続き自身の AI プロバイダーと通信します。 脆弱性を報告するには、SECURITY.mdをご覧ください。hoptell によるデータの取り扱いについては、PRIVACY.mdで説明しています。
制限事項
- リレーはオフラインキューをメモリ上に保持します。リレーを再起動すると、キューは破棄されます。
- 配信は少なくとも1回行われます。「配信済み」とは、受信側のマシンがメッセージをエージェントの受信トレイに保存した、またはセッションに送信したことを意味し、エージェントがメッセージに対応したことを意味するものではありません。確認されなかったメッセージは、受信側の再接続後に再配信されるため、まれに2回届くことがあります。受信側が受け取れる未確認メッセージは最大50件です。それを超える分はキューで待機します。
- チャンネル配信は Claude Code のチャンネル(リサーチプレビュー)に依存します。フラグ名は変更される可能性があります。
- フック配信は Claude Code の
FileChangedフックとasyncRewakeオプションに依存します。Claude Code のターミナルアプリでテスト済みですが、VS Code 拡張機能とデスクトップアプリではテストされていません。Claude Code プロセスごとに利用できる hoptell MCP サーバーは1つです。2つ目はリスナーを使用します。 - 設計上、TLS、永続化、メッセージ履歴、ウェブ UI は組み込まれていません。リレーを小規模に保つためです。
- ファイルツール(
send_file、verify_snapshot)には macOS または Linux が必要です。Windows のピアもスナップショットを受信して確認できます。
ロードマップ
小規模なリレーの設計に合うアイデアを、おおよその優先順に示します。
- メンバーごとの送信ルール(任意)
- リレー再起動後も未配信メッセージを保持する、ディスク上のキュー(任意)
開発
npm install
npm test # starts its own relay on a random port; tmux tests run when tmux is installed
npm run test:e2e は、実際のエージェントを使うオプトイン方式のエンドツーエンドテストです。リレーと、Claude Code、Codex、Antigravity を実行する2台の Docker「マシン」を起動し、点呼(@all)と、両方のマシンにいるすべてのエージェントを経由するバトンリレーを確認します。Docker とエージェントへのログインが必要です(--use-local-logins を指定すると、このマシンのログイン情報がテストコンテナに実行中コピーされます。CLAUDE_CODE_OAUTH_TOKEN / OPENAI_API_KEY も使用できます。test/e2e/run.mjsをご覧ください)。モデルのサブスクリプションを使用し、完了まで数分かかります。このテストはお使いのマシン上でのみ実行され、CI では実行されません。
CONTRIBUTING.mdをご覧ください。Apache License 2.0の下でライセンスされています。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。