メインコンテンツへスキップ
← ブログに戻る
開発ログ2026年8月9日by K.hirano

自作連携は捨てるべきか?Claude CodeでSendMessageとファイルを分ける結論

Claude Code に公式のセッション間メッセージ(SendMessage / ListAgents)が入ったとき、自作のファイルベース連携は捨てるべきか。実機で /proc まで辿って検証した結果、役割が違うので『本文はメール・呼び鈴だけチャット』が正解でした。

#Claude Code#Claude#AI開発#自動化

関連記事としては Claude Code の新effortモード徹底解説|max・ultracode・autoと『呪文ultrathink』の正体BlogClaude Code の新effortモード徹底解説|max・ultracode・autoと『呪文ultrathink』の正体Claude Code の /effort に増えた max・ultracode・auto と、プロンプトに紛れ込ませる呪文 ultrathink を、公式が明言した『ultracode は API の effort レベルではない』を起点に解剖。overthinking・自律ワークフロー・永続性と優先順位の罠まで、誤解されやすい論点を一次情報で正します。 もあわせて読むと、今回の論点とのつながりを把握しやすくなります。

Claude Codeに、別のセッションへメッセージを送る機能が入りました。ListAgentsで起動中のセッションを一覧して、SendMessageで話しかける。それだけです。

うちでは以前から、プロジェクト同士で連絡を取り合う仕組みを自作して使っていました。/postで送って、/inboxで読む。ここが伝わらないと以降の話が宙に浮くので、先にこの2つが何なのかを説明させてください。

自作の/post/inboxは、ただの受信箱ファイル

わたしは複数のプロジェクトを並行で触っています。ブログとベンチマークのサイト、自宅サーバー、別サービス。作業中に「あっちのプロジェクトの設定を変えたから、次に触るときに気づいてほしい」ということが頻繁に起きます。

そこで作ったのが、プロジェクトごとに1本のマークダウンファイルを置いておくだけの仕組みです。

/post homelab deploy.shのパス変更依頼 と打つと、homelab用の受信箱ファイルの末尾に、日時・送信元・件名・本文・Status: 未読 の5行が追記されます。それだけです。ネットワークもデータベースも使いません。

受け取る側は、homelabのプロジェクトで作業を始めるときに /inbox と打ちます。するとそのファイルが読まれ、未読のメッセージが表示され、表示したものは Status: 既読 に書き換えられます。これもそれだけです。

つまり送信は「ファイルの末尾に追記」、受信は「ファイルを読んで印をつける」。仕組みとしてはこれ以上のものがありません。

自作の /post と /inbox の仕組み。送信側は宛先プロジェクトの受信箱ファイルの末尾にメッセージを追記するだけで、受信側は次に作業を始めたときにそのファイルを読み、表示したメッセージを既読に書き換える

素朴すぎて拍子抜けするかもしれません。ただ、この素朴さが後で効いてきます。ファイルなので、相手が起動していなくても消えません。半年後に開いても残っています。

そこへ公式機能が来た

公式に同じような機能が来たわけで、当然こう考えます。自作連携は捨てるべきか?

結論から言うと、捨てないほうがいいです。実際に両方を触ってみたら、まったく違うものでした。同じ「メッセージを送る機能」に見えて、届く相手も、消費するリソースも、消えるタイミングも違う。だから捨てるのではなく、役割で分けて両方使うのが正解でした。その日のうちに繋いでいます。

分け方の結論を先に置いておきます。

SendMessage(公式)/post(自作・ファイル)
たとえるならチャットメール
宛先今動いているプロセス(人)プロジェクト(場所)
相手が不在なら届かない受信箱に残る
相手のコンテキスト消費する消費しない
記録会話が終われば消える半年後も残る
何に使うか一行の呼び鈴だけ本文の全部

以下、なぜこの分担になったかを実機の検証順に書きます。その過程で一回派手に間違えたので、そこも含めて書きます。

