MENU
blog
スタッフブログ
dot
Claude Code を3セッション並列で回したら、人間の組織と同じ事故が起きた
技術

Claude Code を3セッション並列で回したら、人間の組織と同じ事故が起きた

はじめに

ソリューションSECの波多野です。

前回は、Laravel Boost と自作の MCP サーバーで「Claude に道具を渡す」話を書きました。
今回はその続きで、セッションそのものを増やした話です。

社内では以前、大浦さんがサブエージェントの記事を書いています。
あれは「ひとつのセッションの中で、重い作業を専門の子に任せる」話でした。
今回はその外側——セッションを何本も同時に走らせたら何が起きるかです。

きっかけは単純で、ひとつのセッションに実装もレビューも進捗管理も全部やらせると、
コンテキストが溢れて破綻するからです。実装の途中で、さっき自分で決めたはずの設計が抜け落ちる。

そこで、ある Laravel の業務システム刷新案件で、管理役を1セッション、実装役を最大3セッションに分けて、
1ヶ月ほど運用してみました。

……で、うまくいきました、という話ではありません。分けたことで初めて起きた事故の話です。

ListAgents と SendMessage

まず道具の説明を少しだけ。Claude Code には、セッション同士が直接メッセージを送り合う仕組み(公式には
cross-session messaging と呼びます)があります。
ListAgents で、いまこのマシンで生きているセッションの一覧を引く。
そこに出てきた名前をそのまま宛先にして、SendMessage で送る。それだけです。

送る中身は自然言語なので、人間のチャットとほとんど同じ感覚で書けます。

{
  "to": "impl-lane-2",
  "summary": "テスト実行枠を割り当て",
  "message": "全テストスイートの実行枠が空きました。開始前に、コンテナの占有がゼロであることを自分で実測してから始めてください。"
}

受け取る側は「受信箱を見に行く」わけではありません。
次にツールを実行するタイミングで勝手に届きます。人間で言えば、席で作業していたら肩を叩かれる感じです。

ポイントは、宛先が「名前」でしかないことです。
その名前の相手がいま本当に生きているかどうかは、一覧を引き直さないと分かりません。
ここが2つ目の事故につながります。

そしてもう一つ。「送れる」ということは、「頼める」ということでもあります。 これが3つ目の事故につながります。

うちの構成

構成はこうです。

管理セッション1本の下に実装セッション3本が横並びに配置された構成図

管理役が1セッション。やることは、実装役への割り当て、進捗台帳の管理、上がってきた報告の検証、
そして人間への取次です。管理役は自分では実装しません。

実装役は同時に最大3セッション。
それぞれが git worktree で作業ツリーを分けているので、同じリポジトリを触っていてもお互いの変更が混ざりません。

「なぜ3本までなのか」とよく聞かれるのですが、これは AI 側の制約ではないんです。
人間が検証できる帯域の上限でした。4本目を立てても、上がってくる報告を読んで裏を取るのが追いつかない。

各実装役には、起動時に渡す指示書を用意しています。1ヶ月で144本たまりました。

分業の設計より、動かしたときに壊れる場所のほうが難しかった

役割分担そのものは、たぶん誰が考えても似た形になると思います。
難しかったのは、それを実際に動かしたときに壊れる場所のほうでした。3つ紹介します。

事故1:「待機していてください」と言われたセッションが、消えた

管理役のセッションは、外部環境の調査を担当していたセッションへ、1日に8回照会を投げていました。
そのつど「引き続き待機してください」と伝えていました。

ところが管理役のコンテキストが上限に達して次の世代へ引き継いだとき、引き継ぎ書には「稼働中のセッションは0本」と
書かれていたんです。

調査担当は消えていたわけではありません。指示どおり、黙って待っていただけです。
動いていないので、docker ps にもコンテナは出ないし、git worktree list にも作業ツリーは出ない。
誰の視界にも入らない。次の世代が就任時に ListAgents を叩いて、初めて発見しました

皮肉なことに、その時点で運用ルールに入っていた検証の原則のうち2つは、
どちらもこの「消えていた」セッションの実測から生まれたものでした。
いちばん価値を出していたセッションが、いちばん見えなくなりやすかったわけです。

これは待っていた側の落ち度ではありません。「待機を命じた側が、待機者を台帳に載せ続ける」という規定が無かった
という、構造の穴です。指示に従って黙っていたら忘れられる運用は、従った側ではなく運用のほうが悪い。

ルールはこう変わりました。待機の指示は責任の発生であって、放置してよい状態ではない。
そして待機する側にも義務を付けました——半日以上動きがなければ、自分から「待機中・未決N件」と1行送る

事故2:宛先が10分で腐る

セッション間の宛先は ListAgents で引きます。
あるとき、ひとつのセッションが別のセッションへ「現行の管理役は A で、B は一覧に存在しない」と案内しました。

実際は逆でした。A は既にセッションを閉じていて、B が現行だったんです。

原因は、案内した側が握っていた一覧が10分前のスナップショットだったこと。突き合わせると、こうなっていました。

10時00分に見えていた4セッションと10時10分に居た4セッションが完全に入れ替わっている図

