Tool Call Role Design: Claude Code vs Codex
Background
The question under discussion: why do Claude Code / Anthropic tool results appear to live in role: user, while Codex / the OpenAI Responses API treats tool calls and tool results more like independent events.
To be precise:
- Claude does not define the tool call itself as
user. Claude's tool call is an assistant-sidetool_use. - What goes into
role: useris the post-executiontool_result. - That
useris not a human user; it is closer to the client / environment side handing external observations back to the model.
Core judgment
Claude's design reads as a "conversational input stream":
assistant: what the model itself says, and its owntool_useuser: new input from the outside world to the model — human messages, environment context, tool resultstool_resultis matched to the earlier tool call via content block type andtool_use_id
The upside is a simple schema, a direct conversation loop, and unified content blocks. The cost is transcript readability: much of what sits under role: user is not human speech but tool observations — shell output, file reads, MCP responses.
Codex / OpenAI Responses reads as an "agent event stream":
- user messages are still
role: user - the model requesting a tool is a
function_call - the tool's return is a
function_call_output - the two are matched by
call_id
The upside is clearer auditing, replay, state machines and permission analysis. Tool output doesn't blend into the user role; the role system mainly expresses instruction authority, and tool output is observation. The cost is a more complex protocol — adapting other models or frameworks means handling typed items.
In one sentence:
Claude puts tool results into the conversational input stream; Codex puts them into the agent event stream.
What each fits
Claude's approach fits:
- quickly implementing an
assistant tool_use -> client execute -> user tool_result -> assistant continueloop - a two-role message schema without inventing extra roles
- putting text, images, tool calls and tool results all into one unified content block
Codex's approach fits:
- complex local agent runtimes
- event auditing for multi-tool, multi-round execution, approvals, sandboxes, sub-agents
- treating tool output as a traceable observation instead of mixing it into human/user messages
- later work on Trace Logs, replay, compression, and permission-boundary analysis
Article angles worth developing
This could become an article about the representation layer of agent runtimes; tentative angle:
- Title direction:
Conversation stream or event stream: where do agent tool results belong - Central question: is a tool result user input, an environment observation, or an agent runtime event?
- Core tension: a simple API schema versus a long-term auditable runtime
- Extends the existing
Trace Logthread: a good Trace Log doesn't just record final output — it must distinguish human instructions, system constraints, model decisions, tool observations and environment side effects
Open questions
- If tool output contains a prompt injection, is it more easily mistaken for high-authority instruction under
role: user? - Should a home-grown agent harness define an explicit
observation/tool_resultlayer instead of reusinguser? - How should a Trace Log stay human-readable while remaining structured enough for the model to keep consuming?