tool_call says that a call was requested, and by whom. A tool_result says what came back and, in particular, what reached the model. Approval is recorded in permission records, or on the result when no request was shown. Questions to the user are input_request records. Long-running processes that outlive a call are terminal entities. Hooks the harness runs are hook records.
tool_call
Capture state keys:
name, input, inputText.
ASR-250 A tool_call MUST contain callId and callIdSource, and MUST contain name unless capture.name is present.
ASR-251 A tool_call records that a call was requested; requestedBy says who requested it. It MUST NOT carry an outcome. Execution, denial, cancellation and results are recorded in tool_result and permission records.
ASR-252 name MUST be the exact tool name as requested, with no normalization, prefix stripping or splitting.
ASR-253 kind MUST come from the source, or from a mapping of exact tool names to kinds published in the agent’s registry entry. Producers MUST NOT assign kind from the title, the input or other heuristics.
ASR-254 When the source holds arguments as JSON text that meets ASR-032, input MAY hold the parsed value. When arguments are not JSON, cannot be parsed, or contain integers that do not meet ASR-032, inputText MUST hold the complete arguments without loss (ASR-035). A record MUST NOT contain both input and inputText.
Paths inside input are kept as the model wrote them. Root substitution never applies to them (see Coding).
kind is coarse. Tools that ask the user, delegate to another agent, set a plan or send a message all fall into other. Consumers find those facts by record type (input_request, subagent, plan, message), not by kind.
Who requested a call
Most calls come from the model. Some do not: a person runs a shell command directly (Claude Code’s! prefix, Codex’s user shell), the harness runs a tool for its own purposes, or a program the model wrote calls tools (Codex and OpenClaw code mode, where one model call to a code cell runs many tool calls).
call_Cx91rT) ran a command. Codex records the cell that ran it in this case; when a source does not, parentCallId is absent.
ASR-274 requestedBy MUST come from the source. A producer sets model when the source records the call as part of a model response, code when it records the call as made by a program the model wrote, user when it records a person’s direct command, and harness when it records the agent software making the call. Readers MUST NOT read an absent requestedBy as model.
ASR-275 parentCallId MUST come from a link the source records. Producers MUST NOT infer it from position or timing.
Provider identity
provider says where a tool comes from: a Model Context Protocol (MCP) server, a plugin, a connector (a hosted app integration), or the harness itself.
Many harnesses name MCP tools with a composite string (mcp__server__tool, mcp_<server>_<tool>, sanitized or truncated forms) that cannot be split reliably: server and tool names may themselves contain the separator. Some record the server and tool separately, on the call or on the result.
ASR-255 A
provider MUST contain kind and identity. exact MUST be used only when the source recorded the identity in separate fields; parsed only under a registry-documented rule.
ASR-256 Consumers MUST NOT split composite tool names themselves to recover an MCP server or tool. They use provider, or treat the server as unknown.
ASR-276 A tool_result MAY carry provider when the source records the identity on the result. A consumer that needs a call’s provider uses the call’s provider, or, when the call has none, the provider of its paired result (ASR-263).
tool_result
exitCode: this source does not record a numeric exit code, so none is written (ASR-267). The model saw a truncated copy of the output; the full output is in a blob.
Capture state keys:
content, displayContent, raw, exec.stdout, exec.stderr, exec.output.
ASR-257 A tool_result MUST contain linkage and status, and MUST contain callId unless linkage is none or ambiguous.
Status
ASR-258
status MUST reflect the source’s own outcome. A producer MUST NOT derive completed or failed from an exit code or from output text unless the source itself does, and MUST use denied only when the source records a refusal.
What reached the model
ASR-259content MUST hold what the model received as the tool’s result, as far as the source records it. When the source does not record what reached the model, content MUST be absent and capture.content MUST give the state (for example absent). Display text and raw output belong in displayContent and raw. Stored output is raw unless evidence establishes the form in which it reached the model, for the relevant source version and use. Evidence for one code path does not establish this for other renderers, retries or backends.
exec
content is absent and its capture state says so (ASR-259).
ASR-260 exec.exitCode MUST be written only when the source records a numeric exit code. Producers MUST NOT parse it from output text or from descriptive fields such as “return code interpretation”.
ASR-288 Producers MUST omit an execution field that is null in the source only when null means unavailable. This rule does not change nulls in arbitrary native JSON. signal remains a native string; a numeric signal MUST stay numeric in raw, not be stringified or mapped to a guessed signal name.
ASR-289 tool_result.exec.processId, when present, MUST be a string or an integer between −(253−1) and 253−1 inclusive.
ASR-290 exec.terminalId refers to a terminal entity. Producers MUST NOT emit it unless the stream or bundle contains a terminal record with that terminalId. Resolve it in the same stream first; if no such record is there, it MUST identify exactly one terminal entity in the bundle. Missing-session entries and gaps do not satisfy this requirement.
ASR-291 Producers MUST keep exec.processId verbatim, including its string or integer type. Readers MUST treat it as uninterpreted provenance and MUST NOT resolve it as a reference or use it as a fallback for exec.terminalId. A native process ID without a recorded terminal lifecycle goes in exec.processId; producers MUST NOT invent terminal records to hold it. Native numbers outside the safe range follow ASR-035 instead of being rounded or converted to strings.
ASR-261 startedAt, completedAt and durationMs MUST come from the source. A producer MAY compute durationMs from the same result’s startedAt and completedAt, and MUST NOT compute timing from other records’ timestamps.
Linkage and pairing
|nativeCallId | string | no | The native call ID, kept as written; never used as a fallback for pairing. |
ASR-262 Duplicate native call IDs MUST be preserved on each call. When no identifier recorded by the source shows which call a result answers, the producer MUST leave the result unpaired with
linkage: "ambiguous" and callId absent, keeping the literal native ID in nativeCallId. Positional or “latest call” pairing is fabrication and MUST NOT be used. Readers MUST distinguish ambiguous identity from an absent target (ASR-064). tool_result.nativeCallId is an optional string holding the native ID as recorded, without interpretation. Readers MUST NOT use it as an automatic fallback for pairing the result with a call.
ASR-263 A reader MUST pair a tool_result with a tool_call only when linkage is exact or derived and exactly one tool_call entity in the stream has that callId. Otherwise the result is unpaired.
ASR-264 When more than one result entity has the callId of one call, and none supersedes another, readers MUST treat the pairing as ambiguous and MUST NOT choose by position.
ASR-265 A tool_call with no paired result is dangling: its outcome is unknown. Readers MUST NOT present a dangling call as having succeeded. Producers MUST NOT synthesize a result for it.
ASR-266 A result with no paired call is an orphan. Producers MUST keep orphan results, and readers MUST show them as unpaired rather than dropping them.
A result’s later revision (for example a status that changed after completion, or output masked afterwards) is a new tool_result record that supersedes the earlier one (see Missing data and revisions). It is the same result entity.
ASR-267 Producers MUST NOT fabricate execution details: exit codes, durations, working directories and output appear only when the source records them.
permission
A permission records a request for approval and, when known, its status and decision. It follows ACP v2’s permission requests: a request has its own identity, a title, an optional subject (a tool call or a command) and options.
allow_session allows the request for the rest of the session (T3 Code’s acceptForSession).
decidedBy values: user (a person), policy (configuration or a rule), hook, auto_mode (an automatic mode with no reviewer), agent (another agent, such as a parent session answering for its child), classifier (a model that reviews actions, such as Codex’s reviewer, Claude Code’s auto-mode classifier or OpenClaw’s automatic review).
A review is separate from the resolution when the source records both: a model reviewer’s verdict, then a person’s decision. reviews[].by is an actor reference, verdict is the reviewer’s verdict as the source names it, and rationale is the reviewer’s stated reason.
Capture state keys: title, description, feedback, rationale.
ASR-268 A permission MUST contain requestId. subject, when present, MUST contain exactly one of callId or command.
ASR-269 A permission whose latest revision has no decision is unresolved: its outcome is unknown, like a dangling call. Readers MUST NOT present it as granted or refused.
ASR-270 decidedBy, decider, rule and reviews MUST be recorded only from the source. A producer MUST NOT infer that a user decided because no policy is recorded.
ASR-280 decidedBy: "classifier" or "agent" MUST be used only when that reviewing model or agent resolved the request. A review that came before another resolver’s decision goes in reviews and does not set decision or decidedBy.
ASR-281 When status is resolved, decision MUST be present. When status is pending or held, decision MUST be absent. Each entry of reviews MUST contain by, an actor reference.
Decisions without a request
Some sources record an approval decision on each tool result without recording any request: Claude Code stores a decision on every result, almost all of them made by configuration without a prompt. A fullpermission record per call would double the stream for no added fact. For these decisions, the result carries a compact permission member:
decision, decidedBy and rule values as the full record. It is an audit fact on a context-participating record, and it does not change the context view. This exception to the record model is listed in Extensibility.
ASR-277 A tool_result.permission MUST contain decision.
ASR-278 A tool_result MUST NOT carry permission when a permission record in the stream has subject.callId equal to the result’s callId.
ASR-279 A producer MUST use a permission record, not tool_result.permission, when the source records that a request was shown or records the request itself (a title, options, a pending state). Consumers that count approval decisions MUST count each compact decision once.
input_request
An input_request records a question the agent or a tool asked the user, and the answer when known: a set of structured questions with options (Claude Code AskUserQuestion, Codex request_user_input, T3 Code question cards, OpenClaw ask_user), a form a tool server asked for (MCP and ACP elicitation in form mode), or a URL the user was asked to open (URL mode). It is audit-only: the question and the answer reach the model only through the records the source keeps for them (a tool call and its result, or messages).
Question fields:
id (required, unique in the record), header (a short label), text (required, the question), options ([{label, value?, description?}]), multiSelect (more than one option may be chosen), allowOther (a typed answer is allowed), secret (the answer is a secret).
Answer fields: questionId (required); selected, the chosen options, each as the option’s value or, when the option has no value, its label; text, a typed answer.
For url mode, answered means the user agreed to open the URL. It does not mean that whatever happens at the URL finished.
Capture state keys: questions, answers, response.
ASR-282 An input_request MUST contain requestId and mode. When mode is questions it MUST contain questions. Each question MUST contain id and text, each option MUST contain label, and each answer MUST contain questionId.
ASR-283 A producer MUST NOT record the value given for a secret (a request or question marked secret, or one the source marks as asking for a secret) anywhere in the stream or bundle: not in answers or response, not in native payloads, blobs or _meta. It records only that the secret was asked and the request’s status.
ASR-284 Question IDs MUST be unique within an input_request. Each answers[].questionId MUST name a question in the same record, and answerRef, when present, MUST resolve to a message record.
ASR-285 status, answers, response and answeredBy MUST come from the source. A producer MUST NOT set answered because a later message exists, unless the source links that message to the request (then answerRef names it).
terminal
A terminal is a process entity for long-running and background processes and monitors: ACP v2’s agent-owned terminals, background shell commands, monitors that watch a command’s output, terminal transcripts kept beside a session. A terminal can outlive the call that created it and be read by later calls.
Capture state key:
output.
ASR-271 A terminal MUST contain terminalId. Each terminal record is a complete snapshot; a later state is a revision with the same terminalId that supersedes the previous record.
ASR-272 Terminal output MUST NOT be copied into a tool_result’s content unless the source records that it was delivered to the model. A result that read a recorded terminal sets exec.terminalId under ASR-290.
ASR-286 A background agent is a subagent, and its lifecycle is recorded in subagent revisions (see Lineage). A producer MUST NOT also record that agent’s lifecycle as a terminal. A process that an agent runs is a different entity and is a terminal when the source records it.
hook
A hook records the execution of a hook: a command, prompt, agent, HTTP call or MCP tool that the harness runs in response to an event, as configured by the user, the project or the harness itself. Setup scripts that the harness runs for a workspace are hooks too.
Capture state keys:
stdout, stderr, output.
ASR-273 A hook MUST contain event. Content a hook injected into the conversation is a message with author: "hook", not part of the hook record.
ASR-287 Hook execution details (exitCode, timedOut, stdout, stderr, output, durationMs) MUST appear only when the source records them. A command the harness runs for its own setup, not at the model’s request, is a hook, not a tool_call.