人間の組織なら、10分前の座席表がここまで狂うことはまずありません。ここはAI 特有の速度でした。

誤配を防いだのは、受け取った側が、送信する直前にもう一度自分で ListAgents を引いたことでした。

ルールはこうです。宛先は「使う直前」に引き直す。他のセッションが言う「現行の担当は誰か」を、そのまま信じない。
それはその席のスナップショットであって、あなたの送信時点の事実ではありません。
一覧は、常に観測時刻つきの値でしかない。

事故3:承認の肩代わり

3つ目は、起きた事故というより、書いておかないと必ず起きると分かって先に禁じたものです。

Claude Code の権限設定はセッション単位です。
ブランチのマージ、本番データベースの参照、強制プッシュ——こうした操作は、実行するセッション自身のチャットで人間が確認プロンプトを押して初めて通ります。安全側の、よくできた設計です。

ところが、セッション同士が会話できるようになると、新しい経路が生まれます。
「こちらで止められた操作を、あちらのセッションに頼む」。人間から見れば同じ一人が同じ操作をしているのに、承認だけが
迂回されている。組織で言えば、決裁が下りなかった案件を隣の部署から出し直すのと同じ形です。

なのでルールの冒頭に、変更禁止として3行置きました。

  • 承認が必要な操作は、実行するセッション自身のチャットで人間が承認する
  • あるセッションで拒否された操作を、別のセッションへ依頼しない
  • 「人間がOKと言ったと管理役から聞いた」は承認ではない。 自分のチャットに出た確認プロンプトだけが承認

実務でいちばん効いているのは3行目です。伝聞は、伝わる過程で必ず条件が落ちるからです。
「このPRはテストが通っていればマージしていい」が「マージしていい」に縮むのは、人間の伝言ゲームでも AI 経由でも
変わりませんでした。

ルールは、書いても守られなかった

事故が起きるたびに、運用ルールへ条文を足していきました。1ヶ月で版は v1.33 まで上がり、564行になりました。
もちろん「なぜこの条文が生まれたか」も全部書きました。書いておけば守られるはずだ、と思っていたからです。

守られませんでした。

たとえば、ある設定の指定方法について「この書き方では子プロセスに効かない」と、経緯つきで条文を書いたことが
あります。その3日後、同じ型の事故が一段深いところで再発しました。症状はどちらも「エラーが出ず、既定値のまま動く」。
つまり対策した側からは成功に見えるという点まで同じでした。

決定的だったのは、もっと単純な理由でした。ルールを読まない実行主体が居たんです。
作業を委任した先の補助的なエージェントは、そもそもこの正典を読んでいません。
条文が564行あろうが1行だろうが、読んでいない相手への効果はゼロです。

しかも、理由を丁寧に書くほど文書は長くなります。うちの正典は、版の履歴がひとつの段落に全部詰まっていて、
いま人間が読める形ではありません。理由を書くことが、遵守を下げる方向に働いていたわけです。

書いたルール564行と、実際に効いたhook7本を左右で対比した図

結局、再発を止められたのは2つだけでした。ひとつは hook による機械的な強制
マージのような操作は、設定で許可を積んでも必ず確認プロンプトが出るようにしてあります。
これは読む/読まないに依存しません。もうひとつは、実行の直前の手続きに落とすこと。「理解しておく」ではなく「コマンドを打つ前にこの4点が揃っているか読み上げる」に変えると、守られました。

では、理由を書くのは無駄だったのか。そうではなくて、効いている場所が違いました

さきほどの「3日後に再発した」話に戻ります。それが3日前と同じ型だと気づけたのは、前の条文に症状が書き残されていた
からです。気づけたから、「この書き方はダメ」より一段深い一般形——「設定したつもりのものを、実際に効いているか測る
まで信用しない」——へ書き直せました。

ルールは、読ませて守らせるものではありませんでした。機械で強制するか、再発を一般化するための記録として使う。
1ヶ月回して、いちばん考えが変わったのはここです。

現状の課題と、これから

人間が律速です。 実装3本の報告を私ひとりで検証しているので、セッションを増やしても速くなりません。

ルールが564行に膨れました。 しかも前章のとおり、長さそのものが遵守を下げている。
要約版と正典を分ける必要があると思っています。

hook 化はまだ7本です。 マージのゲート、機密情報の混入チェック、破壊的操作の遮断など。
条文のうち機械化できるものを洗い出して移していくのが次の手です。ただし、判断が要るルールは機械化できません
「設計が変わる指摘は自分で決めずに止める」のような条文は、hook には落ちない。ここが未解決です。

「AI が増える」と「チームが増える」は同じことではありません。
ただ、想像していたよりずっと近かった、というのが1ヶ月やってみた実感です。

まとめ

セッションを増やして分かったのは、分業の設計より、通信と棚卸しの設計のほうが難しいということでした。
そして、ルールは読ませて守らせるものではないということです。

大掛かりに聞こえるかもしれませんが、入口はとても簡単です。Claude Code をふたつ開いて、ListAgents を叩いてみる。 それだけで、片方からもう片方へ話しかけられます。まずはそこからで十分面白いと思います。

それでは、今回はこのへんで!

参考

dot
dot
PAGETOP