Braintrust Tracing

作者 parcadeid07ff4b06b62無授權條款3.9K 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫8 個月前更新

Braintrust tracing for Claude Code - hook architecture, sub-agent correlation, debugging

僅含說明AI & Agents
AI 產生的概覽

說明 Claude Code 工作階段的 Braintrust 追蹤,涵蓋鉤子架構、子代理關聯、狀態檔案與除錯。

功能
此技能是一份參考指南,說明 Claude Code 工作階段如何透過 SessionStart、UserPromptSubmit、PreToolUse、PostToolUse、Stop、SubagentStop 與 SessionEnd 等鉤子事件追蹤至 Braintrust。它描述了隨之產生的工作階段、回合、LLM 與工具 span 的追蹤階層,並解釋子代理為何會產生獨立的孤立追蹤。文件也說明了各工作階段與全域狀態檔案、環境變數、除錯指令以及疑難排解清單。
適用情境
當你需要理解或排解 Claude Code 工作階段的 Braintrust 追蹤問題時使用,例如 span 遺失、狀態損毀,或將子代理追蹤關聯至父層 Task span。它也適用於建立需要關聯父層與子代理追蹤的代理執行資料集。
執行需求
需要啟用 Braintrust 追蹤,將 TRACE_TO_BRAINTRUST 設為 true 並提供 BRAINTRUST_API_KEY,同時需要連線至 Braintrust API 的網路存取。文件中提到了鉤子指令碼與一個 Python 分析指令碼,但此技能僅提供說明,不含指令碼或資源。

Braintrust Tracing for Claude Code

Comprehensive guide to tracing Claude Code sessions in Braintrust, including sub-agent correlation.

Architecture Overview

                         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)  |                                         +---------------------+

Hook Event Flow

HookTriggerCreatesKey Fields
SessionStartSession beginsRoot spansession_id, root_span_id
UserPromptSubmitUser sends promptTurn spanprompt, turn_number
PreToolUseBefore tool runs(modifies Task prompts)tool_input.prompt
PostToolUseAfter tool runsTool spantool_name, input, output
StopTurn completesLLM spansmodel, tokens, tool_calls
SubagentStopSub-agent finishes(no span)session_id of sub-agent
SessionEndSession ends(finalizes root)turn_count, tool_count

Trace Hierarchy

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 ...

Sub-Agent Tracing: What Works and What Doesn't

What Doesn't Work

SessionStart doesn't receive the Task prompt.

We tried injecting trace context into Task prompts via PreToolUse:

bash
# PreToolUse hook injects:[BRAINTRUST_TRACE_CONTEXT]{"root_span_id": "abc", "parent_span_id": "xyz", "project_id": "123"}[/BRAINTRUST_TRACE_CONTEXT]

But SessionStart only receives session metadata, not the modified prompt. The injected context is lost.

What DOES Work

Task spans in parent session contain everything:

  • agentId - identifier for the sub-agent run
  • totalTokens, totalToolUseCount - metrics
  • content - full agent response/summary
  • tool_input.prompt - original task prompt
  • tool_input.subagent_type - agent type (e.g., "oracle")

SubagentStop hook receives the sub-agent's session_id:

  • This equals the sub-agent's orphaned trace root_span_id
  • Allows correlation between parent Task span and child trace

The Correlation Pattern

Current state: Sub-agents create orphaned traces (new root_span_id).

Correlation method:

  1. Query parent session's Task spans for agent metadata
  2. Match agentId or timing with orphaned traces
  3. Sub-agent's session_id = its trace's root_span_id

Future solution (not yet implemented):

SubagentStop fires -> writes session_id to temp filePostToolUse (Task) -> reads temp file -> adds child_session_id to Task span metadata

This would link: Task.agentId + Task.child_session_id -> orphaned trace root_span_id

State Management

Per-Session State Files

~/.claude/state/braintrust_sessions/  {session_id}.json       # Per-session state

Each session file contains:

