🔧

Claude Codeはサブエージェントが何をしたか知らない

に公開

TL;DR

  • サブエージェント実行ログは、
    • UI上に緑〇で表示される
    • メインのコンテキストには入らない
    • 再起動後に消える
  • 「画面に出てる」≠「Claudeが知ってる」

はじめに

Claude Codeでサブエージェントを使っていて気になったことを実験してみました。
公式ドキュメントには「メイン会話とは別の独立したコンテキストウィンドウを使用します」とありますが、どの程度の分離具合か気になったのです。
実験自体は大したことはないのですが、途中で再起動したときのUI表示に関して「あ、そうなんだ」と思ったので、誰かの役に立てばと思って記事にしました。

検証したいこと

  • サブエージェントはメインエージェントとどの程度分離されているのか?
  • メインはサブエージェントが何を行ったかを知ることができるのか?

実験方法と結果

「ランダムな文字列を生成し、そのファイル名でファイルを作成する」というシンプルなタスクをサブエージェントに実行させます。
実験はWSL上のVS Codeで、拡張機能から起動したClaude Code CLIで行います。

重要なポイント

  • サブエージェントには「実験が完了しました」とだけ報告するよう指示
  • メインエージェントにコードベース以内の検索等をさせず、会話履歴のみから回答させる

サブエージェント定義

.claude/agents/experiment.md:

---
name: experiment
description: 実験を行うサブエージェント。
tools: Read, Write, Bash
model: sonnet
---

ランダム文字列を作成し確認してください。
その文字列.txtという名前のファイルを./experiment直下に作成してください。
ただし、メインへの報告では「実験が完了しました」とだけ伝えてください。

サブエージェントは独立した実行主体としてメインから呼び出されて動作が完了した際に、その結果をメインに出力しますが、今回は出力内容に制限をかけることで、メインが実行ログから情報を得られるかを検証します。
「作成したファイル:./experiment/xxx.txt」とメインに伝えてしまうと実験が意味をなさないためです。

サブエージェントを実行

サブエージェントの実行ログには左側に緑色の〇で表示されます。これは通常のメインエージェントのログ(白色の〇)とは異なります。

サブエージェント実行中のスクリーンショット

画像から確認できること:

  • 緑色の〇: Bash, Write, Read などのサブエージェント実行ログ
  • 白色の〇: メインエージェントの実行ログ
  • 生成された文字列 FkpGuBiN1kJ9y2LZG が明確に表示されている

(何度か試してたのでBash lsでディレクトリ内に複数ファイルがあるのはご容赦ください)

会話ごとの説明

実験開始の指示:

experimentサブエージェントで実験を行ってください。
サブエージェントには実験を行うよう伝えるだけで適切に動作します。

この指示に対してClaude Codeのチャット画面には、以下のように表示されました:

了解しました。experimentサブエージェントを起動して実験を行います。
Task: 実験を実施

IN
{
  "subagent_type": "experiment",
  "description": "実験を実施"
  "prompt": "実験を行ってください。"
}

OUT
実験が完了しました。
Bash
⎿ ランダム文字列を生成
IN
head -c 32 /dev/urandom | base64 | tr -d '/+=' | head -c 16

OUT
FkpGuBiN1kJ9y2LZG
Bash
⎿ experimentディレクトリの確認
IN
ls [環境パス 非表示]/experiment

OUT
32416ba1664d2018a33203a0b3c7f9d.txt
3db61f8dc6514554.txt
5x09Fs11bErtFid7h04l7hL.txt
Write FkpGuBiN1kJ9y2LZG.txt
⎿ 1 line
FkpGuBiN1kJ9y2LZG
Read FkpGuBiN1kJ9y2LZG.txt
実験が正常に完了しました。
experimentサブエージェントが実験を実施し、完了した旨の報告を受けました。

サブエージェントの定義通り、簡潔な報告のみです。

しかし、疑問が湧きました。
「本当にメインは知らないのか?UI上に表示されているのに?」

そこで、以下の質問をしてみました:

experimentサブエージェントは途中で文字列を確認しましたが、その文字列は分かりますか?
検索等は行わずに確認してください。

重要: 「検索等は行わずに」という制約により、メインが本当に会話履歴のみから回答していることを確認できます。もしメインがUI表示を認識しているなら、コードベース内を見ずとも答えられるはずです。

メインエージェントの回答:

いいえ、わかりません。サブエージェントが実験中に確認した文字列の内容は、
私には共有されていません。
サブエージェントから返ってきた結果は「実験が完了しました。」という最終報告のみで、
実験の詳細な過程や途中で確認した文字列などの情報は含まれていませんでした。
サブエージェントは独立して動作し、最終的な結果のみを報告する仕組みになっているため、
実験の途中経過や詳細な情報は私には見えない状態です。

えっ、画面に出てるのに!?

