Create authoritative documentation suite for Claude Code JSONL session log processing, synthesized from codebase analysis, official Anthropic documentation, and community tooling research. Documentation structure (docs/claude-jsonl-reference/): 01-format-specification.md (214 lines): - Complete message envelope structure with all fields - Content block types (text, thinking, tool_use, tool_result) - Usage object for token reporting - Model identifiers and version history - Conversation DAG structure via parentUuid 02-message-types.md (346 lines): - Every message type with concrete JSON examples - User messages (string content vs array for tool results) - Assistant messages with all content block variants - Progress events (hooks, bash, MCP) - System, summary, and file-history-snapshot types - Codex format differences (response_item, function_call) 03-tool-lifecycle.md (341 lines): - Complete tool invocation to result flow - Hook input/output formats (PreToolUse, PostToolUse) - Parallel tool call handling - Tool-to-result pairing algorithm - Missing result edge cases - Codex tool format differences 04-subagent-teams.md (363 lines): - Task tool invocation and input fields - Subagent transcript locations and format - Team coordination (TeamCreate, SendMessage) - Hook events (SubagentStart, SubagentStop) - AMC spawn tracking with pending spawn registry - Worktree isolation for subagents 05-edge-cases.md (475 lines): - Parsing edge cases (invalid JSON, type ambiguity) - Type coercion gotchas (bool vs int in Python) - Session state edge cases (orphans, dead detection) - Tool call edge cases (missing results, parallel ordering) - Codex-specific quirks (content injection, buffering) - File system safety (path traversal, permissions) - Cache invalidation strategies 06-quick-reference.md (238 lines): - File locations cheat sheet - jq recipes for common queries - Python parsing snippets - Common gotchas table - Useful constants - Debugging commands Also adds CLAUDE.md at project root linking to documentation and providing project overview for agents working on AMC. Sources include Claude Code hooks.md, headless.md, Anthropic Messages API reference, and community tools (claude-code-log, claude-JSONL-browser). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
7.8 KiB
7.8 KiB
Tool Call Lifecycle
Complete documentation of how tool invocations flow through Claude JSONL logs.
Lifecycle Overview
1. Assistant message with tool_use block
↓
2. PreToolUse hook fires (optional)
↓
3. Tool executes
↓
4. PostToolUse hook fires (optional)
↓
5. User message with tool_result block
↓
6. Assistant processes result
Phase 1: Tool Invocation
Claude requests a tool via tool_use content block:
{
"type": "assistant",
"message": {
"role": "assistant",
"content": [
{
"type": "text",
"text": "I'll read that file for you."
},
{
"type": "tool_use",
"id": "toolu_01ReadFile123",
"name": "Read",
"input": {
"file_path": "/src/auth/login.ts",
"limit": 200
}
}
],
"stop_reason": null
},
"uuid": "msg-001"
}
Tool Use Block Structure
| Field | Type | Required | Description |
|---|---|---|---|
type |
"tool_use" |
Yes | Block type identifier |
id |
string | Yes | Unique tool call ID (format: toolu_*) |
name |
string | Yes | Tool name |
input |
object | Yes | Tool parameters |
Common Tool Names
| Tool | Purpose | Key Input Fields |
|---|---|---|
Read |
Read file | file_path, offset, limit |
Edit |
Edit file | file_path, old_string, new_string |
Write |
Create file | file_path, content |
Bash |
Run command | command, timeout |
Glob |
Find files | pattern, path |
Grep |
Search content | pattern, path, type |
WebFetch |
Fetch URL | url, prompt |
WebSearch |
Search web | query |
Task |
Spawn subagent | prompt, subagent_type |
AskUserQuestion |
Ask user | questions |
Phase 2: Hook Execution (Optional)
If hooks are configured, progress events are logged:
PreToolUse Hook Input
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../session.jsonl",
"cwd": "/Users/dev/myproject",
"permission_mode": "default",
"hook_event_name": "PreToolUse",
"tool_name": "Read",
"tool_input": {
"file_path": "/src/auth/login.ts"
}
}
Hook Progress Event
{
"type": "progress",
"data": {
"type": "hook_progress",
"hookEvent": "PreToolUse",
"hookName": "security_check",
"status": "running"
},
"parentToolUseID": "toolu_01ReadFile123",
"toolUseID": "toolu_01ReadFile123",
"uuid": "prog-001"
}
Hook Output (Decision)
{
"decision": "allow",
"reason": "File read permitted",
"additionalContext": "Note: This file was recently modified"
}
Phase 3: Tool Result
Tool output is wrapped in a user message:
{
"type": "user",
"message": {
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01ReadFile123",
"content": "1\texport async function login(email: string, password: string) {\n2\t const user = await db.users.findByEmail(email);\n..."
}
]
},
"uuid": "msg-002",
"parentUuid": "msg-001"
}
Tool Result Block Structure
| Field | Type | Required | Description |
|---|---|---|---|
type |
"tool_result" |
Yes | Block type identifier |
tool_use_id |
string | Yes | Matches tool_use.id |
content |
string | Yes | Tool output |
is_error |
boolean | No | True if tool failed |
Error Results
{
"type": "tool_result",
"tool_use_id": "toolu_01ReadFile123",
"content": "Error: File not found: /src/auth/login.ts",
"is_error": true
}
Phase 4: Result Processing
Claude processes the result and continues:
{
"type": "assistant",
"message": {
"content": [
{
"type": "thinking",
"thinking": "The login function looks correct. The issue might be in the middleware..."
},
{
"type": "text",
"text": "I see the login function. Let me check the middleware next."
},
{
"type": "tool_use",
"id": "toolu_01ReadMiddleware",
"name": "Read",
"input": {"file_path": "/src/auth/middleware.ts"}
}
]
},
"uuid": "msg-003",
"parentUuid": "msg-002"
}
Parallel Tool Calls
Multiple tools can be invoked in a single message:
{
"type": "assistant",
"message": {
"content": [
{"type": "tool_use", "id": "toolu_01A", "name": "Grep", "input": {"pattern": "TODO"}},
{"type": "tool_use", "id": "toolu_01B", "name": "Grep", "input": {"pattern": "FIXME"}},
{"type": "tool_use", "id": "toolu_01C", "name": "Glob", "input": {"pattern": "**/*.test.ts"}}
]
}
}
Results come back in the same user message:
{
"type": "user",
"message": {
"content": [
{"type": "tool_result", "tool_use_id": "toolu_01A", "content": "Found 15 TODOs"},
{"type": "tool_result", "tool_use_id": "toolu_01B", "content": "Found 3 FIXMEs"},
{"type": "tool_result", "tool_use_id": "toolu_01C", "content": "tests/auth.test.ts\ntests/api.test.ts"}
]
}
}
Codex Tool Format
Codex uses a different structure:
Function Call
{
"type": "response_item",
"payload": {
"type": "function_call",
"call_id": "call_abc123",
"name": "Read",
"arguments": "{\"file_path\": \"/src/auth/login.ts\"}"
}
}
Note: arguments is a JSON string that needs parsing.
Function Result
{
"type": "response_item",
"payload": {
"type": "function_call_result",
"call_id": "call_abc123",
"result": "File contents..."
}
}
Tool Call Pairing
To reconstruct tool call history:
- Find tool_use blocks in assistant messages
- Match by ID to tool_result blocks in following user messages
- Handle parallel calls — multiple tool_use can have multiple tool_result
# Example: Pairing tool calls with results
tool_calls = {}
for line in jsonl_file:
event = json.loads(line)
if event['type'] == 'assistant':
for block in event['message']['content']:
if block['type'] == 'tool_use':
tool_calls[block['id']] = {
'name': block['name'],
'input': block['input'],
'timestamp': event['timestamp']
}
elif event['type'] == 'user':
content = event['message']['content']
if isinstance(content, list):
for block in content:
if block['type'] == 'tool_result':
call_id = block['tool_use_id']
if call_id in tool_calls:
tool_calls[call_id]['result'] = block['content']
tool_calls[call_id]['is_error'] = block.get('is_error', False)
Missing Tool Results
Edge cases where tool results may be absent:
- Session interrupted — User closed session mid-tool
- Tool timeout — Long-running tool exceeded limits
- Hook blocked — PreToolUse hook returned
block - Permission denied — User denied tool permission
Handle by checking if tool_use has matching tool_result before assuming completion.
Tool-Specific Formats
Bash Tool
{
"type": "tool_use",
"name": "Bash",
"input": {
"command": "npm test -- --coverage",
"timeout": 120000,
"description": "Run tests with coverage"
}
}
Result includes exit code context:
{
"type": "tool_result",
"content": "PASS src/auth.test.ts\n...\nCoverage: 85%\n\n[Exit code: 0]"
}
Task Tool (Subagent)
{
"type": "tool_use",
"name": "Task",
"input": {
"description": "Research auth patterns",
"prompt": "Explore authentication implementations...",
"subagent_type": "Explore"
}
}
Result returns subagent output:
{
"type": "tool_result",
"content": "## Research Findings\n\n1. JWT patterns...\n\nagentId: agent-abc123"
}