json
{  "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}

Global State

~/.claude/state/braintrust_global.json   # Cached project_id~/.claude/state/braintrust_hook.log      # Debug log

Debugging Commands

Check if Tracing is Active

bash
# View hook logs in real-timetail -f ~/.claude/state/braintrust_hook.log
# Check if session has statecat ~/.claude/state/braintrust_sessions/*.json | jq -s '.'
# Verify environmentecho "TRACE_TO_BRAINTRUST=$TRACE_TO_BRAINTRUST"echo "BRAINTRUST_API_KEY=${BRAINTRUST_API_KEY:+set}"

Query Braintrust Directly

bash
# List recent sessionsuv run python -m runtime.harness scripts/braintrust_analyze.py --sessions 5
# Analyze last sessionuv run python -m runtime.harness scripts/braintrust_analyze.py --last-session
# Replay specific sessionuv 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

Debug Hook Execution

bash
# Enable verbose loggingexport BRAINTRUST_CC_DEBUG=true
# Test hooks manuallyecho '{"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"

Troubleshooting Checklist

  1. No traces appearing:

    • Check TRACE_TO_BRAINTRUST=true in .claude/settings.local.json
    • Verify API key: echo $BRAINTRUST_API_KEY
    • Check logs: tail -20 ~/.claude/state/braintrust_hook.log
  2. Sub-agents not linking:

    • This is expected - sub-agents create orphaned traces
    • Use --agent-stats to find agent activity
    • Correlate via timing or agentId in parent Task span
  3. Missing spans:

    • Check current_turn_span_id in session state
    • Ensure Stop hook runs (turn finalization)
    • Look for "Failed to create" errors in log
  4. State corruption:

    • Remove session state: rm ~/.claude/state/braintrust_sessions/*.json
    • Clear global cache: rm ~/.claude/state/braintrust_global.json

Key Files

FilePurpose
.claude/plugins/braintrust-tracing/hooks/common.shShared utilities, API, state management
.claude/plugins/braintrust-tracing/hooks/session_start.shCreates root span, handles sub-agent context
.claude/plugins/braintrust-tracing/hooks/user_prompt_submit.shCreates Turn spans per user message
.claude/plugins/braintrust-tracing/hooks/pre_tool_use.shInjects trace context into Task prompts
.claude/plugins/braintrust-tracing/hooks/post_tool_use.shCreates tool spans, captures agent/skill metadata
.claude/plugins/braintrust-tracing/hooks/stop_hook.shCreates LLM spans, finalizes Turns
.claude/plugins/braintrust-tracing/hooks/session_end.shFinalizes session, triggers learning extraction
scripts/braintrust_analyze.pyQuery and analyze traced sessions
~/.claude/state/braintrust_sessions/Per-session state files
~/.claude/state/braintrust_hook.logDebug log

Environment Variables

VariableRequiredDefaultDescription
TRACE_TO_BRAINTRUSTYes-Set to "true" to enable
BRAINTRUST_API_KEYYes-API key for Braintrust
BRAINTRUST_CC_PROJECTNoclaude-codeProject name
BRAINTRUST_CC_DEBUGNofalseVerbose logging
BRAINTRUST_API_URLNohttps://api.braintrust.devAPI endpoint

Session Learnings

What We Learned About Sub-Agent Tracing (Dec 2025)

Attempted: Inject trace context via PreToolUse into Task prompts.

Result: Failed - SessionStart only receives session metadata, not the prompt.

Discovery: Task spans already contain rich sub-agent data:

  • metadata.agent_type - agent type from subagent_type
  • metadata.skill_name - skill from Skill tool
  • tool_input - full prompt sent to agent
  • tool_output - agent response

Current correlation path:

  1. Parent session Task span has agentId and timing
  2. Sub-agent creates orphaned trace with root_span_id = session_id
  3. SubagentStop provides the sub-agent's session_id
  4. Manual correlation: match timing or use session_id link

Future work: Write child_session_id to Task span metadata from PostToolUse after SubagentStop.

What We Learned About Sub-Agent Correlation

The Problem

  • Sub-agents spawned via Task tool create orphaned Braintrust traces
  • Parent session has Task spans with agentId, sub-agent has separate session_id
  • No built-in link between them

What DOESN'T Work

1. Prompt injection via PreToolUse

SessionStart hook only receives session metadata (session_id, type, cwd), NOT the prompt. Injected trace context is never seen.

The hook receives:

json
{  "session_id": "...",  "type": "start|resume|compact|clear",  "cwd": "...",  "env": {...}}

No prompt field exists - context injection is impossible at SessionStart.

2. SubagentStop → PostToolUse file handoff

Race condition. These are independent async hooks with no timing guarantees:

  • SubagentStop fires when sub-agent session ends
  • PostToolUse (Task) fires when Task tool completes
  • No ordering guarantee between them
  • Writing to a correlation file creates a race

3. PreToolUse correlation files

SessionStart can't access the task_span_id because it has no context about which Task spawned it. PreToolUse modifies prompts but doesn't create a reliably accessible state file that SessionStart can find.

What DOES Work

Post-hoc matching for dataset building:

Parent session Task spans contain:

  • agentId - identifier for the sub-agent run
  • totalTokens, totalToolUseCount - aggregated metrics
  • content - full agent response/summary
  • tool_input.prompt - original task prompt
  • tool_input.subagent_type - agent type (e.g., "oracle")
  • Start/end timestamps

Sub-agent sessions contain:

  • session_id (equals orphaned trace root_span_id)
  • Start/end timestamps
  • All internal spans and tool calls

Correlation strategy:

  1. Export parent session traces (query parent root_span_id)
  2. Export sub-agent traces (query all sessions created within parent's time window)
  3. Match by:
    • Timing: Task span end ≈ sub-agent session end
    • Metadata: subagent_type from Task prompt
    • IDs: SubagentStop hook provides session_id (can be captured and logged)

Architecture Insight

SessionStart input is intentionally minimal - it contains no prompt or tool context:

typescript
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}

This design boundary prevents real-time correlation at hook time.

Recommendation

For building agent run datasets with sub-agent correlation:

  1. In-session logging: Capture SubagentStop session_id in logs or state
  2. Post-session export: Query Braintrust API for parent and sub-agent traces
  3. Offline correlation: Match traces by timing and metadata in a script
  4. Don't try real-time linking: Hooks don't have necessary context

Example script pattern:

bash
# 1. Export parent sessionbraintrust_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

This approach is reliable, testable, and doesn't require hooks to maintain implicit state.

來源與署名

來源:parcadei/continuous-claude-v3位於.claude/skills/braintrust-tracing提交d07ff4b

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架