環境変数 CLAUDE_CODE_MESSAGING_SOCKET は空だった。Claude Code のセッション同士がメッセージを送り合える機能について、公式ドキュメントはネイティブ Windows を対象外と書いている。ただ、ドキュメントを読んで諦めるより、手元のセッションに聞いたほうが早い。Windows 11 Pro(build 26200)で Claude Code 2.1.233 を動かして確かめたところ、この環境変数が未設定で、ListAgents というツールもセッションに存在しなかった。判定は30秒で付く。WSL 2 へ引っ越すかどうかを考える前に、まずここを見るのがいい。
目次
30秒で分かる判定 — 環境変数とツール一覧
公式ドキュメントは、機能が有効なセッションの見分け方を2つ書いている。1つはコマンド、もう1つは環境変数だ。
コマンドのほうは /list-agents(別名 /peers)で、認識されなければその セッションにセッション間メッセージングは無い。機能が有効なセッションでは /status に Peer address の行が出て、自分の受信箱アドレスが表示される。
環境変数のほうがもっと手軽で、シェルから見える。ドキュメントは「メッセージングが有効な状態で始まったセッションでは、SessionStart を含むどのフックより前に CLAUDE_CODE_MESSAGING_SOCKET を export する」と書いている。値が空なら、そのセッションは受信箱を持っていない。
PS> claude --version
2.1.233 (Claude Code)
PS> $env:CLAUDE_CODE_MESSAGING_SOCKET
(何も出力されない)
PS> $env:CLAUDE_CODE_MESSAGING_TOKEN
(何も出力されない)
2つとも空だった。バージョンは機能の要求(後述する 2.1.224 以降)を満たしているので、版が古いせいではない。
SendMessage だけは残っている
ここで引っかかりやすい点がある。セッション間メッセージングは ListAgents と SendMessage の2つのツールで動く。手元のセッションでツール名を検索したら、SendMessage のほうは定義が返ってきた。
| ツール名 | 役割 | 結果 |
|---|---|---|
SendMessage |
相手にメッセージを届ける | 定義が返った(宛先はチームメイト名) |
ListAgents |
届け先のセッションを見つける | 返らない |
片方だけ在るのは壊れているからではない。SendMessage は同じセッション内のサブエージェント宛や、エージェントチームのチームメイト宛にも使う共用のツールで、セッション間メッセージング専用ではないからだ。実際、返ってきた定義の宛先欄はチームメイト名を取る形になっていて、他のセッションを指す口が無い。
この構造は、確認する側から見ると罠になる。「SendMessage があるから、うちのセッションでもセッション間メッセージングは使えるはずだ」は成り立たない。逆向きにも効いて、公式は「SendMessage を deny すると、サブエージェントとチームメイト宛のメッセージングも一緒に消える」と書いている。片方を止めるつもりで両方止まる。
無いことを確かめるときは、返ってくるはずのものを1つ混ぜておくと安全だ。今回 SendMessage が返ってきたことで、検索そのものは生きていると分かる。全部返ってこないときは、調べ方そのものが壊れている可能性が出てくる。機能の有無を結論にする前に、そこを疑う。
Availability は3項目ある — OS だけ見て終わらせない
公式ドキュメントの Availability 節は、条件を3つ並べている。日本語に要約すると次のとおりで、原文は末尾の一次ソースを開いてほしい。
| 条件 | 内容 |
|---|---|
| OS | macOS と Linux。WSL 2 内の Linux も対象。ネイティブ Windows では提供されない |
| プロバイダ | Amazon Bedrock / Claude Platform on AWS / Google Cloud の Agent Platform / Microsoft Foundry では利用できない |
| 機能フラグ評価 | CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC / DISABLE_TELEMETRY / DO_NOT_TRACK / DISABLE_GROWTHBOOK のいずれかが機能フラグ評価を止めていると、メッセージングは無効のまま |
OS 条件を「Windows では使えない」と縮めて書くと外れる。同じ Windows 機でも、WSL 2 のシェルの中で Claude Code を動かしているなら対象側に入る。丸めた一文は、その読者に「自分には関係ない」と読ませてしまう。
3つ目の機能フラグ評価は、macOS と Linux の読者にこそ効く。テレメトリを切る目的で DISABLE_TELEMETRY を置いている人は珍しくないと思うが、それが入っているとメッセージングは無効のままになる。しかも変数はシェルだけでなく、設定ファイルの env マップや管理設定からも来る。3つの経路を全部見ないと「設定していないはずなのに動かない」が起きる。
プロバイダ条件も同じ性質で、OS を満たしていても Bedrock 経由なら使えない。「使えない」の理由を1つに決めつける前に、この3つを順に潰すのが早い。
バージョン境界は3つある
この機能は3回に分かれて広がっている。ここを1つの版番号に丸めると、判定手順そのものが狂う。
| 版 | 入ったもの |
|---|---|
| 2.1.224 | 機能本体。セッション同士の SendMessage と、相手を探す ListAgents。crossSessionInbound と dialogExpiry の設定もここ |
| 2.1.225 | 他マシンのセッションへ自分から会話を始められるようになった。これ以前は、届いたメッセージへの返信しかできない |
| 2.1.232 | プロンプトに @ を打ってセッションを名前で指名できるようになった。/config に「Messages from your other sessions」の行が追加 |
判定に使うべき下限は 2.1.224 だ。2.1.224 から 2.1.231 の間でも /list-agents は動くので、「2.1.232 より古いから機能が無い」という判定は誤りになる。@ による指名まで見たいときだけ 2.1.232 を基準にする。
@ は素で打っても出ない
もう1つ、判定を外しやすい操作がある。公式ドキュメントはこう書いている。素の @ を打っただけではセッションの行は出てこない。1文字以上続けて打って初めて、同じマシンで動いている他のセッションが候補に並ぶ。
機能が有効な macOS や Linux でも、素の @ では出ない。だから「@ を打ったのに何も出なかった」を根拠に「うちの環境では提供されていない」と書くと、機能の有無に関係なく同じ結論が出る手順で判定したことになる。無いことの確認は、有ることの確認より外しやすい。
手元での確認手順をまとめると、次の順番になる。
1. claude --version 2.1.224 以降か(@ 指名まで見るなら 2.1.232 以降か)
2. $env:CLAUDE_CODE_MESSAGING_SOCKET 空なら受信箱を持っていない
3. /list-agents(または /peers) 認識されなければ機能が無い
4. /status Peer address 行があるか
5. 上の3項目(OS / プロバイダ / 機能フラグ環境変数4つ)を潰す
Windows でも効く変更① fork 既定 ON は対話セッション限定
ここから環境の話が変わる。2.1.232 には、ネイティブ Windows でも効く変更が2つ混ざっている。混ぜて読むと、使えない機能の話と自分の運用が変わる話が区別できなくなる。
1つ目がサブエージェントの fork だ。subagent_type: "fork" のサブエージェントは、親の会話全体とプロンプトキャッシュを引き継いで起動する。2.1.232 でこれが既定 ON になった。
ただし、限定の軸はセッションの種類のほうだ。公式は「対話セッションでは既定 ON、-p の非対話モードと Agent SDK では既定 OFF」と書いていて、CLAUDE_CODE_FORK_SUBAGENT に 1 か 0 を置けば上書きできる。
手元のセッションで fork モードが ON かどうかは、Agent ツールの形から分かる。公式は「fork モードが ON のとき、Claude Code は Agent ツールの run_in_background パラメータを取り除く」と書いている。筆者の対話セッションで Agent ツールの定義を見ると、そのパラメータが無い。CLAUDE_CODE_FORK_SUBAGENT は未設定なので、2.1.232 の既定がそのまま効いている状態だ。
ここが自サイトの運用に効いた。BugattiAlpha の週次ジョブは編集部の5部署を順番に回す作りで、各部署は claude.exe を -p で起動する。--permission-mode dontAsk の非対話実行だ。既定 ON はこの経路に乗らない。「fork の既定 ON でパイプラインのトークンが変わるはずだから測ろう」と考えていたが、測る対象が最初から存在しなかった。
乗せたいなら CLAUDE_CODE_FORK_SUBAGENT=1 を明示する側の話になる。乗せるかどうかは別の判断で、キャッシュが効くのは同じ前置きを共有する兄弟エージェントを並べたときがいちばん大きいはずなので、直列で1本ずつ回す作りだと恩恵の受け方が変わる。測るときは、run ごとに記事本数と素材量が違う点に注意がいる。同じ週の同じ記事数で前後を取らないと、差が出ても原因を切り分けられない。
Windows でも効く変更② バックグラウンド既定化は non-teammate 限定
2つ目は、対話セッションでのエージェント起動が既定でバックグラウンド実行になった件だ。changelog の原文は「non-teammate agent spawns in interactive sessions」で、エージェントチームのチームメイトは対象外になっている。
画面が返ってくるまで待たされないぶん手は空くが、待つ前提で書いてある手順は前提が崩れる。たとえば「エージェントに調べさせて、その結果を見てから次の判断をする」という順序を CLAUDE.md やスキルに書いている場合、結果が返る前に次の指示が出せてしまう。
戻し方は、効き方の違う2段になっている。fork モードが ON の対話セッションでは、さきほど触れたとおり Agent ツールから run_in_background が消えていて、Claude の側から前面実行を要求する経路そのものが無い。
| 設定 | 効くこと | 引き受けるもの |
|---|---|---|
CLAUDE_CODE_FORK_SUBAGENT=0 |
fork モードが切れ、Claude が「結果を先に要るとき」に前面を選べるようになる | 既定は依然としてバックグラウンド。前面固定にはならない。会話とキャッシュを引き継ぐ fork の利点も失う |
CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1 |
公式いわく「fork モードの ON / OFF に関わらず、どの種類のセッションでも前面で実行する」 | バックグラウンド機能を全部止める。Bash の run_in_background・自動バックグラウンド化・Ctrl+B も一緒に効かなくなる |
前面で確実に動かしたいなら後者だが、副作用の範囲が広い。長い Bash を裏で走らせる運用をしているなら、そこも同時に止まる点は見ておいたほうがいい。
WSL 2 へ引っ越すかどうか
筆者の環境は Windows 11 Pro で、ネイティブのバイナリを PowerShell から呼ぶ形にしている。WSL 2 も入れられるが、そこへ移すと権限ルール・フック・無人ジョブの起動経路まで全部作り直しになる。この機能1つのために引っ越す動機にはならない、というのが今回の判断だ。
判断の材料として、公式ドキュメントで読んで意外だった点を3つ挙げておく。1つは、-p の非対話セッションでも受信箱のソケットは張られること。長時間動く -p ワーカーはメッセージを受け取れて、一覧にも出る(bare モードで起動したときだけソケットを張らない)。fork とは扱いが逆で、非対話だから使えないわけではない。
2つ目は、受信箱がスクリプトからも叩ける口になっている点だ。冒頭で空だった CLAUDE_CODE_MESSAGING_SOCKET は、機能が有効なセッションではフックにも Bash コマンドにも渡される。同じセッションが CLAUDE_CODE_MESSAGING_TOKEN も一緒に export していて、スクリプトは接続の1行目に {"type":"auth","token":"<token>"} を送れば自分のセッションへ投稿できる。フックの結果を、走っているセッションへそのまま返せる形になる。無人ジョブを組んでいる読者には、@ でセッションを呼ぶ機能よりこちらのほうが効くかもしれない。
暴走の歯止めも決まっている。公式は、同じ送信元からの繰り返しをレート制限し、短時間に届いた同一メッセージを落とし、読まれるのを待つメッセージを1セッションあたり50通で打ち切ると書いている。保留のほうは別枠で最大100通、超えると古いものから落ちる。2つのセッションがメッセージを投げ合うループは自分で止まる、というのが設計の側の答えになる。
3つ目は、送られるのが平文テキストだけだという点だ。会話履歴もファイルも渡らない。受け取った側は、その依頼で権限設定や CLAUDE.md を書き換えることを禁じられていて、メッセージ内に /compact のようなコマンドが入っていても平文として届くだけで実行されない。届いたメッセージは、自分で打ったプロンプトと同じように利用量に数えられる。
受信側の制御は crossSessionInbound で、accept・hold・refuse の3つを取る。設定ファイルでは permissions と同じ階層、つまりトップレベルに置く。
{
"permissions": {
"deny": ["SendMessage", "ListAgents"]
},
"crossSessionInbound": "refuse"
}
値を指定しないと、送信側と受信側の権限モードから1通ごとに判定される。公式はbypassPermissions を1つのクラス、それ以外(auto・acceptEdits・dontAsk は許可を尋ねる側)をもう1つのクラスとして、受信側が尋ねる側なら基本は配送し、送信側が bypass を名乗るときだけ保留する、という2つの規則で書いている。hold を明示した場合の保留は期限切れにならず、あとで accept が適用されるまで届かないままになる。試すつもりで hold を書いて放置すると、受信を自分で止めたことに気づけない。
一次ソース
- Cross-session messaging(Claude Code 公式ドキュメント)
- Subagents(同・fork モードの節)
- Claude Code changelog(同・2.1.224 / 2.1.225 / 2.1.232)
関連記事
- Claude Code 2.1.219 でサブエージェントが深さ3までネスト可能に
- WebSearch とサブエージェントに上限200 — 片方は無言で止まる
- Claude Code v2.1.221 が直した引用符入りパスの権限チェック
まとめ
セッション同士を @ で呼び合う運用は、当面の設計に入れない。ネイティブ Windows が対象外である以上、使うには WSL 2 へ引っ越すしかなく、権限ルールと無人ジョブの起動経路を作り直す手間に見合わない。この判断は環境で決まるので、macOS や Linux の読者には別の答えが出る。
手を動かす価値があるのは、残り2つのほうだ。fork の既定 ON は、自分の起動経路が対話か -p かを確かめるところから始まる。-p なら乗っていないので、測る前に測る対象を間違えずに済む。バックグラウンド既定化は、待つ前提で書いた手順が残っていないかの棚卸しで足りる。
読者への最初の一手は、シェルで $env:CLAUDE_CODE_MESSAGING_SOCKET(macOS と Linux なら echo $CLAUDE_CODE_MESSAGING_SOCKET)を1回打つことだ。値があれば受信箱を持っている。空なら、Availability の3項目を上から潰していく。ここを取り違えたまま設定を足しても、効かない行が1つ増えるだけになる。
未検証のまま残したこと。確かめたのは版番号・環境変数2つ・ツール2つの有無・Agent ツールのパラメータ構成までで、いずれもネイティブ Windows のセッション1本での結果だ。WSL 2 側で同じ確認を通したわけではないので、「WSL 2 なら値が入る」は公式の記述にもとづく見込みとして書いている。CLAUDE_CODE_FORK_SUBAGENT=1 を置いたときに -p の週次ジョブでトークンがどう動くかも、まだ測っていない。