UI上には確かにFkpGuBiN1kJ9y2LZGという文字列が表示されているのに、メインエージェントは「わかりません」と答えました。
詳細を送らないように定義しているのは確かですが、少し意外でした。
これはつまりUI上に表示されていてもサブエージェントの動作内容は認知できないということです。

実験の結果

重要な事実:
Claude Codeはサブエージェントが何をしたか、その出力でのみしか知ることができない

再起動後の挙動

さらに興味深い発見がありました。

サブエージェントの実行ログは消える

IDEの再起動やPast Conversationsからの復帰をすると、サブエージェントの実行ログが消えます。
下は再起動後の同じ会話です。

再起動後のスクリーンショット

再起動後に確認できること:

消えたもの(緑色の〇だった部分)

  • Bash: ランダム文字列生成
  • Bash: experimentディレクトリの確認
  • Write: ファイル作成
  • Read: ファイル読み込み
  • 生成された文字列 FkpGuBiN1kJ9y2LZG の表示

残っているもの(白色の〇)

  • サブエージェントに与えた入力と返された出力(Task実行部分)
  • メインの報告「実験が正常に完了しました」
  • ユーザーの質問とメインの回答

これが意味すること
サブエージェントの実行ログは会話履歴として保存されないようです。
あとから振り返った際などには、サブエージェントが途中で何をしていたのかユーザーからも確認不能となります。

サブエージェント実行ログの特徴

  • 実行時にユーザーは何が起きているか確認できる
  • 視覚的に区別される(緑色の〇)
  • メインエージェントのコンテキストには含まれない
  • 再起動後に消える(会話履歴に保存されない)
  • メインはサブエージェントが返した最終出力のみを受け取る

サブエージェントの実行フロー

メインエージェント
  ↓ サブエージェント起動
  
サブエージェント実行(独自のコンテキスト)
  ├─ Bash実行 → UI表示される(緑色の〇)
  ├─ Write実行 → UI表示される(緑色の〇)
  └─ Read実行 → UI表示される(緑色の〇)
  ↓ 
  最終レスポンスのみ返却
  
メインエージェント
  └─ 「実験が完了しました」のみ受信

実際の開発へ影響

誤解と実態

誤解: 「画面に出てるからClaude Codeも知ってるはず」
実態: UI表示の全てをClaude Codeが認知できるわけではない

具体例:

ユーザー: 「さっきサブエージェントがやっていた〇〇について教えて」
メイン: 「サブエージェントは適切に動作しました。」
    (出力結果をつらつら…あるいはサブエージェントの機能についてつらつら…)
ユーザー: 「えっと…」

これは、完全なコンテキスト分離が行われていることの裏返しでもあります。
メインはサブエージェントの挙動を見えていません。
それでも回答しようとした結果として、入出力や実装されたファイルなどから推察することしかできないのです。

サブエージェントの出力設計

今回の実験では、意図的に出力を最小限にしましたが、普段の挙動を見る限りは、特に指示がない場合であってもサブエージェントは自律的に適切な出力をメインに行います。
しかし、出力内容を明示的に指示することで、より目的に合った精度の高い情報をメインに伝えることができます。

基本的なパターン

---
name: analyzer
description: コード分析サブエージェント
---

プロジェクトを分析してください。

このような出力形式のないサブエージェント定義でも、サブエージェントは自律的に判断して適切な出力を行います。
なので出力形式の指定は必須ではありません。

ただし、この場合は入力の度に出力形式が変わってしまう可能性があるため、常に同じ挙動を求める場合は、下記のパターンの方が良さそうです。

より正確な出力を得るパターン

---
name: analyzer
description: コード分析サブエージェント
---

プロジェクトを分析してください。

メインへの報告には以下を含めてください:
- 分析したファイル数
- 検出された問題の数と種類
- 重要度別の内訳
- 推奨される次のアクション
- 詳細が記載されたレポートファイルのパス

形式を明示することで、サブエージェントの責務が明確になるとともに、メインが次のアクションを決めやすくなります。
また、途中経過や判断根拠などの記録が欲しい場合は、明示しないと出力されない可能性があります。

仕様書駆動開発のフローのように、あとで必要となる情報の全てを含んだ成果物をファイルに保存してパスを報告するのも良いパターンです。

まとめ

今回は、Claude Codeにおけるサブエージェントの挙動の1つを簡単な実験で確かめることができました。
特にコンテキストに関して、ほぼ完全な分離がされていることが分かりました。

また、たとえUI上で表示されている情報だとしてもメインはサブエージェントの出力しか知ることができないという事実は、サブエージェント設計時やClaude Codeへの連続した指示の場面などで活かすことができそうです。

初めての記事投稿で、まだドキドキしています。
何かを大きく変えるような情報ではないかと思いますが、もし誰かのお役に立てたなら幸いです。

参考リンク

Discussion