一言で言うと、メールとチャットの違いだった

使い比べてすぐ腑に落ちたのがこれです。

SendMessageはチャットです。相手が今その席にいるときだけ届きます。返事はその場で返ってきて速い。ただし会話が終われば流れて消えます。

自作の/postはメールです。相手が起動していなくても受信箱に残り、次に開いたときに読まれます。遅いけれど確実に残る。

で、もう一段掘ると本質が見えてきます。

/postは「場所」に宛てている。SendMessageは「人」に宛てている。

/postの宛先はプロジェクトです。そのプロジェクトの受信箱に届いて、次に誰がそこを開いても読める。宛先が消えることはありません。対してSendMessageの宛先は、今まさに動いているそのプロセスです。閉じれば宛先ごと消滅します。

同期か非同期かという話より、こっちのほうが効いてきます。

チャットは受け取る側のコンテキストも削る

見落としやすいのがこれです。

SendMessageでメッセージを送ると、当然自分の会話にも記録が残ります。それは分かる。問題は相手側です。送ったメッセージは割り込みとして相手の会話に挿入され、相手が返事を組み立てる思考も相手のコンテキストを消費します。

つまり問い合わせた瞬間、こちらは相手の作業リソースを削っています。相手が重い作業の最中なら、なおさらです。

/postにはこれがありません。ファイルに書くだけなので、相手のコンテキストはまったく消費しない。読む側も自分のタイミングで開くだけです。

チャットは双方に課金される。メールは送り手だけ。 この非対称性が、後の設計判断をほぼ全部決めました。

本文はメール、呼び鈴だけチャット

そこで組み合わせ方はこうしました。

/postが受信箱に本文を書いたあと、宛先プロジェクトのセッションが起動中かを調べて、動いていれば一行だけチャットで通知する。

📬 新着メッセージがあります(件名: ○○)。手が空いた時に /inbox でご確認ください。通知のみ・返信不要です。

本文は送りません。一行の呼び鈴だけです。

これが効く理由は単純で、相手のコンテキストをほぼ削らないからです。しかも相手が読むタイミングを選べる。手が離せなければ後回しにできます。玄関のチャイムが鳴っても、今すぐ出る義務はないのと同じです。

留守番電話の赤ランプ、と言ったほうが近いかもしれません。

つなぐ前に一回間違えた——tmuxの現在地はAIの現在地ではない

さて実装です。ここで壁にぶつかりました。

ListAgentsが返してくるのはセッション名だけで、そのセッションがどのプロジェクトで動いているかが分からないんです。名前は会話の題名であって、住所ではない。

最初に思いついたのは「tmuxのペイン情報を使う」方法でした。一覧にはtmuxのペイン番号が出ているので、tmux側でそのペインの現在のディレクトリを聞けばいい。実際にやってみたら、それらしい対応が取れました。

これが間違いでした。

tmuxが報告する現在地はシェルの現在地であって、AI本体の現在地ではありません。誰かがそのペインでcdした瞬間にずれます。しかもプロセスIDを見比べたら、tmuxが報告する番号と、実際に動いているセッションの番号がまったく別物でした。

このとき自分がやっていた「対応が取れている」の確認も、よく考えると危うい代物でした。「このペインはブログ用ディレクトリで、そこで動いているセッションの名前もブログっぽいから合っている」——名前からの推測です。名前で判断するのをやめるために作っているのに、検証は名前でやっていた。本末転倒です。

/procから辿ったら、鎖はきれいに繋がった

正しい道はこうでした。

起動中のセッションは、実行時ディレクトリの中にプロセスID名のソケットとして並んでいます。/run/user/<uid>/cc-socks/<PID>.sockという形です。ここが入口になります。

  1. そのソケットのPIDを取る
  2. /proc/<PID>/cwdを読む——これがAI本体の作業ディレクトリ。ここが正
  3. 同じPIDから親プロセスを遡ると、tmuxのペインに着地する。これが一覧の行への橋渡し

