braintrust-tracing について
braintrust-tracing は、Braintrust で Claude Code のセッションを追跡するためのガイドとフック設定です。セッション、ターン、ツール、LLM のスパンを記録し、独立したサブエージェントのトレースを事後に関連付ける方法も説明します。
主な機能
- 01セッションとターンのスパンを記録
- 02ツールと LLM のスパンを取得
- 03セッションごとの追跡状態を保存
- 04トレース分析コマンドを提供
- 05サブエージェントの事後関連付けを説明
活用シーン
- 01Claude Code セッションの活動確認
- 02フックログによるスパン欠落の調査
- 03親とサブエージェントのトレースを使ったデータセット構築
MCP 対応
このプロジェクトは、Claude Code のセッショントレースを Braintrust に送るフックを説明するもので、MCP サーバーではありません。README に MCP 連携の説明はありません。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ parcadei/ continuous-claude-v3 --skill braintrust-tracingインストール後、Claude Code で/braintrust-tracingを入力して読み込まれたか確認します。
詳細
Claude Code の Braintrust トレーシング
サブエージェントの相関付けを含む、Braintrust で Claude Code のセッションをトレースするための包括的なガイドです。
アーキテクチャの概要
PARENT SESSION
+---------------------+
| SessionStart |
| (creates root) |
+----------+----------+
|
+----------v----------+
| UserPromptSubmit |
| (creates Turn) |
+----------+----------+
|
+--------------------+--------------------+
| | |
+---------v--------+ +--------v--------+ +--------v--------+
| PostToolUse | | PostToolUse | | PreToolUse |
| (Read span) | | (Edit span) | | (Task - inject) |
+------------------+ +-----------------+ +--------+--------+
|
+----------v----------+
| SUB-AGENT |
| SessionStart |
| (NEW root_span_id)|
+----------+----------+
|
+----------v----------+
| SubagentStop |
| (has session_id) |
+---------------------+
フックイベントのフロー
| フック | トリガー | 作成するもの | 主なフィールド |
|---|---|---|---|
| SessionStart | セッション開始時 | ルートスパン | session_id、root_span_id |
| UserPromptSubmit | ユーザーがプロンプトを送信 | ターンスパン | prompt、turn_number |
| PreToolUse | ツールの実行前 | (Task プロンプトを変更) | tool_input.prompt |
| PostToolUse | ツールの実行後 | ツールスパン | tool_name、input、output |
| Stop | ターン完了時 | LLM スパン | model、tokens、tool_calls |
| SubagentStop | サブエージェント終了時 | (スパンなし) | サブエージェントの session_id |
| SessionEnd | セッション終了時 | (ルートを確定) | turn_count、tool_count |
トレース階層
Session (task span) - root_span_id = session_id
|
+-- Turn 1 (task span)
| |
| +-- claude-sonnet (llm span) - model call with tool_use
| +-- Read (tool span)
| +-- Edit (tool span)
| +-- claude-sonnet (llm span) - response after tools
|
+-- Turn 2 (task span)
| |
| +-- claude-sonnet (llm span)
| +-- Task (tool span) -----> [Sub-agent session - SEPARATE trace]
| +-- claude-sonnet (llm span)
|
+-- Turn 3 ...
サブエージェントのトレース:できること、できないこと
できないこと
SessionStart は Task プロンプトを受け取りません。
PreToolUse を通じて Task プロンプトにトレースコンテキストを挿入してみました。
# PreToolUse hook injects:
[BRAINTRUST_TRACE_CONTEXT]
{"root_span_id": "abc", "parent_span_id": "xyz", "project_id": "123"}
[/BRAINTRUST_TRACE_CONTEXT]
しかし、SessionStart が受け取るのはセッションのメタデータのみで、変更後のプロンプトは受け取りません。挿入したコンテキストは失われます。
できること
親セッションの Task スパンにはすべての情報が含まれます。
agentId- サブエージェントの実行を識別する IDtotalTokens、totalToolUseCount- メトリクスcontent- エージェントの応答/要約全体tool_input.prompt- 元のタスクプロンプトtool_input.subagent_type- エージェントの種類(例:「oracle」)
SubagentStop フックはサブエージェントの session_id を受け取ります。
- これはサブエージェントの孤立したトレースの
root_span_idと一致します - 親の Task スパンと子のトレースを相関付けられます
相関付けのパターン
**現在の状態:**サブエージェントは孤立したトレース(新しい root_span_id)を作成します。
相関付けの方法:
- 親セッションの Task スパンをクエリして、エージェントのメタデータを取得します
agentIdまたはタイミングを使って、孤立したトレースと照合します- サブエージェントの
session_idは、そのトレースのroot_span_idと同じです
今後の解決策(未実装):
SubagentStop fires -> writes session_id to temp file
PostToolUse (Task) -> reads temp file -> adds child_session_id to Task span metadata
これにより、Task.agentId + Task.child_session_id を孤立したトレースの root_span_id にリンクできます。
状態管理
セッションごとの状態ファイル
~/.claude/state/braintrust_sessions/
{session_id}.json # Per-session state
各セッションファイルには次の情報が含まれます。
{
"root_span_id": "abc-123",
"project_id": "proj-456",
"turn_count": 5,
"tool_count": 23,
"current_turn_span_id": "turn-789",
"current_turn_start": 1703456789,
"started": "2025-12-24T10:00:00.000Z",
"is_subagent": false
}
グローバル状態
~/.claude/state/braintrust_global.json # Cached project_id
~/.claude/state/braintrust_hook.log # Debug log
デバッグ用コマンド
トレーシングが有効か確認する
# View hook logs in real-time
tail -f ~/.claude/state/braintrust_hook.log
# Check if session has state
cat ~/.claude/state/braintrust_sessions/*.json | jq -s '.'
# Verify environment
echo "TRACE_TO_BRAINTRUST=$TRACE_TO_BRAINTRUST"
echo "BRAINTRUST_API_KEY=${BRAINTRUST_API_KEY:+set}"
Braintrust に直接クエリする
# List recent sessions
uv run python -m runtime.harness scripts/braintrust_analyze.py --sessions 5
# Analyze last session
uv run python -m runtime.harness scripts/braintrust_analyze.py --last-session
# Replay specific session
uv run python -m runtime.harness scripts/braintrust_analyze.py --replay <session-id>
# Find sub-agent traces (orphaned roots)
uv run python -m runtime.harness scripts/braintrust_analyze.py --agent-stats
フックの実行をデバッグする
# Enable verbose logging
export BRAINTRUST_CC_DEBUG=true
# Test hooks manually
echo '{"session_id":"test-123","type":"resume"}' | \
bash "$CLAUDE_PROJECT_DIR/.claude/plugins/braintrust-tracing/hooks/session_start.sh"
# Test PreToolUse (Task injection)
echo '{"session_id":"test-123","tool_name":"Task","tool_input":{"prompt":"test"}}' | \
bash "$CLAUDE_PROJECT_DIR/.claude/plugins/braintrust-tracing/hooks/pre_tool_use.sh"
トラブルシューティングのチェックリスト
-
トレースが表示されない場合:
.claude/settings.local.jsonのTRACE_TO_BRAINTRUST=trueを確認します- API キーを確認します:
echo $BRAINTRUST_API_KEY - ログを確認します:
tail -20 ~/.claude/state/braintrust_hook.log
-
サブエージェントがリンクされない場合:
- これは想定どおりです。サブエージェントは孤立したトレースを作成します
--agent-statsを使ってエージェントのアクティビティを確認します- 親の Task スパン内のタイミングまたは
agentIdを使って相関付けます
-
スパンが見つからない場合:
- セッション状態の
current_turn_span_idを確認します - Stop フックが実行されること(ターンの確定)を確認します
- ログに「Failed to create」エラーがないか確認します
- セッション状態の
-
状態が破損している場合:
- セッション状態を削除します:
rm ~/.claude/state/braintrust_sessions/*.json - グローバルキャッシュをクリアします:
rm ~/.claude/state/braintrust_global.json
- セッション状態を削除します:
主要なファイル
| ファイル | 目的 |
|---|---|
.claude/plugins/braintrust-tracing/hooks/common.sh | 共通ユーティリティ、API、状態管理 |
.claude/plugins/braintrust-tracing/hooks/session_start.sh | ルートスパンを作成し、サブエージェントのコンテキストを処理 |
.claude/plugins/braintrust-tracing/hooks/user_prompt_submit.sh | ユーザーメッセージごとに Turn スパンを作成 |
.claude/plugins/braintrust-tracing/hooks/pre_tool_use.sh | Task プロンプトにトレースコンテキストを挿入 |
.claude/plugins/braintrust-tracing/hooks/post_tool_use.sh | ツールスパンを作成し、エージェント/スキルのメタデータを取得 |
.claude/plugins/braintrust-tracing/hooks/stop_hook.sh | LLM スパンを作成し、Turn を終了 |
.claude/plugins/braintrust-tracing/hooks/session_end.sh | セッションを終了し、学習内容の抽出を開始 |
scripts/braintrust_analyze.py | トレースされたセッションをクエリして分析 |
~/.claude/state/braintrust_sessions/ | セッションごとの状態ファイル |
~/.claude/state/braintrust_hook.log | デバッグログ |
環境変数
| 変数 | 必須 | デフォルト | 説明 |
|---|---|---|---|
TRACE_TO_BRAINTRUST | はい | - | "true" に設定すると有効になります |
BRAINTRUST_API_KEY | はい | - | Braintrust の API キー |
BRAINTRUST_CC_PROJECT | いいえ | claude-code | プロジェクト名 |
BRAINTRUST_CC_DEBUG | いいえ | false | 詳細ログ |
BRAINTRUST_API_URL | いいえ | https://api.braintrust.dev | API エンドポイント |
セッションから得た知見
サブエージェントのトレースについて分かったこと(2025年12月)
試みたこと: PreToolUse を介して Task プロンプトにトレースコンテキストを挿入しました。
結果: 失敗しました。SessionStart が受け取るのはセッションのメタデータのみで、プロンプトは受け取りません。
判明したこと: Task スパンには、すでにサブエージェントに関する豊富なデータが含まれています。
metadata.agent_type-subagent_typeによるエージェントの種類metadata.skill_name- Skill ツールによるスキルtool_input- エージェントに送信された完全なプロンプトtool_output- エージェントの応答
現在の相関付けの手順:
- 親セッションの Task スパンには
agentIdとタイミング情報がある - サブエージェントは
root_span_id = session_idの孤立したトレースを作成する - SubagentStop からサブエージェントの
session_idを取得する - 手動で相関付ける:タイミングを照合するか、
session_idのリンクを使用する
今後の作業: SubagentStop の後、PostToolUse から Task スパンのメタデータに child_session_id を書き込みます。
サブエージェントの相関付けについて分かったこと
問題
- Task ツールで起動したサブエージェントは、孤立した Braintrust トレースを作成する
- 親セッションには
agentIdを含む Task スパンがあり、サブエージェントには別のsession_idがある - 両者を結び付ける組み込みの仕組みがない
機能しない方法
1. PreToolUse によるプロンプトへの挿入
SessionStart フックが受け取るのはセッションのメタデータ(session_id、type、cwd)のみで、プロンプトは受け取りません。挿入されたトレースコンテキストは参照されません。
フックが受け取る内容:
{
"session_id": "...",
"type": "start|resume|compact|clear",
"cwd": "...",
"env": {...}
}
プロンプトのフィールドが存在しないため、SessionStart ではコンテキストを挿入できません。
2. SubagentStop → PostToolUse のファイル受け渡し
競合状態が発生します。これらはタイミングが保証されない独立した非同期フックです。
- サブエージェントのセッション終了時に SubagentStop が実行される
- Task ツールの完了時に PostToolUse(Task)が実行される
- 両者の実行順序は保証されない
- 相関付け用のファイルに書き込むと競合が発生する
3. PreToolUse による相関付けファイル
SessionStart には、どの Task がサブエージェントを起動したかを示すコンテキストがないため、task_span_id にアクセスできません。PreToolUse はプロンプトを変更しますが、SessionStart が確実に参照できる状態ファイルは作成しません。
機能すること
データセット構築のための事後マッチング:
親セッションの Task スパンには、次の情報が含まれます。
agentId- サブエージェントの実行を識別する IDtotalTokens、totalToolUseCount- 集計されたメトリクスcontent- エージェントの応答/要約全体tool_input.prompt- 元のタスクプロンプトtool_input.subagent_type- エージェントの種類(例:「oracle」)- 開始/終了タイムスタンプ
サブエージェントのセッションには、次の情報が含まれます。
session_id(孤立したトレースのroot_span_idと同じ)- 開始/終了タイムスタンプ
- すべての内部スパンとツール呼び出し
相関付けの方法:
- 親セッションのトレースをエクスポートします(親の
root_span_idをクエリします) - サブエージェントのトレースをエクスポートします(親の時間枠内に作成されたすべてのセッションをクエリします)
- 次の情報で照合します。
- タイミング:Task スパンの終了時刻 ≈ サブエージェントセッションの終了時刻
- メタデータ:Task プロンプトの
subagent_type - ID:SubagentStop フックから
session_idを取得できます(取得してログに記録できます)
アーキテクチャに関する考察
SessionStart の入力は意図的に最小限に抑えられており、プロンプトやツールのコンテキストは含まれません。
interface SessionStartInput {
session_id: string;
type: "start" | "resume" | "compact" | "clear";
cwd: string;
env: { [key: string]: string };
// NO: prompt, tool_context, task_span_id, parent_span_id
}
この設計上の境界により、フックの実行時にリアルタイムで相関付けすることはできません。
推奨事項
サブエージェントとの相関付けを含むエージェント実行データセットを構築するには、次の手順を実施します。
- セッション内でのログ記録: SubagentStop の
session_idをログまたは状態に記録します - セッション後のエクスポート: Braintrust API をクエリして、親とサブエージェントのトレースを取得します
- オフラインでの相関付け: スクリプトでタイミングとメタデータを基にトレースを照合します
- リアルタイムのリンクを試みない: フックには必要なコンテキストがありません
スクリプトの例:
# 1. Export parent session
braintrust_analyze.py --replay <parent-session-id> > parent_traces.json
# 2. Query for orphaned sub-agent traces (those created during parent's time window)
braintrust_analyze.py --agent-stats > all_agent_traces.json
# 3. Correlate in Python:
# - Parent Task spans -> agentId, timestamps, subagent_type
# - Orphaned traces -> root_span_id, timestamps
# - Match by timing and type
この方法は信頼性が高く、テスト可能であり、フックに暗黙の状態を維持させる必要もありません。