[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7EXESQ187MXWC94QWS089SC":3,"skill-same:01M7EXESQ187MXWC94QWS089SC":46},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":27,"repositoryHtmlUrl":28,"repositoryHomepageUrl":6,"ownerHtmlUrl":29,"ownerBlogUrl":6,"ownerDescription":30,"updatedAt":31,"install":32,"resources":45},"01M7EXESQ187MXWC94QWS089SC","braintrust-tracing",null,"Braintrust tracing for Claude Code - hook architecture, sub-agent correlation, debugging","lza6\u002FArmor-piercing-system-prompts","lza6","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F128880206?v=4","01M7EB3K7WPX5T28EJ2NVHE6EG","Chinese-tingfeng","01M7EB3K97E1KQ16QWKJMFNGX8",11,"MIT","https:\u002F\u002Fgithub.com\u002Flza6\u002FArmor-piercing-system-prompts\u002Fblob\u002Fmain\u002F05-技能与代理开发\u002Fbraintrust-tracing\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: braintrust-tracing\ndescription: Braintrust tracing for Claude Code - hook architecture, sub-agent correlation, debugging\nuser-invocable: false\n---\n\n# Braintrust Tracing for Claude Code\n\nComprehensive guide to tracing Claude Code sessions in Braintrust, including sub-agent correlation.\n\n## Architecture Overview\n\n```\n                         PARENT SESSION\n                    +---------------------+\n                    |  SessionStart       |\n                    |  (creates root)     |\n                    +----------+----------+\n                               |\n                    +----------v----------+\n                    |  UserPromptSubmit   |\n                    |  (creates Turn)     |\n                    +----------+----------+\n                               |\n          +--------------------+--------------------+\n          |                    |                    |\n+---------v--------+  +--------v--------+  +--------v--------+\n| PostToolUse      |  | PostToolUse     |  | PreToolUse      |\n| (Read span)      |  | (Edit span)     |  | (Task - inject) |\n+------------------+  +-----------------+  +--------+--------+\n                                                    |\n                                         +----------v----------+\n                                         |   SUB-AGENT         |\n                                         |   SessionStart      |\n                                         |   (NEW root_span_id)|\n                                         +----------+----------+\n                                                    |\n                                         +----------v----------+\n                                         |   SubagentStop      |\n                                         |   (has session_id)  |\n                                         +---------------------+\n```\n\n## Hook Event Flow\n\n| Hook | Trigger | Creates | Key Fields |\n|------|---------|---------|------------|\n| **SessionStart** | Session begins | Root span | `session_id`, `root_span_id` |\n| **UserPromptSubmit** | User sends prompt | Turn span | `prompt`, `turn_number` |\n| **PreToolUse** | Before tool runs | (modifies Task prompts) | `tool_input.prompt` |\n| **PostToolUse** | After tool runs | Tool span | `tool_name`, `input`, `output` |\n| **Stop** | Turn completes | LLM spans | `model`, `tokens`, `tool_calls` |\n| **SubagentStop** | Sub-agent finishes | (no span) | `session_id` of sub-agent |\n| **SessionEnd** | Session ends | (finalizes root) | `turn_count`, `tool_count` |\n\n## Trace Hierarchy\n\n```\nSession (task span) - root_span_id = session_id\n|\n+-- Turn 1 (task span)\n|   |\n|   +-- claude-sonnet (llm span) - model call with tool_use\n|   +-- Read (tool span)\n|   +-- Edit (tool span)\n|   +-- claude-sonnet (llm span) - response after tools\n|\n+-- Turn 2 (task span)\n|   |\n|   +-- claude-sonnet (llm span)\n|   +-- Task (tool span) -----> [Sub-agent session - SEPARATE trace]\n|   +-- claude-sonnet (llm span)\n|\n+-- Turn 3 ...\n```\n\n## Sub-Agent Tracing: What Works and What Doesn't\n\n### What Doesn't Work\n\n**SessionStart doesn't receive the Task prompt.**\n\nWe tried injecting trace context into Task prompts via PreToolUse:\n\n```bash\n# PreToolUse hook injects:\n[BRAINTRUST_TRACE_CONTEXT]\n{\"root_span_id\": \"abc\", \"parent_span_id\": \"xyz\", \"project_id\": \"123\"}\n[\u002FBRAINTRUST_TRACE_CONTEXT]\n```\n\nBut SessionStart only receives session metadata, not the modified prompt. The injected context is lost.\n\n### What DOES Work\n\n**Task spans in parent session contain everything:**\n- `agentId` - identifier for the sub-agent run\n- `totalTokens`, `totalToolUseCount` - metrics\n- `content` - full agent response\u002Fsummary\n- `tool_input.prompt` - original task prompt\n- `tool_input.subagent_type` - agent type (e.g., \"oracle\")\n\n**SubagentStop hook receives the sub-agent's `session_id`:**\n- This equals the sub-agent's orphaned trace `root_span_id`\n- Allows correlation between parent Task span and child trace\n\n### The Correlation Pattern\n\n**Current state:** Sub-agents create orphaned traces (new `root_span_id`).\n\n**Correlation method:**\n1. Query parent session's Task spans for agent metadata\n2. Match `agentId` or timing with orphaned traces\n3. Sub-agent's `session_id` = its trace's `root_span_id`\n\n**Future solution (not yet implemented):**\n```\nSubagentStop fires -> writes session_id to temp file\nPostToolUse (Task) -> reads temp file -> adds child_session_id to Task span metadata\n```\n\nThis would link: `Task.agentId` + `Task.child_session_id` -> orphaned trace `root_span_id`\n\n## State Management\n\n### Per-Session State Files\n\n```\n~\u002F.claude\u002Fstate\u002Fbraintrust_sessions\u002F\n  {session_id}.json       # Per-session state\n```\n\nEach session file contains:\n```json\n{\n  \"root_span_id\": \"abc-123\",\n  \"project_id\": \"proj-456\",\n  \"turn_count\": 5,\n  \"tool_count\": 23,\n  \"current_turn_span_id\": \"turn-789\",\n  \"current_turn_start\": 1703456789,\n  \"started\": \"2025-12-24T10:00:00.000Z\",\n  \"is_subagent\": false\n}\n```\n\n### Global State\n```\n~\u002F.claude\u002Fstate\u002Fbraintrust_global.json   # Cached project_id\n~\u002F.claude\u002Fstate\u002Fbraintrust_hook.log      # Debug log\n```\n\n## Debugging Commands\n\n### Check if Tracing is Active\n```bash\n# View hook logs in real-time\ntail -f ~\u002F.claude\u002Fstate\u002Fbraintrust_hook.log\n\n# Check if session has state\ncat ~\u002F.claude\u002Fstate\u002Fbraintrust_sessions\u002F*.json | jq -s '.'\n\n# Verify environment\necho \"TRACE_TO_BRAINTRUST=$TRACE_TO_BRAINTRUST\"\necho \"BRAINTRUST_API_KEY=${BRAINTRUST_API_KEY:+set}\"\n```\n\n### Query Braintrust Directly\n```bash\n# List recent sessions\nuv run python -m runtime.harness scripts\u002Fbraintrust_analyze.py --sessions 5\n\n# Analyze last session\nuv run python -m runtime.harness scripts\u002Fbraintrust_analyze.py --last-session\n\n# Replay specific session\nuv run python -m runtime.harness scripts\u002Fbraintrust_analyze.py --replay \u003Csession-id>\n\n# Find sub-agent traces (orphaned roots)\nuv run python -m runtime.harness scripts\u002Fbraintrust_analyze.py --agent-stats\n```\n\n### Debug Hook Execution\n```bash\n# Enable verbose logging\nexport BRAINTRUST_CC_DEBUG=true\n\n# Test hooks manually\necho '{\"session_id\":\"test-123\",\"type\":\"resume\"}' | \\\n  bash \"$CLAUDE_PROJECT_DIR\u002F.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fsession_start.sh\"\n\n# Test PreToolUse (Task injection)\necho '{\"session_id\":\"test-123\",\"tool_name\":\"Task\",\"tool_input\":{\"prompt\":\"test\"}}' | \\\n  bash \"$CLAUDE_PROJECT_DIR\u002F.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fpre_tool_use.sh\"\n```\n\n### Troubleshooting Checklist\n\n1. **No traces appearing:**\n   - Check `TRACE_TO_BRAINTRUST=true` in `.claude\u002Fsettings.local.json`\n   - Verify API key: `echo $BRAINTRUST_API_KEY`\n   - Check logs: `tail -20 ~\u002F.claude\u002Fstate\u002Fbraintrust_hook.log`\n\n2. **Sub-agents not linking:**\n   - This is expected - sub-agents create orphaned traces\n   - Use `--agent-stats` to find agent activity\n   - Correlate via timing or `agentId` in parent Task span\n\n3. **Missing spans:**\n   - Check `current_turn_span_id` in session state\n   - Ensure Stop hook runs (turn finalization)\n   - Look for \"Failed to create\" errors in log\n\n4. **State corruption:**\n   - Remove session state: `rm ~\u002F.claude\u002Fstate\u002Fbraintrust_sessions\u002F*.json`\n   - Clear global cache: `rm ~\u002F.claude\u002Fstate\u002Fbraintrust_global.json`\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fcommon.sh` | Shared utilities, API, state management |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fsession_start.sh` | Creates root span, handles sub-agent context |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fuser_prompt_submit.sh` | Creates Turn spans per user message |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fpre_tool_use.sh` | Injects trace context into Task prompts |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fpost_tool_use.sh` | Creates tool spans, captures agent\u002Fskill metadata |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fstop_hook.sh` | Creates LLM spans, finalizes Turns |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fsession_end.sh` | Finalizes session, triggers learning extraction |\n| `scripts\u002Fbraintrust_analyze.py` | Query and analyze traced sessions |\n| `~\u002F.claude\u002Fstate\u002Fbraintrust_sessions\u002F` | Per-session state files |\n| `~\u002F.claude\u002Fstate\u002Fbraintrust_hook.log` | Debug log |\n\n## Environment Variables\n\n| Variable | Required | Default | Description |\n|----------|----------|---------|-------------|\n| `TRACE_TO_BRAINTRUST` | Yes | - | Set to `\"true\"` to enable |\n| `BRAINTRUST_API_KEY` | Yes | - | API key for Braintrust |\n| `BRAINTRUST_CC_PROJECT` | No | `claude-code` | Project name |\n| `BRAINTRUST_CC_DEBUG` | No | `false` | Verbose logging |\n| `BRAINTRUST_API_URL` | No | `https:\u002F\u002Fapi.braintrust.dev` | API endpoint |\n\n## Session Learnings\n\n### What We Learned About Sub-Agent Tracing (Dec 2025)\n\n**Attempted:** Inject trace context via PreToolUse into Task prompts.\n\n**Result:** Failed - SessionStart only receives session metadata, not the prompt.\n\n**Discovery:** Task spans already contain rich sub-agent data:\n- `metadata.agent_type` - agent type from `subagent_type`\n- `metadata.skill_name` - skill from Skill tool\n- `tool_input` - full prompt sent to agent\n- `tool_output` - agent response\n\n**Current correlation path:**\n1. Parent session Task span has `agentId` and timing\n2. Sub-agent creates orphaned trace with `root_span_id = session_id`\n3. SubagentStop provides the sub-agent's `session_id`\n4. Manual correlation: match timing or use `session_id` link\n\n**Future work:** Write `child_session_id` to Task span metadata from PostToolUse after SubagentStop.\n\n## What We Learned About Sub-Agent Correlation\n\n### The Problem\n\n- Sub-agents spawned via Task tool create orphaned Braintrust traces\n- Parent session has Task spans with `agentId`, sub-agent has separate `session_id`\n- No built-in link between them\n\n### What DOESN'T Work\n\n**1. Prompt injection via PreToolUse**\n\nSessionStart hook only receives session metadata (`session_id`, `type`, `cwd`), NOT the prompt. Injected trace context is never seen.\n\nThe hook receives:\n```json\n{\n  \"session_id\": \"...\",\n  \"type\": \"start|resume|compact|clear\",\n  \"cwd\": \"...\",\n  \"env\": {...}\n}\n```\n\nNo prompt field exists - context injection is impossible at SessionStart.\n\n**2. SubagentStop → PostToolUse file handoff**\n\nRace condition. These are independent async hooks with no timing guarantees:\n- SubagentStop fires when sub-agent session ends\n- PostToolUse (Task) fires when Task tool completes\n- No ordering guarantee between them\n- Writing to a correlation file creates a race\n\n**3. PreToolUse correlation files**\n\nSessionStart 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.\n\n### What DOES Work\n\n**Post-hoc matching for dataset building:**\n\nParent session Task spans contain:\n- `agentId` - identifier for the sub-agent run\n- `totalTokens`, `totalToolUseCount` - aggregated metrics\n- `content` - full agent response\u002Fsummary\n- `tool_input.prompt` - original task prompt\n- `tool_input.subagent_type` - agent type (e.g., \"oracle\")\n- Start\u002Fend timestamps\n\nSub-agent sessions contain:\n- `session_id` (equals orphaned trace `root_span_id`)\n- Start\u002Fend timestamps\n- All internal spans and tool calls\n\n**Correlation strategy:**\n1. Export parent session traces (query parent `root_span_id`)\n2. Export sub-agent traces (query all sessions created within parent's time window)\n3. Match by:\n   - Timing: Task span end ≈ sub-agent session end\n   - Metadata: `subagent_type` from Task prompt\n   - IDs: SubagentStop hook provides `session_id` (can be captured and logged)\n\n### Architecture Insight\n\nSessionStart input is intentionally minimal - it contains no prompt or tool context:\n\n```typescript\ninterface SessionStartInput {\n  session_id: string;\n  type: \"start\" | \"resume\" | \"compact\" | \"clear\";\n  cwd: string;\n  env: { [key: string]: string };\n  \u002F\u002F NO: prompt, tool_context, task_span_id, parent_span_id\n}\n```\n\nThis design boundary prevents real-time correlation at hook time.\n\n### Recommendation\n\nFor building agent run datasets with sub-agent correlation:\n\n1. **In-session logging:** Capture SubagentStop `session_id` in logs or state\n2. **Post-session export:** Query Braintrust API for parent and sub-agent traces\n3. **Offline correlation:** Match traces by timing and metadata in a script\n4. **Don't try real-time linking:** Hooks don't have necessary context\n\nExample script pattern:\n```bash\n# 1. Export parent session\nbraintrust_analyze.py --replay \u003Cparent-session-id> > parent_traces.json\n\n# 2. Query for orphaned sub-agent traces (those created during parent's time window)\nbraintrust_analyze.py --agent-stats > all_agent_traces.json\n\n# 3. Correlate in Python:\n#    - Parent Task spans -> agentId, timestamps, subagent_type\n#    - Orphaned traces -> root_span_id, timestamps\n#    - Match by timing and type\n```\n\nThis approach is reliable, testable, and doesn't require hooks to maintain implicit state.\n","# Braintrust Tracing for Claude Code\n\nComprehensive guide to tracing Claude Code sessions in Braintrust, including sub-agent correlation.\n\n## Architecture Overview\n\n```\n                         PARENT SESSION\n                    +---------------------+\n                    |  SessionStart       |\n                    |  (creates root)     |\n                    +----------+----------+\n                               |\n                    +----------v----------+\n                    |  UserPromptSubmit   |\n                    |  (creates Turn)     |\n                    +----------+----------+\n                               |\n          +--------------------+--------------------+\n          |                    |                    |\n+---------v--------+  +--------v--------+  +--------v--------+\n| PostToolUse      |  | PostToolUse     |  | PreToolUse      |\n| (Read span)      |  | (Edit span)     |  | (Task - inject) |\n+------------------+  +-----------------+  +--------+--------+\n                                                    |\n                                         +----------v----------+\n                                         |   SUB-AGENT         |\n                                         |   SessionStart      |\n                                         |   (NEW root_span_id)|\n                                         +----------+----------+\n                                                    |\n                                         +----------v----------+\n                                         |   SubagentStop      |\n                                         |   (has session_id)  |\n                                         +---------------------+\n```\n\n## Hook Event Flow\n\n| Hook | Trigger | Creates | Key Fields |\n|------|---------|---------|------------|\n| **SessionStart** | Session begins | Root span | `session_id`, `root_span_id` |\n| **UserPromptSubmit** | User sends prompt | Turn span | `prompt`, `turn_number` |\n| **PreToolUse** | Before tool runs | (modifies Task prompts) | `tool_input.prompt` |\n| **PostToolUse** | After tool runs | Tool span | `tool_name`, `input`, `output` |\n| **Stop** | Turn completes | LLM spans | `model`, `tokens`, `tool_calls` |\n| **SubagentStop** | Sub-agent finishes | (no span) | `session_id` of sub-agent |\n| **SessionEnd** | Session ends | (finalizes root) | `turn_count`, `tool_count` |\n\n## Trace Hierarchy\n\n```\nSession (task span) - root_span_id = session_id\n|\n+-- Turn 1 (task span)\n|   |\n|   +-- claude-sonnet (llm span) - model call with tool_use\n|   +-- Read (tool span)\n|   +-- Edit (tool span)\n|   +-- claude-sonnet (llm span) - response after tools\n|\n+-- Turn 2 (task span)\n|   |\n|   +-- claude-sonnet (llm span)\n|   +-- Task (tool span) -----> [Sub-agent session - SEPARATE trace]\n|   +-- claude-sonnet (llm span)\n|\n+-- Turn 3 ...\n```\n\n## Sub-Agent Tracing: What Works and What Doesn't\n\n### What Doesn't Work\n\n**SessionStart doesn't receive the Task prompt.**\n\nWe tried injecting trace context into Task prompts via PreToolUse:\n\n```bash\n# PreToolUse hook injects:\n[BRAINTRUST_TRACE_CONTEXT]\n{\"root_span_id\": \"abc\", \"parent_span_id\": \"xyz\", \"project_id\": \"123\"}\n[\u002FBRAINTRUST_TRACE_CONTEXT]\n```\n\nBut SessionStart only receives session metadata, not the modified prompt. The injected context is lost.\n\n### What DOES Work\n\n**Task spans in parent session contain everything:**\n- `agentId` - identifier for the sub-agent run\n- `totalTokens`, `totalToolUseCount` - metrics\n- `content` - full agent response\u002Fsummary\n- `tool_input.prompt` - original task prompt\n- `tool_input.subagent_type` - agent type (e.g., \"oracle\")\n\n**SubagentStop hook receives the sub-agent's `session_id`:**\n- This equals the sub-agent's orphaned trace `root_span_id`\n- Allows correlation between parent Task span and child trace\n\n### The Correlation Pattern\n\n**Current state:** Sub-agents create orphaned traces (new `root_span_id`).\n\n**Correlation method:**\n1. Query parent session's Task spans for agent metadata\n2. Match `agentId` or timing with orphaned traces\n3. Sub-agent's `session_id` = its trace's `root_span_id`\n\n**Future solution (not yet implemented):**\n```\nSubagentStop fires -> writes session_id to temp file\nPostToolUse (Task) -> reads temp file -> adds child_session_id to Task span metadata\n```\n\nThis would link: `Task.agentId` + `Task.child_session_id` -> orphaned trace `root_span_id`\n\n## State Management\n\n### Per-Session State Files\n\n```\n~\u002F.claude\u002Fstate\u002Fbraintrust_sessions\u002F\n  {session_id}.json       # Per-session state\n```\n\nEach session file contains:\n```json\n{\n  \"root_span_id\": \"abc-123\",\n  \"project_id\": \"proj-456\",\n  \"turn_count\": 5,\n  \"tool_count\": 23,\n  \"current_turn_span_id\": \"turn-789\",\n  \"current_turn_start\": 1703456789,\n  \"started\": \"2025-12-24T10:00:00.000Z\",\n  \"is_subagent\": false\n}\n```\n\n### Global State\n```\n~\u002F.claude\u002Fstate\u002Fbraintrust_global.json   # Cached project_id\n~\u002F.claude\u002Fstate\u002Fbraintrust_hook.log      # Debug log\n```\n\n## Debugging Commands\n\n### Check if Tracing is Active\n```bash\n# View hook logs in real-time\ntail -f ~\u002F.claude\u002Fstate\u002Fbraintrust_hook.log\n\n# Check if session has state\ncat ~\u002F.claude\u002Fstate\u002Fbraintrust_sessions\u002F*.json | jq -s '.'\n\n# Verify environment\necho \"TRACE_TO_BRAINTRUST=$TRACE_TO_BRAINTRUST\"\necho \"BRAINTRUST_API_KEY=${BRAINTRUST_API_KEY:+set}\"\n```\n\n### Query Braintrust Directly\n```bash\n# List recent sessions\nuv run python -m runtime.harness scripts\u002Fbraintrust_analyze.py --sessions 5\n\n# Analyze last session\nuv run python -m runtime.harness scripts\u002Fbraintrust_analyze.py --last-session\n\n# Replay specific session\nuv run python -m runtime.harness scripts\u002Fbraintrust_analyze.py --replay \u003Csession-id>\n\n# Find sub-agent traces (orphaned roots)\nuv run python -m runtime.harness scripts\u002Fbraintrust_analyze.py --agent-stats\n```\n\n### Debug Hook Execution\n```bash\n# Enable verbose logging\nexport BRAINTRUST_CC_DEBUG=true\n\n# Test hooks manually\necho '{\"session_id\":\"test-123\",\"type\":\"resume\"}' | \\\n  bash \"$CLAUDE_PROJECT_DIR\u002F.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fsession_start.sh\"\n\n# Test PreToolUse (Task injection)\necho '{\"session_id\":\"test-123\",\"tool_name\":\"Task\",\"tool_input\":{\"prompt\":\"test\"}}' | \\\n  bash \"$CLAUDE_PROJECT_DIR\u002F.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fpre_tool_use.sh\"\n```\n\n### Troubleshooting Checklist\n\n1. **No traces appearing:**\n   - Check `TRACE_TO_BRAINTRUST=true` in `.claude\u002Fsettings.local.json`\n   - Verify API key: `echo $BRAINTRUST_API_KEY`\n   - Check logs: `tail -20 ~\u002F.claude\u002Fstate\u002Fbraintrust_hook.log`\n\n2. **Sub-agents not linking:**\n   - This is expected - sub-agents create orphaned traces\n   - Use `--agent-stats` to find agent activity\n   - Correlate via timing or `agentId` in parent Task span\n\n3. **Missing spans:**\n   - Check `current_turn_span_id` in session state\n   - Ensure Stop hook runs (turn finalization)\n   - Look for \"Failed to create\" errors in log\n\n4. **State corruption:**\n   - Remove session state: `rm ~\u002F.claude\u002Fstate\u002Fbraintrust_sessions\u002F*.json`\n   - Clear global cache: `rm ~\u002F.claude\u002Fstate\u002Fbraintrust_global.json`\n\n## Key Files\n\n| File | Purpose |\n|------|---------|\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fcommon.sh` | Shared utilities, API, state management |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fsession_start.sh` | Creates root span, handles sub-agent context |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fuser_prompt_submit.sh` | Creates Turn spans per user message |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fpre_tool_use.sh` | Injects trace context into Task prompts |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fpost_tool_use.sh` | Creates tool spans, captures agent\u002Fskill metadata |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fstop_hook.sh` | Creates LLM spans, finalizes Turns |\n| `.claude\u002Fplugins\u002Fbraintrust-tracing\u002Fhooks\u002Fsession_end.sh` | Finalizes session, triggers learning extraction |\n| `scripts\u002Fbraintrust_analyze.py` | Query and analyze traced sessions |\n| `~\u002F.claude\u002Fstate\u002Fbraintrust_sessions\u002F` | Per-session state files |\n| `~\u002F.claude\u002Fstate\u002Fbraintrust_hook.log` | Debug log |\n\n## Environment Variables\n\n| Variable | Required | Default | Description |\n|----------|----------|---------|-------------|\n| `TRACE_TO_BRAINTRUST` | Yes | - | Set to `\"true\"` to enable |\n| `BRAINTRUST_API_KEY` | Yes | - | API key for Braintrust |\n| `BRAINTRUST_CC_PROJECT` | No | `claude-code` | Project name |\n| `BRAINTRUST_CC_DEBUG` | No | `false` | Verbose logging |\n| `BRAINTRUST_API_URL` | No | `https:\u002F\u002Fapi.braintrust.dev` | API endpoint |\n\n## Session Learnings\n\n### What We Learned About Sub-Agent Tracing (Dec 2025)\n\n**Attempted:** Inject trace context via PreToolUse into Task prompts.\n\n**Result:** Failed - SessionStart only receives session metadata, not the prompt.\n\n**Discovery:** Task spans already contain rich sub-agent data:\n- `metadata.agent_type` - agent type from `subagent_type`\n- `metadata.skill_name` - skill from Skill tool\n- `tool_input` - full prompt sent to agent\n- `tool_output` - agent response\n\n**Current correlation path:**\n1. Parent session Task span has `agentId` and timing\n2. Sub-agent creates orphaned trace with `root_span_id = session_id`\n3. SubagentStop provides the sub-agent's `session_id`\n4. Manual correlation: match timing or use `session_id` link\n\n**Future work:** Write `child_session_id` to Task span metadata from PostToolUse after SubagentStop.\n\n## What We Learned About Sub-Agent Correlation\n\n### The Problem\n\n- Sub-agents spawned via Task tool create orphaned Braintrust traces\n- Parent session has Task spans with `agentId`, sub-agent has separate `session_id`\n- No built-in link between them\n\n### What DOESN'T Work\n\n**1. Prompt injection via PreToolUse**\n\nSessionStart hook only receives session metadata (`session_id`, `type`, `cwd`), NOT the prompt. Injected trace context is never seen.\n\nThe hook receives:\n```json\n{\n  \"session_id\": \"...\",\n  \"type\": \"start|resume|compact|clear\",\n  \"cwd\": \"...\",\n  \"env\": {...}\n}\n```\n\nNo prompt field exists - context injection is impossible at SessionStart.\n\n**2. SubagentStop → PostToolUse file handoff**\n\nRace condition. These are independent async hooks with no timing guarantees:\n- SubagentStop fires when sub-agent session ends\n- PostToolUse (Task) fires when Task tool completes\n- No ordering guarantee between them\n- Writing to a correlation file creates a race\n\n**3. PreToolUse correlation files**\n\nSessionStart 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.\n\n### What DOES Work\n\n**Post-hoc matching for dataset building:**\n\nParent session Task spans contain:\n- `agentId` - identifier for the sub-agent run\n- `totalTokens`, `totalToolUseCount` - aggregated metrics\n- `content` - full agent response\u002Fsummary\n- `tool_input.prompt` - original task prompt\n- `tool_input.subagent_type` - agent type (e.g., \"oracle\")\n- Start\u002Fend timestamps\n\nSub-agent sessions contain:\n- `session_id` (equals orphaned trace `root_span_id`)\n- Start\u002Fend timestamps\n- All internal spans and tool calls\n\n**Correlation strategy:**\n1. Export parent session traces (query parent `root_span_id`)\n2. Export sub-agent traces (query all sessions created within parent's time window)\n3. Match by:\n   - Timing: Task span end ≈ sub-agent session end\n   - Metadata: `subagent_type` from Task prompt\n   - IDs: SubagentStop hook provides `session_id` (can be captured and logged)\n\n### Architecture Insight\n\nSessionStart input is intentionally minimal - it contains no prompt or tool context:\n\n```typescript\ninterface SessionStartInput {\n  session_id: string;\n  type: \"start\" | \"resume\" | \"compact\" | \"clear\";\n  cwd: string;\n  env: { [key: string]: string };\n  \u002F\u002F NO: prompt, tool_context, task_span_id, parent_span_id\n}\n```\n\nThis design boundary prevents real-time correlation at hook time.\n\n### Recommendation\n\nFor building agent run datasets with sub-agent correlation:\n\n1. **In-session logging:** Capture SubagentStop `session_id` in logs or state\n2. **Post-session export:** Query Braintrust API for parent and sub-agent traces\n3. **Offline correlation:** Match traces by timing and metadata in a script\n4. **Don't try real-time linking:** Hooks don't have necessary context\n\nExample script pattern:\n```bash\n# 1. Export parent session\nbraintrust_analyze.py --replay \u003Cparent-session-id> > parent_traces.json\n\n# 2. Query for orphaned sub-agent traces (those created during parent's time window)\nbraintrust_analyze.py --agent-stats > all_agent_traces.json\n\n# 3. Correlate in Python:\n#    - Parent Task spans -> agentId, timestamps, subagent_type\n#    - Orphaned traces -> root_span_id, timestamps\n#    - Match by timing and type\n```\n\nThis approach is reliable, testable, and doesn't require hooks to maintain implicit state.\n",{"name":5,"description":7,"user-invocable":20},"main","d69096e239f2a89aabc2cd078c47664a9d3b1e11","05-技能与代理开发\u002Fbraintrust-tracing",3,"https:\u002F\u002Fgithub.com\u002Flza6\u002FArmor-piercing-system-prompts","https:\u002F\u002Fgithub.com\u002Flza6","个人vx：Tf00798\r\n个人✈：@TFGY999","2026-10-08 14:29:22",{"source":8,"skillName":5,"commands":33,"prompt":43,"zipAvailable":44},[34,37,40],{"tool":35,"command":36},"npx","npx skills add lza6\u002FArmor-piercing-system-prompts --skill braintrust-tracing",{"tool":38,"command":39},"bunx","bunx skills add lza6\u002FArmor-piercing-system-prompts --skill braintrust-tracing",{"tool":41,"command":42},"pnpm","pnpm dlx skills add lza6\u002FArmor-piercing-system-prompts --skill braintrust-tracing","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Flza6\u002FArmor-piercing-system-prompts\u002Fblob\u002Fmain\u002F05-技能与代理开发\u002Fbraintrust-tracing\u002FSKILL.md",true,[],[47,54,61,68,76,83],{"skillNo":48,"name":49,"nameZh":6,"description":50,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":51,"categories":52,"keywords":53,"publishedAt":19},"01M7EXRM12046G0GM1WGMMFXCN","ci-cd-and-automation","Automates CI\u002FCD pipeline setup. Use when setting up or modifying build and deployment pipelines. Use when you need to automate quality gates, configure test runners in CI, or establish deployment strategies.","https:\u002F\u002Fgithub.com\u002Flza6\u002FArmor-piercing-system-prompts\u002Fblob\u002Fmain\u002F05-技能与代理开发\u002Fci-cd-and-automation\u002FSKILL.md",[],[],{"skillNo":55,"name":56,"nameZh":6,"description":57,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":58,"categories":59,"keywords":60,"publishedAt":19},"01M7EXRFYYSJ3Y15AGPDDEWWQD","chrome-devtools","Uses Chrome DevTools via MCP for efficient debugging, troubleshooting and browser automation. Use when debugging web pages, automating browser interactions, analyzing performance, or inspecting network requests. This skill does not apply to `--slim` mode (MCP configuration).","https:\u002F\u002Fgithub.com\u002Flza6\u002FArmor-piercing-system-prompts\u002Fblob\u002Fmain\u002F05-技能与代理开发\u002Fchrome-devtools\u002FSKILL.md",[],[],{"skillNo":62,"name":63,"nameZh":6,"description":64,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":65,"categories":66,"keywords":67,"publishedAt":19},"01M7EXR6EYPE4X5X1BTAE6QJRV","chrome-cdp","Drive a real Chrome via the Chrome DevTools Protocol (CDP). Ensures a\ndebuggable Chrome is running (launching it if needed) so the agent can\nnavigate, read page content, inspect the DOM, run JavaScript, and take\nscreenshots — without the user typing any launch command. Includes a\nfirst-class \"review a live running app\" flow: point Chrome at the app under\ndevelopment and inspect\u002Fscreenshot the REAL page (what a static-artifact tool\ncannot do). Backed by Glimpse and the chrome-devtools MCP server. Use when\nasked to \"use chrome\", \"open chrome\", \"drive my browser\", \"read the page in\nchrome\", \"review the running app\", \"screenshot the app\", or \"\u002Fchrome-cdp\".","https:\u002F\u002Fgithub.com\u002Flza6\u002FArmor-piercing-system-prompts\u002Fblob\u002Fmain\u002F05-技能与代理开发\u002Fchrome-cdp\u002FSKILL.md",[],[],{"skillNo":69,"name":70,"nameZh":6,"description":71,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":72,"licenseFileUrl":6,"sourceHtmlUrl":73,"categories":74,"keywords":75,"publishedAt":19},"01M7EXR1Y7E79KQKG4J798XGH6","check-identity-pack","Run an AFP 100-point or AUSTRAC safe-harbour identity check over a set of documents, and report exactly what's missing. Use when the user asks to check identity documents, verify someone's ID for onboarding, or assess whether a document pack satisfies Australian identity requirements.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Flza6\u002FArmor-piercing-system-prompts\u002Fblob\u002Fmain\u002F05-技能与代理开发\u002Fcheck-identity-pack\u002FSKILL.md",[],[],{"skillNo":77,"name":78,"nameZh":6,"description":79,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":82,"publishedAt":19},"01M7EXQXW7C7PGREJW9ZZTZ16H","changelog","Auto-generates a changelog from git commits, sprint data, and design documents. Produces both internal and player-facing versions.","https:\u002F\u002Fgithub.com\u002Flza6\u002FArmor-piercing-system-prompts\u002Fblob\u002Fmain\u002F05-技能与代理开发\u002Fchangelog\u002FSKILL.md",[],[],{"skillNo":84,"name":85,"nameZh":6,"description":86,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":89,"publishedAt":19},"01M7EXQMH2ZME3ANN8Q8MEWPFB","cellxgene-census","Query the CZ CELLxGENE Census programmatically for versioned public single-cell and spatial transcriptomics data. Use when you need population-scale cell metadata, gene expression slices, Census summary counts, source H5AD URIs\u002Fdownloads, embeddings, spatial Census data, or reference atlas comparisons across organisms, tissues, diseases, assays, and cell types. For analyzing your own local single-cell data use scanpy, anndata, or scvi-tools.","https:\u002F\u002Fgithub.com\u002Flza6\u002FArmor-piercing-system-prompts\u002Fblob\u002Fmain\u002F05-技能与代理开发\u002Fcellxgene-census\u002FSKILL.md",[],[]]