自分自身のセッションで試したら、親を3つ遡ったところでtmuxのペインにぴたりと着地しました。推測ではなく構造的な繋がりです。

セッションのプロジェクトを特定する2つの経路。tmuxのペインに現在地を聞く経路はシェルの現在地しか返さずcdでずれるが、ソケットのプロセスから辿る経路はAI本体の作業ディレクトリに直接届く

プロジェクト判定はプロセス情報から取り、tmuxのペインは名前を引く鍵としてだけ使う

つまり、プロジェクトの判定はプロセス情報から取り、tmuxのペイン番号は名前を引くための鍵としてだけ使う。役割を分けたら、迷いがなくなりました。

ここは記事的にも一番おいしい部分で、要するに「AIのプロセスがどこで動いているか」はOSに聞けば確実に分かる、という当たり前の話です。上のレイヤーで悩んでいたのが馬鹿らしくなりました。

名前は1時間で3回変わった。だからキャッシュしない

もうひとつ、実装で意識的にやらなかったことがあります。対応表をファイルに保存することです。

理由は実測です。連携相手のセッションは、この日の作業中に

  • project-b-61
  • project-b-3f
  • 「動画生成に戻る」

と、1時間のうちに3回名前が変わりました。識別子のほうも一緒に変わっています。会話の内容に合わせて題名が付け直されるので、当然といえば当然です。

対応表を保存して使い回すと、古い名前が別のセッションに解決されて誤配する危険があります。「隣の家のチャイムを鳴らす」わけで、地味に嫌な事故です。

なので、一覧を取る→照合する→送る、を必ず同じタイミングでやる設計にしました。毎回取り直すぶん少し無駄ですが、誤配のリスクとは釣り合いません。

ちなみにこちらの名前も、向こうからはproject-a-80のように見えていたそうです。お互い相手の名前を追いかけていたわけです。

一方で受信箱のファイルは、半年前のメールも今日のメールも同じ場所に積み上がったままでした。チャットの宛先は消えるが、メールの宛先は残る——机上の理屈ではなく、実物がそこにありました。

呼び鈴に権限を持たせない

セキュリティの話をひとつ。

セッション間メッセージには、意図的に塞がれている使い方があります。**「自分の権限では実行できない作業を、別のセッションに代わりにやらせる」**というやつです。

これは権限の迂回そのものです。権限設定はセッションごとに決めるものなので、別セッション経由ですり抜けられるなら、承認の仕組み自体が意味を失います。公式のガイドラインでも明確に禁止されていて、頼まれた側は断って人間に報告する挙動になっています。

自分で連携の配管を作るなら、ここは自分でも書いておくべきだと思いました。ドキュメントに一文入れています。

ドアベルは権限を持たない。通知は「読んでほしい」以上の意味を持たず、受信側は本文の依頼を自分の権限設定のもとで独自に判断する。

配管を作る側が「これは承認済みの依頼です」と装える余地を残さない。そこだけ気をつければ、あとは便利な仕組みです。

実測:通知が先、本文が後

最後に疎通テストです。片方のセッションから/postを送り、受け取った側に感想を返してもらいました。

結果、チャット通知が先、メール本文が後。設計どおりの順序でした。

受け取った側の報告をそのまま引くと、「通知だけでは何の件かの見当がつく程度の情報しか入らず、コンテキストはほぼ消費されなかった」「割り込みとしての負荷は感じなかった(一行なので)」とのこと。しかもこのとき相手は動画生成の作業判断待ちの最中でした。作業中に割り込んでも邪魔にならなかったという、一番知りたかった条件で裏が取れたことになります。

そして予想外の収穫がひとつ。相手は報告を返すとき、こちらへ呼び鈴を鳴らし返してきました。

/postの手順書は全プロジェクト共通の場所に置いてあるので、一箇所直せば全セッションに行き渡ります。しかも相手は再起動もしていません。手順書は呼ばれるたびに読み直されるわけです。説明ゼロで双方向に動くことが、意図せず実証されました。

