Message Types in Claude Code Transcripts¶
See application_model.md for the system overview.
This document describes all message types found in Claude Code JSONL transcript files and their corresponding output representations. The goal is to define an intermediate representation that captures the logical message structure independent of HTML rendering.
Overview¶
Claude Code transcripts contain messages in JSONL format. Each line represents an input message that gets transformed through:
- Input Layer (JSONL): Raw Claude Code transcript data
- Intermediate Layer (TemplateMessage): Format-neutral logical representation
- Output Layer (HTML): Rendered visual output
This document maps input types to their intermediate and output representations.
Data Flow: From Transcript Entries to Rendered Messages¶
JSONL Parsing (parser.py)
│
├── UserTranscriptEntry
│ ├── TextContent → User message variants:
│ │ ├── UserSlashCommandMessage (isMeta) or SlashCommandMessage (<command-name> tags)
│ │ ├── CommandOutputMessage (<local-command-stdout> tags)
│ │ ├── BashInputMessage (<bash-input> tags)
│ │ ├── CompactedSummaryMessage (compacted conversation)
│ │ ├── UserSteeringMessage (queue-operation "remove")
│ │ └── Plain user text
│ ├── ToolResultContent → ToolResultMessage with output:
│ │ ├── ReadOutput (cat-n formatted file content)
│ │ ├── EditOutput (cat-n formatted edit result)
│ │ └── ToolResultContent (generic fallback)
│ └── ImageContent → Image messages
│
├── AssistantTranscriptEntry
│ ├── TextContent → AssistantTextMessage
│ ├── ThinkingContent → ThinkingMessage
│ └── ToolUseContent → ToolUseMessage with parsed inputs:
│ ├── ReadInput, WriteInput, EditInput, MultiEditInput
│ ├── BashInput, GlobInput, GrepInput
│ ├── TaskInput, TodoWriteInput, AskUserQuestionInput
│ └── ExitPlanModeInput
│
├── SystemTranscriptEntry
│ ├── SystemMessage (level: info/warning/error)
│ ├── HookSummaryMessage (subtype: stop_hook_summary)
│ └── AwaySummaryMessage (subtype: away_summary)
│
├── SummaryTranscriptEntry → Session metadata (not rendered)
│
└── QueueOperationTranscriptEntry
└── "remove" operation → UserSteeringMessage (rendered as user)
Intermediate Representation: TemplateMessage¶
The intermediate representation is TemplateMessage, a Python class (in renderer.py) that captures all fields needed for rendering.
Key Fields¶
class TemplateMessage:
# Identity
type: str # Base type: "user", "assistant", "tool_use", etc.
message_id: str # Unique ID within session (e.g., "msg-0", "tool-1")
uuid: str # Original JSONL uuid
# Content (format-neutral)
content: Optional[MessageContent] # Structured content model
# Note: HTML is generated during template rendering, not stored in the message
# Display
message_title: str # Display title (e.g., "User", "Assistant")
is_sidechain: bool # Sub-agent message flag (via content.meta)
# Note: has_markdown is accessed via content.has_markdown
# Note: CSS classes are derived from content type via CSS_CLASS_REGISTRY
# Metadata
raw_timestamp: str # ISO 8601 timestamp
session_id: str # Session UUID
# Hierarchy
children: List[TemplateMessage] # Child messages (tree mode)
ancestry: List[str] # Parent message IDs for fold/unfold
# Pairing
is_paired: bool # True if part of a pair
pair_role: Optional[str] # "pair_first", "pair_last", "pair_middle"
# Tool-specific
tool_use_id: Optional[str] # ID linking tool_use to tool_result
Content Type → CSS Classes¶
CSS classes are derived from the content type using CSS_CLASS_REGISTRY (in html/utils.py). This ensures the content type is the single source of truth for display styling.
| css_class | Content Type | Dynamic Modifier |
|---|---|---|
"user" |
UserTextMessage |
— |
"user compacted" |
CompactedSummaryMessage |
— |
"user slash-command" |
SlashCommandMessage, UserSlashCommandMessage |
— |
"user command-output" |
CommandOutputMessage |
— |
"user steering" |
UserSteeringMessage |
— |
"assistant" |
AssistantTextMessage |
— |
"tool_use" |
ToolUseMessage |
— |
"tool_result" |
ToolResultMessage |
— |
"tool_result error" |
ToolResultMessage |
is_error=True |
"thinking" |
ThinkingMessage |
— |
"bash-input" |
BashInputMessage |
— |
"bash-output" |
BashOutputMessage |
— |
"system system-info" |
SystemMessage |
level="info" |
"system system-warning" |
SystemMessage |
level="warning" |
"system system-error" |
SystemMessage |
level="error" |
"system system-hook" |
HookSummaryMessage |
— |
"system system-away-summary" |
AwaySummaryMessage |
— |
The sidechain modifier is added when msg.is_sidechain=True (a cross-cutting concern that applies to any message type).
Note: See css-classes.md for complete CSS support status.
Part 1: User Messages (UserTranscriptEntry)¶
User transcript entries (type: "user") contain human input, tool results, and images.
1.1 Content Types in User Messages¶
User messages contain ContentItem instances that are either:
- TextContent: User-typed text (with various semantic variants)
- ToolResultContent: Results from tool execution
- ImageContent: User-attached images
1.2 User Text Variants¶
Based on flags and tag patterns in TextContent, user text messages are classified into specialized content types defined in models.py.
Regular User Prompt¶
- Condition: No special flags or tags
- Content Model: Plain
TextContent - CSS Class:
user - Files: user.json | user.jsonl
{
"type": "user",
"message": {
"role": "user",
"content": [{ "type": "text", "text": "Help me fix this bug..." }]
},
"isSidechain": false
}
Slash Command (isMeta)¶
- Condition:
isMeta: trueflag - Content Model:
UserSlashCommandMessage(models.py) - CSS Class:
user slash-command - Files: user_slash_command.json
{
"type": "user",
"message": { "content": "Caveat: The messages below were generated..." },
"isMeta": true
}
@dataclass
class UserSlashCommandMessage(MessageContent):
text: str # LLM-generated markdown instruction text
Note: These are LLM-generated instruction prompts from slash commands. The text is markdown formatted and rendered as collapsible markdown.
Slash Command (Tags)¶
- Condition: Contains
<command-name>tags - Content Model:
SlashCommandMessagewith parsed name/args/contents - CSS Class:
user slash-command - Files: user_command.json
@dataclass
class SlashCommandMessage(MessageContent):
command_name: str # e.g., "/model", "/context"
command_args: str # Arguments after command
command_contents: str # Content inside command
Note: Both built-in commands (e.g.,
/init,/model,/context) and user-defined commands (e.g.,/my-commandfrom~/.claude/commands/my-command.md) use the same<command-name>tag format. There is no field in the JSONL to differentiate between them.
Command Output¶
- Condition: Contains
<local-command-stdout>tags - Content Model:
CommandOutputMessage - CSS Class:
user command-output - Files: command_output.json
@dataclass
class CommandOutputMessage(MessageContent):
stdout: str # Command output text
is_markdown: bool # True if content appears to be markdown
Bash Input¶
- Condition: Contains
<bash-input>tags - Content Model:
BashInputMessage - CSS Class:
bash-input(filtered by User) - Files: bash_input.json
@dataclass
class BashInputMessage(MessageContent):
command: str # The bash command that was executed
Bash Output¶
The corresponding output uses <bash-stdout> and optionally <bash-stderr> tags:
- Condition: Contains
<bash-stdout>tags - Content Model:
BashOutputMessage - CSS Class:
bash-output(filtered by User) - Files: bash_output.json
Compacted Conversation¶
- Condition: Contains "(compacted conversation)" marker
- Content Model:
CompactedSummaryMessage - CSS Class:
user compacted
@dataclass
class CompactedSummaryMessage(MessageContent):
summary_text: str # The compacted conversation summary
User Steering (Queue Remove)¶
- Condition:
QueueOperationTranscriptEntrywithoperation: "remove" - Content Model:
UserSteeringMessage(extendsUserTextMessage) - CSS Class:
user steering - Title: "User (steering)"
@dataclass
class UserSteeringMessage(UserTextMessage):
"""Message for user steering prompts (queue-operation 'remove')."""
pass # Inherits items from UserTextMessage
Steering messages represent user interrupts that cancel queued operations.
User Memory¶
- Condition: Contains
<user-memory-input>tags - Content Model:
UserMemoryMessage - CSS Class:
user
@dataclass
class UserMemoryMessage(MessageContent):
memory_text: str # The memory content from the tag
Sidechain User (Sub-agent)¶
- Condition:
isSidechain: true - CSS Class:
user sidechain - Note: Typically skipped during rendering (duplicates Task prompt)
- Files: user_sidechain.json
Async Task Notification (<task-notification>)¶
When an async-spawned Task (with run_in_background=True) completes,
Claude Code injects a synthetic User entry whose message.content is
a raw <task-notification>…</task-notification> block.
task_notification_factory.create_task_notification_message parses
the embedded fields into a structured content model.
- Condition:
message.contentis a string containing<task-notification>…</task-notification> - Content Model:
TaskNotificationMessage(aMessageContentsubclass — not aUserTextMessagevariant) - CSS Classes:
user task_notification(theuserclass is what keeps the runtime "User" filter toggle showing the card)
@dataclass
class TaskNotificationMessage(MessageContent):
task_id: str
status: str # "completed", "failed", …
summary: str # Agent "<description>" completed
result_text: str # the agent's final answer body
usage: Optional[TaskNotificationUsage]
transcript_path: Optional[str] # "Full transcript available at: …"
raw_text: Optional[str]
# Phase 3 dedup markers
result_is_duplicate: bool = False
spawning_task_message_index: Optional[int] = None
The result_text is the canonical source for the spawn-fold —
_link_async_notifications copies it onto
TaskOutput.async_final_answer of the spawning Task tool_result so
the answer renders in place. See
agents.md § 2 (Async task agents)
for the end-to-end flow and detail-level matrix.
IDE Notifications¶
User messages may contain IDE notification tags that are parsed into structured content:
- Condition: Contains
<ide_opened_file>,<ide_selection>, or<ide_diagnostics>tags - Content Model:
IdeNotificationContentcontaining lists of: IdeOpenedFile: File open notificationsIdeSelection: Code selection notificationsIdeDiagnostic: Diagnostic messages (parsed JSON or raw text fallback)- CSS Class: Notifications rendered as inline elements within user message
@dataclass
class IdeOpenedFile:
content: str # Raw content from the tag
@dataclass
class IdeSelection:
content: str # Raw selection content
@dataclass
class IdeDiagnostic:
diagnostics: Optional[List[Dict[str, Any]]] # Parsed JSON
raw_content: Optional[str] # Fallback if parsing failed
@dataclass
class IdeNotificationContent: # NOT a MessageContent subclass
"""Embedded within UserTextMessage.items alongside TextContent/ImageContent."""
opened_files: List[IdeOpenedFile]
selections: List[IdeSelection]
diagnostics: List[IdeDiagnostic]
remaining_text: str # Text after notifications extracted
1.3 Tool Results (ToolResultContent)¶
Tool results appear as ToolResultContent items in user messages, linked to their corresponding ToolUseContent via tool_use_id.
Tool Result Output Models¶
| Tool | Output Model | Key Fields | Files |
|---|---|---|---|
| Read | ReadOutput |
file_path, content, start_line, num_lines, is_truncated | tool_result |
| Edit | EditOutput |
file_path, success, diffs, message, start_line | tool_result |
| Write | WriteOutput |
file_path, success, message | tool_result |
| Bash | BashOutput |
content, has_ansi | tool_result |
| Task | TaskOutput (see note) |
result, metadata, async_final_answer | tool_result |
| TaskOutput | TaskOutputResult (see note) |
retrieval_status, task_id, task_type, status, output_truncated, output_file | (async-agent polling tool — issue #90) |
| TaskStop | TaskStopOutput |
stopped, message | (kills a background task by id — PR #158 follow-up) |
| AskUserQuestion | AskUserQuestionOutput |
answers, raw_message | tool_result |
| ExitPlanMode | ExitPlanModeOutput |
message, approved | tool_result |
| Glob | GlobOutput (TODO) |
pattern, files, truncated | tool_result |
| Grep | GrepOutput (TODO) |
pattern, matches, output_mode, truncated | tool_result |
| (error) | — | is_error: true | Bash error |
(TODO): Glob and Grep output models defined in models.py but not yet used.
Note on TaskOutput vs TaskOutputResult: two unrelated dataclasses with overlapping names.
TaskOutput is the parsed output of the Task tool_result (carries the launch stub or final
answer text, agent metadata, and the Phase 3 async_final_answer field).
TaskOutputResult is the parsed output of the TaskOutput polling tool's tool_result (the
<retrieval_status>/<task_id>/<status>/<output>[Truncated…] body that the assistant explicitly
polls between an async-Task launch and its completion notification). The fold writes into
TaskOutput.async_final_answer — i.e. the Task tool_result, not the polling tool's result. See
agents.md § 2.2.
Generic Tool Result¶
- CSS Class:
tool_result - Content: Raw string or structured content
{
"type": "user",
"message": {
"content": [{
"type": "tool_result",
"tool_use_id": "toolu_xxx",
"is_error": false,
"content": "..."
}]
}
}
Tool Result Error¶
- Condition:
is_error: true - CSS Class:
tool_result error - Files: Bash-tool_result_error.json
Read Tool Result → ReadOutput¶
Read tool results in cat-n format are parsed into structured ReadOutput:
- Files: Read-tool_result.json
@dataclass
class ReadOutput(MessageContent):
file_path: str
content: str # File content (may be truncated)
start_line: int # 1-based starting line number
num_lines: int # Number of lines in content
total_lines: int # Total lines in file
is_truncated: bool
system_reminder: Optional[str] # Embedded system reminder
Edit Tool Result → EditOutput¶
Edit tool results with cat-n snippets are parsed into structured EditOutput:
- Files: Edit-tool_result.json
@dataclass
class EditOutput(MessageContent):
file_path: str
success: bool
diffs: List[EditDiff] # Changes made
message: str # Result message or code snippet
start_line: int # Starting line for display
Tool Result Rendering Wrapper¶
Tool results are wrapped in ToolResultMessage for rendering, which provides additional context and typed output:
@dataclass
class ToolResultMessage(MessageContent):
tool_use_id: str
output: ToolOutput # Specialized output or ToolResultContent fallback
is_error: bool = False
tool_name: Optional[str] = None # Name of the tool
file_path: Optional[str] = None # File path for Read/Edit/Write
# ToolOutput is a union type for tool results
ToolOutput = Union[
ReadOutput,
WriteOutput,
EditOutput,
BashOutput,
TaskOutput,
AskUserQuestionOutput,
ExitPlanModeOutput,
ToolResultContent, # Generic fallback for unparsed results
]
1.4 Images (ImageContent)¶
- CSS Class:
image - Files: image.json
{
"type": "user",
"message": {
"content": [{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": "iVBORw0KGgo..."
}
}]
}
}
Image data is structured using ImageSource:
class ImageSource(BaseModel):
type: Literal["base64"]
media_type: str # e.g., "image/png"
data: str # Base64-encoded image data
class ImageContent(BaseModel, MessageContent):
type: Literal["image"]
source: ImageSource
Part 2: Assistant Messages (AssistantTranscriptEntry)¶
Assistant transcript entries (type: "assistant") contain Claude's responses.
2.1 Content Types in Assistant Messages¶
Assistant messages contain ContentItem instances that are:
- TextContent: Claude's text response
- ThinkingContent: Extended thinking blocks
- ToolUseContent: Tool invocations
2.2 Assistant Text → AssistantTextMessage¶
- Content Model:
AssistantTextMessage(models.py) - CSS Class:
assistant(orassistant sidechain) - Files: assistant.json
@dataclass
class AssistantTextMessage(MessageContent):
items: list[TextContent | ImageContent] # Interleaved text and images
token_usage: Optional[str] # Formatted token usage string
Sidechain Assistant¶
- Condition:
isSidechain: true - CSS Class:
assistant sidechain - Title: "Sub-assistant"
- Files: assistant_sidechain.json
2.3 Thinking Content → ThinkingMessage¶
- Content Model:
ThinkingMessage(models.py) - CSS Class:
thinking - Files: thinking.json
@dataclass
class ThinkingMessage(MessageContent):
thinking: str # The thinking text
signature: Optional[str] # Thinking block signature
token_usage: Optional[str] # Formatted token usage string
{
"type": "assistant",
"message": {
"content": [{ "type": "thinking", "thinking": "Let me analyze..." }]
}
}
2.4 Tool Use → ToolUseMessage with Typed Inputs¶
Tool invocations are parsed from ToolUseContent (JSONL) and wrapped in ToolUseMessage for rendering:
@dataclass
class ToolUseMessage(MessageContent):
input: ToolInput # Specialized (BashInput, etc.) or ToolUseContent fallback
tool_use_id: str # From ToolUseContent.id
tool_name: str # From ToolUseContent.name
# ToolInput is a union of typed input models
ToolInput = Union[
BashInput, ReadInput, WriteInput, EditInput, MultiEditInput,
GlobInput, GrepInput, TaskInput, TodoWriteInput,
AskUserQuestionInput, ExitPlanModeInput,
ToolUseContent, # Generic fallback when no specialized parser
]
The original ToolUseContent (Pydantic model) provides:
- name: The tool name (e.g., "Read", "Bash", "Task")
- id: Unique ID for pairing with results
- input: Raw input dictionary
- parsed_input property: Returns typed input model via parse_tool_input()
Tool Input Models (models.py)¶
| Tool | Input Model | Key Fields |
|---|---|---|
| Read | ReadInput |
file_path, offset, limit |
| Write | WriteInput |
file_path, content |
| Edit | EditInput |
file_path, old_string, new_string, replace_all |
| MultiEdit | MultiEditInput |
file_path, edits[] |
| Bash | BashInput |
command, description, timeout, run_in_background |
| Glob | GlobInput |
pattern, path |
| Grep | GrepInput |
pattern, path, glob, type, output_mode, multiline, head_limit, offset |
| Task | TaskInput |
prompt, subagent_type, description, model, run_in_background, resume |
| TodoWrite | TodoWriteInput |
todos[] |
| AskUserQuestion | AskUserQuestionInput |
questions[], question |
| ExitPlanMode | ExitPlanModeInput |
plan, launchSwarm, teammateCount |
Tool Input Helper Models¶
Some tool inputs contain nested structures with their own models:
# MultiEdit tool uses EditItem for individual edits
class EditItem(BaseModel):
old_string: str
new_string: str
# TodoWrite tool uses TodoWriteItem for individual todos
class TodoWriteItem(BaseModel):
content: str = ""
status: str = "pending"
activeForm: str = ""
id: Optional[str] = None
priority: Optional[str] = None
# AskUserQuestion tool uses nested models for questions/options
class AskUserQuestionOption(BaseModel):
label: str = ""
description: Optional[str] = None
class AskUserQuestionItem(BaseModel):
question: str = ""
header: Optional[str] = None
options: List[AskUserQuestionOption] = []
multiSelect: bool = False
Tool Use Message Structure¶
- CSS Class:
tool_use(ortool_use sidechain) - Files: See messages/tools/ (e.g.,
Read-tool_use.json)
{
"type": "assistant",
"message": {
"content": [{
"type": "tool_use",
"id": "toolu_xxx",
"name": "Read",
"input": { "file_path": "/path/to/file" }
}]
}
}
Part 3: System Messages (SystemTranscriptEntry)¶
System transcript entries (type: "system") convey notifications and hook summaries.
3.1 Content Types for System Messages¶
System messages are parsed into structured content models in models.py:
- SystemMessage: For info/warning/error messages
- HookSummaryMessage: For hook execution summaries
- AwaySummaryMessage: For away_summary recap entries
3.2 System Info/Warning/Error → SystemMessage¶
- Content Model:
SystemMessage(models.py) - CSS Class:
system system-info,system system-warning,system system-error - Files: system_info.json
@dataclass
class SystemMessage(MessageContent):
level: str # "info", "warning", "error"
text: str # Raw text content (may contain ANSI codes)
3.3 Hook Summary → HookSummaryMessage¶
- Content Model:
HookSummaryMessage(models.py) - Condition:
subtype: "stop_hook_summary" - CSS Class:
system system-hook
@dataclass
class HookInfo:
command: str
@dataclass
class HookSummaryMessage(MessageContent):
has_output: bool
hook_errors: List[str]
hook_infos: List[HookInfo]
3.4 Away Summary (Recap) → AwaySummaryMessage¶
- Content Model:
AwaySummaryMessage(models.py) - Condition:
subtype: "away_summary" - CSS Class:
system system-away-summary - Header:
📝 Recap(icon fromget_message_emoji, title fromtitle_AwaySummaryMessage) - Detail levels: kept at FULL/HIGH (narrative content), dropped at LOW/MINIMAL/USER_ONLY (alongside bash/thinking)
Claude Code emits these system entries when a session resumes after a break — narrative prose summarising recent activity. The factory strips a trailing " (disable recaps in /config)" UI hint when present (suffix-match, not global) so all renderers inherit the polished form.
{
"type": "system",
"subtype": "away_summary",
"content": "We're adding a project-level layout to validate projectId in the prepare route tree …"
}
Part 4: Metadata Entries¶
These entry types primarily contain metadata, with some rendered conditionally.
4.1 Summary (SummaryTranscriptEntry)¶
- Purpose: Session summary for navigation
- Files: summary.json
{
"type": "summary",
"summary": "Claude Code warmup for deep-manifest project",
"leafUuid": "b83b0f5f-8bfc-4b98-8368-16162a6e9320"
}
The leafUuid links the summary to the last message of the session.
4.2 Queue Operation (QueueOperationTranscriptEntry)¶
- Purpose: User interrupts and steering during assistant responses
- Rendered: Only
removeoperations (asUserSteeringContent) - CSS Class:
user steering - Files: queue_operation.json
4.3 File History Snapshot¶
- Purpose: File state snapshots for undo/redo
- Not Rendered
- Files: file_history_snapshot.json
Part 5: Renderer Content Models¶
These models are created during rendering to represent synthesized content not directly from JSONL entries.
5.1 SessionHeaderMessage¶
Session headers are rendered at the start of each session:
@dataclass
class SessionHeaderMessage(MessageContent):
title: str # e.g., "Session 2025-12-13 10:30"
session_id: str # Session UUID
summary: Optional[str] = None # Session summary if available
Part 6: Infrastructure Models¶
6.1 CSS Class Registry¶
Display styling is derived from content types using CSS_CLASS_REGISTRY in html/utils.py. This registry maps MessageContent subclasses to their CSS classes:
CSS_CLASS_REGISTRY: dict[type[MessageContent], list[str]] = {
# System message types
SystemMessage: ["system"], # level added dynamically
HookSummaryMessage: ["system", "system-hook"],
AwaySummaryMessage: ["system", "system-away-summary"],
# User message types
UserTextMessage: ["user"],
UserSteeringMessage: ["user", "steering"],
SlashCommandMessage: ["user", "slash-command"],
UserSlashCommandMessage: ["user", "slash-command"],
UserMemoryMessage: ["user"],
CompactedSummaryMessage: ["user", "compacted"],
CommandOutputMessage: ["user", "command-output"],
# Assistant message types
AssistantTextMessage: ["assistant"],
# Tool message types
ToolUseMessage: ["tool_use"],
ToolResultMessage: ["tool_result"], # error added dynamically
# Other message types
ThinkingMessage: ["thinking"],
SessionHeaderMessage: ["session_header"],
BashInputMessage: ["bash-input"],
BashOutputMessage: ["bash-output"],
UnknownMessage: ["unknown"],
}
The _get_css_classes_from_content() function walks the content type's MRO to find the matching registry entry, then adds dynamic modifiers (e.g., system-{level} for SystemMessage).
The only cross-cutting modifier is is_sidechain, which is stored directly on TemplateMessage and appended to CSS classes when true.
6.2 UsageInfo¶
Token usage tracking for assistant messages:
class UsageInfo(BaseModel):
input_tokens: Optional[int] = None
cache_creation_input_tokens: Optional[int] = None
cache_read_input_tokens: Optional[int] = None
output_tokens: Optional[int] = None
service_tier: Optional[str] = None
server_tool_use: Optional[Dict[str, Any]] = None
6.3 BaseTranscriptEntry¶
Base class for all transcript entries, providing common fields:
class BaseTranscriptEntry(BaseModel):
parentUuid: Optional[str] # UUID of parent message
isSidechain: bool # Whether this is a sub-agent message
userType: str # User type identifier
cwd: str # Working directory
sessionId: str # Session UUID
version: str # Transcript format version
uuid: str # Unique message ID
timestamp: str # ISO 8601 timestamp
isMeta: Optional[bool] = None # Slash command marker
agentId: Optional[str] = None # Sub-agent ID
gitBranch: Optional[str] = None # Git branch name when available
Part 7: Message Relationships¶
7.1 Hierarchy (Parent/Child)¶
The message hierarchy is determined by sequence and message type, not by parentUuid:
- Session headers are topmost (Level 0)
- User messages follow at Level 1
- Assistant responses and system messages nest under user messages (Level 2)
- Tool use/result pairs nest under assistant responses (Level 3)
- Sidechain messages nest under their Task result (Level 4+)
Session header (Level 0)
└── User message (Level 1)
├── System message (Level 2)
└── Assistant response (Level 2)
└── Tool use/result pair (Level 3)
└── Sidechain messages (Level 4+)
Note: parentUuid links messages temporally (which message preceded this one) but is not used for rendering hierarchy.
7.2 Tool Pairing¶
tool_use and tool_result messages are paired by tool_use_id:
| First | Last | Link |
|---|---|---|
tool_use |
tool_result |
tool_use.id = tool_result.tool_use_id |
Other Pairings¶
| First | Last | Link |
|---|---|---|
bash-input |
bash-output |
Sequential |
thinking |
assistant |
Sequential |
slash-command |
command-output |
Sequential |
7.3 Sidechain Linking¶
Sub-agent messages (from Task tool):
- Have isSidechain: true
- Have agentId linking to the Task
- Appear nested under their Task result
Part 8: Tool Reference¶
Available Tools by Category¶
File Operations¶
| Tool | Use Sample | Result Sample | Input Model | Output Model |
|---|---|---|---|---|
| Read | tool_use | tool_result | ReadInput |
ReadOutput |
| Write | tool_use | tool_result | WriteInput |
WriteOutput (TODO) |
| Edit | tool_use | tool_result | EditInput |
EditOutput |
| MultiEdit | tool_use | tool_result | MultiEditInput |
— |
| Glob | tool_use | tool_result | GlobInput |
GlobOutput (TODO) |
| Grep | tool_use | tool_result | GrepInput |
GrepOutput (TODO) |
Shell Operations¶
| Tool | Use Sample | Result Sample | Input Model | Output Model |
|---|---|---|---|---|
| Bash | tool_use | tool_result | BashInput |
BashOutput (TODO) |
| BashOutput | tool_use | tool_result | — | — |
| KillShell | tool_use | tool_result | — | — |
Agent Operations¶
| Tool | Use Sample | Result Sample | Input Model | Output Model |
|---|---|---|---|---|
| Task | tool_use | tool_result | TaskInput |
TaskOutput |
| TaskOutput (async-agent polling) | — | — | TaskOutputInput |
TaskOutputResult |
| TaskStop (kill background task) | — | — | TaskStopInput |
TaskStopOutput |
| TodoWrite | tool_use | tool_result | TodoWriteInput |
— |
| AskUserQuestion | tool_use | tool_result | AskUserQuestionInput |
— |
| ExitPlanMode | tool_use | tool_result | ExitPlanModeInput |
— |
Web Operations¶
| Tool | Use Sample | Result Sample | Input Model | Output Model |
|---|---|---|---|---|
| WebFetch | tool_use | tool_result | — | — |
| WebSearch | tool_use | tool_result | — | — |
References¶
- css-classes.md - Complete CSS class reference with support status
- models.py - Pydantic models for transcript data
- renderer.py - Main rendering module
- html/ - HTML-specific formatters (formatting only, content models in models.py)
- system_formatters.py - SystemMessage, HookSummaryMessage, AwaySummaryMessage formatting
- user_formatters.py - User message formatting
- assistant_formatters.py - AssistantTextMessage, ThinkingMessage, ImageContent formatting
- tool_formatters.py - Tool use/result formatting
- parser.py - JSONL parsing and text extraction
- factories/ - Content creation from parsed data
- user_factory.py -
create_user_message(),create_*_message()functions - assistant_factory.py -
create_assistant_message(),create_thinking_message() - tool_factory.py -
create_tool_use_message(),create_tool_result_message() - system_factory.py -
create_system_message() - meta_factory.py -
create_meta() - rendering-architecture.md - Rendering pipeline and Renderer class hierarchy
- ../work/rendering-next.md - Future rendering improvements