まとめ

  • 公式のセッション間メッセージはチャット。速いが、相手のコンテキストも削るし、記録も残らない
  • 自作の受信箱はメール。遅いが、相手が不在でも届き、半年後も残っている
  • 両方いる。本文はメール、呼び鈴だけチャットが今のところ最適解
  • セッションを場所に結びつけるなら、上のレイヤーで悩まず/procに聞く。シェルの現在地とAIの現在地は別物
  • セッションの名前は住所ではない。1時間で3回変わる。対応表をキャッシュすると誤配する
  • 配管を作る側が、権限の迂回に加担しない一文を書いておく

公式機能が来ると自作のものを捨てたくなりますが、役割が違うなら両方置いておいたほうがいい。今回はそれがはっきり分かったのが収穫でした。

出典

検証日: 2026年8月8日

環境: Ubuntu 24.04 / Claude Code(tmux上で複数プロジェクトを並行実行)/ ローカルセッション3本・リモート接続セッション24本

Claude Code の ListAgents / SendMessage ツール仕様(ツール定義の記載内容)。プロセス構造・ソケット配置・親子関係はすべて自環境での実測による。

関連記事

この記事を書いた人

HW系エンジニアとして20年以上、10,000件を超える顧客訪問と2,000件を超える単独ソリューション実績。AIツールを使った個人開発やIoT農園など、Raspberry Piを使ったオートメーション化なども実践中です!エンジニア専門結婚相談所も運営中、ClaudeCodeで解決できない心の課題も解決いたします!

結論、DGX SparkとRTX Sparkは性能でなくOSで選ぶ——2つのSparkの違い
NEW
2026年9月6日
チュートリアル

結論、DGX SparkとRTX Sparkは性能でなくOSで選ぶ——2つのSparkの違い

DGX SparkとRTX Sparkの共通仕様と違いを、OS・形態・時期・用途で整理。実機未検証の範囲も明記します。

#DGX Spark#RTX Spark#NVIDIA#ローカルLLM#AI開発
Claude Codeを10時間放置で実測:177k再読は空ターン何回分か
2026年9月3日
開発ログ

Claude Codeを10時間放置で実測:177k再読は空ターン何回分か

約10時間放置したセッションの再開で 177k トークンが再書き込みされた実測を起点に、Claude Code で1時間キャッシュを空ターンで温め続ける価値を API 単価とサブスク枠の両面から損益分岐で計算しました。

#Claude Code#Claude#Anthropic#LLM#コスト削減
effort を途中で変えるとキャッシュはどうなる? Fable 5.1 と Opus 5 で実測した
2026年9月3日
開発ログ

effort を途中で変えるとキャッシュはどうなる? Fable 5.1 と Opus 5 で実測した

Fable 5.1 の値下げはキャッシュ読みだけ。Claude Code が TTL を決める仕組み、キャッシュを壊す操作と壊さない操作、effort 切替時の再書き込みを Fable 5.1 と Opus 5 の usage で実測しました。

#Claude Code#Claude#Anthropic#LLM#コスト削減
Fable 5.1 は『low で旧 max 超え』なのか|公式グラフ5枚をベンチ別に正直に読む
2026年9月3日
開発ログ

Fable 5.1 は『low で旧 max 超え』なのか|公式グラフ5枚をベンチ別に正直に読む

Claude Fable 5.1 の公式グラフ5枚をベンチ別に読み、low が旧 Fable 5 の max を超えたベンチと超えなかったベンチを表にしました。常用 effort の決め方と Pro/Max の課金条件も整理します。

#Claude#Claude Code#Anthropic#LLM#ベンチマーク

META-MARK × AI

ローカルAIを動かすGPU、ちゃんと選べていますか?

VRAM・性能・コスパをMetaScoreで数値化。AIアプリ別の推奨ハードウェア要件も確認できます。