Building Production-Ready AI Agents: OpenAI Codex CLI Architecture and Agent Loop Design

openai · Tech · 2026 · source Agentic: yes · promotional bias: med · source-backed · extracted with prompt 0.5.5 (schema v2)

Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.

Problem

Domain: Local software-agent harness and coding-agent loop design

OpenAI needed Codex CLI to orchestrate reliable local code changes by coordinating user input, model inference, tool execution, prompt construction, streaming events, security boundaries, prompt caching, stateless API calls, and context compaction across long-running coding conversations.

Constraints:

Architecture

Codex uses a harness centered on an agent loop. The CLI collects user input, layered instructions, tool definitions, environment context, and conversation history into a Responses API request. The model either emits an assistant message or requests a tool call. Codex executes tool calls, appends the resulting output items to the next request, and repeats until an assistant message ends the turn. The Responses API streams events through SSE; Codex transforms streaming text into UI updates and output items into future input state. To make this production-ready, Codex keeps requests stateless for ZDR, preserves prompt prefixes for caching, appends configuration changes instead of rewriting earlier context, and automatically compacts the conversation through the /responses/compact endpoint when token limits are approached.

Diagram confidence: explicit (topology described by the source).

flowchart LR
  user[User] --> codex-cli[Codex CLI]
  codex-cli --> codex-harness[Codex harness]
  codex-cli --> local-environment[Local environment]
  codex-harness --> prompt-builder[Prompt builder]
  codex-harness --> responses-api-client[Responses API client]
  codex-harness --> tool-executor[Tool executor]
  codex-harness --> conversation-state-manager[Conversation state manager]
  prompt-builder --> instruction-sources[Instruction sources]
  prompt-builder --> tool-definitions[Tool definitions]
  prompt-builder --> conversation-state-manager
  tool-definitions --> codex-shell-tool[Codex shell tool]
  tool-definitions --> mcp-servers[MCP servers]
  responses-api-client --> responses-api-server[Responses API server]
  responses-api-server --> model[Model]
  responses-api-server --> sse-event-stream[SSE event stream]
  sse-event-stream --> internal-event-objects[Internal event objects]
  internal-event-objects --> conversation-state-manager
  internal-event-objects --> codex-cli
  tool-executor --> codex-shell-tool
  tool-executor --> mcp-servers
  tool-executor --> local-environment
  codex-shell-tool --> sandbox-and-approval-context[Sandbox and approval context]
  sandbox-and-approval-context --> conversation-state-manager
  conversation-state-manager --> prompt-cache[Prompt cache]
  prompt-cache --> responses-api-server
  conversation-state-manager --> compaction-endpoint[Compaction endpoint]
  compaction-endpoint --> responses-api-server
Drag to pan · scroll or use +/− to zoom · reconstructed from the source's described component topology

Components

Component Role Interacts with
User Developer interacting with Codex CLI through conversation turns. Codex CLI
Codex CLI Cross-platform local software agent surface that runs the harness and presents assistant messages to the user. User, Codex harness, Local environment
Codex harness Core agent-loop implementation shared across Codex experiences. Codex CLI, Prompt builder, Responses API client, Tool executor, Conversation state manager
Prompt builder Constructs instructions, tools, and input items from configuration, AGENTS files, skills, environment context, and user messages. Codex harness, Tool definitions, Instruction sources, Conversation state manager
Instruction sources Developer instructions, user instructions, AGENTS files, project fallback docs, and skills included in the prompt with role precedence. Prompt builder
Tool definitions Responses API tool schema entries from Codex-provided tools, API-provided tools, and user MCP servers. Prompt builder, Tool executor, MCP servers, Codex shell tool
Responses API client HTTP/SSE client that sends model requests to ChatGPT, OpenAI API, local gpt-oss, LM Studio, Ollama, or Azure-compatible endpoints. Codex harness, Responses API server, SSE event stream
Responses API server Server that derives the model prompt, samples the model, and streams response events. Responses API client, Model, Compaction endpoint, SSE event stream
Model LLM that emits assistant messages, reasoning items, or tool-call requests. Responses API server
SSE event stream Streaming channel of response events consumed by Codex and republished as internal event objects. Responses API client, Internal event objects
Internal event objects Codex-side representation of streaming UI updates and stateful output items that feed subsequent requests. SSE event stream, Conversation state manager, Codex CLI
Tool executor Executes requested tool calls, including local shell actions and user-provided MCP tools, then returns outputs into the next model query. Codex harness, Tool definitions, Codex shell tool, MCP servers, Local environment
Codex shell tool Codex-provided shell tool governed by the developer-message sandbox instructions. Tool executor, Sandbox and approval context
MCP servers User-provided tool servers whose tools are not sandboxed by Codex and must enforce their own guardrails. Tool definitions, Tool executor
Sandbox and approval context Permissions instructions and configuration state appended to preserve prompt-cache prefixes when changed mid-conversation. Codex shell tool, Conversation state manager
Conversation state manager Maintains conversation input items, appends assistant/user/tool output state, preserves prefixes, and triggers compaction. Codex harness, Prompt builder, Internal event objects, Prompt cache, Compaction endpoint, Sandbox and approval context
Prompt cache Inference-computation reuse path that depends on exact prefix matches across prompts. Conversation state manager, Responses API server
Compaction endpoint Responses API endpoint that replaces long conversation input with compacted items and encrypted latent state. Conversation state manager, Responses API server
Local environment Developer machine where Codex reads, writes, and edits files or runs commands. Codex CLI, Tool executor

Data flow

A user sends a message in Codex CLI. Codex builds a JSON payload with instructions, tools, and input, including developer messages for sandbox and configuration, user instructions from AGENTS files or skills, and the current user message. The request goes to a Responses API endpoint. The SSE stream returns output text deltas for UI streaming and output items such as reasoning/function-call records that Codex appends to the next input. If the model requests a tool call, Codex executes the relevant tool, appends the tool result, and re-queries the model. If the model returns an assistant message, the turn ends. Across turns, conversation history is resent statelessly, optimized by exact-prefix prompt caching and managed by automatic compaction once the context grows too large.

6 supporting quotes
“the agent loop, which is the core logic in Codex CLI that is responsible for orchestrating the interaction between the user, the model, and the tools”article, stated
“the model either (1) produces a final response to the user’s original input, or (2) requests a tool call that the agent is expected to perform”article, stated
“ls and report the output”). In the case of (2), the agent executes the tool call and appends its output to the original prompt. This output is used to generate a new input that’s used to re-query the model; the agent can then take this new information into account and try again. This process”article, stated
“The server replies with a Server-Sent Events (SSE⁠(opens in a new window)) stream.”article, stated
“internal event objects that can be used by a client. Events like response.output_text.delta are used to support streaming in the UI, whereas other events like response.output_item.added are transformed into objects that are appended to the input for subsequent Responses API calls. Suppose”article, stated
“Codex automatically uses this endpoint to compact the conversation when the auto_compact_limit⁠(opens in a new window) is exceeded. ##”article, stated

Why this architecture

Codex's architecture prioritizes safe local action, transparent state management, ZDR-compatible statelessness, prompt-cache efficiency, and context-window survival. Keeping the harness responsible for loop orchestration lets the model focus on deciding when to answer or request tools, while Codex handles execution, state replay, caching, compaction, and user-turn boundaries.

5 supporting quotes
“our cross-platform local software agent, designed to produce high-quality, reliable software changes while operating safely and efficiently on your machine.”article, stated
“Codex harness, which provides the core agent loop and execution logic that underlies all Codex experiences and is surfaced through the Codex CLI. For ease here, we’ll use the terms “Codex” and “Codex CLI” interchangeably. ## The agent loop At the heart of”article, stated
“Because the agent can execute tool calls that modify the local environment, its “output” is not limited to the assistant message.”article, stated
“Avoiding previous_response_id simplifies things for the provider of the Responses API because it ensures that every request is stateless.”article, stated
“We go to great lengths to ensure cache hits for performance. There’s another key resource we have to manage: the context window.”article, stated

Models used: Responses API · OpenAI hosted models · gpt-oss · ollama · LM Studio · Azure-hosted Responses API · Codex CLI · MCP

Scale

Alternatives considered (roads not taken)

Use previous_response_id to avoid resending full history

Rejected because: Codex chooses stateless requests to simplify provider implementation and support Zero Data Retention customers.

3 supporting quotes
“sent to the Responses API over the course of the conversation?” And you would be right. While the Responses API does support an optional previous_response_id⁠(opens in a new window)”article, stated
“Codex does not use it today, primarily to keep requests fully stateless and to support Zero Data Retention (ZDR) configurations.”article, stated
“storing the data required to support previous_response_id would be at odds with ZDR. Note that ZDR customers do not sacrifice the ability to benefit from proprietary reasoning messages from prior turns, as the associated encrypted_content can be”article, stated

Modify earlier prompt items when configuration changes

Rejected because: Changing early prompt content breaks exact-prefix cache hits, so Codex appends new messages for sandbox, approval, and working-directory changes.

3 supporting quotes
“Cache hits are only possible for exact prefix matches within a prompt. To realize caching benefits, place static content like instructions and examples at the beginning of your prompt, and put variable content, such as user-specific information, at the end.”article, stated
“we handle configuration changes that happen mid-conversation by appending a new message to input to reflect the change rather than modifying an earlier message: * If the sandbox configuration or approval mode changes, we [insert⁠(opens in a new”article, stated
“rather than modifying an earlier message: * If the sandbox configuration or approval mode changes, we [insert⁠(opens in a new”article, stated

Manual /compact only

Rejected because: Codex moved from manual compaction to automatic use of /responses/compact when auto_compact_limit is exceeded.

3 supporting quotes
“conversation, enabling the agent to continue with an understanding of what has happened thus far. An early implementation of compaction⁠(opens in a new window) required the user to manually invoke the /compact”article, stated
“implementation of compaction⁠(opens in a new window) required the user to manually invoke the /compact command, which would query the Responses API using the existing conversation plus custom instructions for [summarization⁠(opens”article, stated
“Now, Codex automatically uses this endpoint to compact the conversation when the auto_compact_limit⁠(opens in a new window) is exceeded.”article, stated

Assume all tools share Codex sandboxing

Rejected because: Only the Codex-provided shell tool is covered by Codex sandbox instructions; MCP tools must enforce their own guardrails.

“role=developer that describes the sandbox that applies only to the Codex-provided _shell_ tool defined in the tools section. That is, other tools, such as those provided from MCP servers, are not sandboxed by Codex and are responsible for enforcing their own guardrails. 2. (Optional)”article, stated
“other tools, such as those provided from MCP servers, are not sandboxed by Codex and are responsible for enforcing their own guardrails.”article, stated

Treat the assistant message as the agent's only output

Rejected because: For a software agent, code written or edited on the local machine is often the primary output.

“for the user. Because the agent can execute tool calls that modify the local environment, its “output” is not limited to the assistant message. In many cases, the primary output of a software agent is the code it writes or edits on your machine. Nevertheless, each”article, stated
“the primary output of a software agent is the code it writes or edits on your machine. Nevertheless, each turn always ends with an assistant message—such as “I added the architecture.md you asked for”—which signals a termination state in the agent loop.”article, stated

Patterns

tool-use-orchestration (agent-runtime)

The Codex harness repeatedly asks the model whether to answer or request a tool call, executes requested tools, appends outputs, and re-queries until the model emits an assistant message.

3 supporting quotes
“At the heart of every AI agent is something called “the agent loop.””article, stated
“the model either (1) produces a final response to the user’s original input, or (2) requests a tool call”article, stated
“This process repeats until the model stops emitting tool calls and instead produces a message for the user”article, stated

context-compaction (context-management)

Codex replaces long conversation input with compacted representative items through /responses/compact when the automatic threshold is exceeded.

3 supporting quotes
“Our general strategy to avoid running out of context window is to compact the conversation once the number of tokens exceeds some threshold.”article, stated
“It returns a list of items⁠(opens in a new window) that can be used in place of the previous input to continue the conversation while freeing up the context window.”article, stated
“Codex automatically uses this endpoint to compact the conversation when the [auto_compact_limit”article, stated

semantic-caching (performance)

Prompt caching reuses inference computation when subsequent prompts keep the old prompt as an exact prefix, making sampling linear instead of quadratic under cache hits.

3 supporting quotes
“In particular, note how the old prompt is an exact prefix of the new prompt. This is intentional, as this makes subsequent requests much more efficient because it enables us to take advantage of prompt caching (which we’ll discuss in the next section on performance).”article, stated
“this makes subsequent requests much more efficient because it enables us to take advantage of prompt caching”article, stated
“When we get cache hits, sampling the model is linear rather than quadratic.”article, stated

privacy-preserving-processing (data-governance)

Codex avoids previous_response_id so every request is stateless and compatible with Zero Data Retention, while encrypted_content preserves reasoning continuity without storing customer data.

3 supporting quotes
“Codex does not use it today, primarily to keep requests fully stateless and to support Zero Data Retention (ZDR) configurations.”article, stated
“storing the data required to support previous_response_id would be at odds with ZDR.”article, stated
“OpenAI persists a ZDR customer’s decryption key, but not their data.”article, stated

safety-policy-enforcement (tool-security)

Codex scopes sandbox instructions to its shell tool and makes MCP servers responsible for their own guardrails, preserving clear security boundaries by tool source.

“describes the sandbox that applies only to the Codex-provided _shell_ tool”article, stated
“MCP servers, are not sandboxed by Codex and are responsible for enforcing their own guardrails.”article, stated

prompt-versioning (configuration-management)

Codex layers system, developer, user, assistant, config, AGENTS, project-doc, and skill instructions with explicit precedence rather than a single prompt blob.

3 supporting quotes
“The role indicates how much weight the associated content should have and is one of the following values (in decreasing order of priority): system, developer, user, assistant.”article, stated
“Optional) A message with role=developer whose contents are the developer_instructions value read from the user’s config.toml file.”article, stated
“Contents of AGENTS.override.md and AGENTS.md in $CODEX_HOME”article, stated

fallback-degradation (provider-flexibility)

Codex CLI can use multiple Responses API endpoints, including ChatGPT, OpenAI API keys, local gpt-oss through ollama/LM Studio, and Azure-hosted endpoints.

“* [When using ChatGPT login⁠(opens in a new window)](https://github.com/openai/codex/blob/d886a8646cb8d3671c3029d08ae8f13fa6536899/codex-rs/core/src/model_provider_info." — *article, stated* "window)](https://github.com/openai/codex/blob/d886a8646cb8d3671c3029d08ae8f13fa6536899/codex-rs/core/src/model_provider_info.rs#L141) with the Codex CLI, it uses https://chatgpt.com/backend-api/codex/responses as the endpoint * [When using API-key authentication⁠(opens in a new”article, stated
“Codex CLI can be used with the Responses API hosted by a cloud provider such as Azure”article, stated

Tradeoffs

Keep Responses API requests stateless

Chose Full-history stateless requests over previous_response_id statefulness.

Rationale: Stateless requests preserve ZDR compatibility and simplify provider implementation, even though the JSON payload grows over conversation lifetime.

3 supporting quotes
“Codex does not use it today, primarily to keep requests fully stateless and to support Zero Data Retention (ZDR) configurations.”article, stated
“Avoiding previous_response_id simplifies things for the provider of the Responses API”article, stated
“storing the data required to support previous_response_id would be at odds with ZDR.”article, stated

Optimize by preserving prompt prefixes

Chose Append-only prompt evolution where possible over Rewriting earlier prompt items when configuration changes.

Rationale: Exact prefix preservation enables prompt caching and avoids expensive cache misses during long agent sessions.

3 supporting quotes
“In particular, note how the old prompt is an exact prefix of the new prompt. This is intentional, as this makes subsequent requests much more efficient because it enables us to take advantage of prompt caching (which we’ll discuss in the next section on performance).”article, stated
“To realize caching benefits, place static content like instructions and examples at the beginning of your prompt”article, stated
“we handle configuration changes that happen mid-conversation by appending a new message to input”article, stated

Automatically compact conversations

Chose /responses/compact with a compaction item over Manual /compact as the normal context-management path.

Rationale: Automatic compaction frees context window space while preserving the model's latent understanding through encrypted content.

3 supporting quotes
“far. An early implementation of compaction⁠(opens in a new window) required the user to manually invoke the /compact command, which would query the Responses API using the existing conversation plus custom instructions for [summarization⁠(opens in a new”article, stated
“a special type=compaction item with an opaque encrypted_content item that preserves the model’s latent understanding”article, stated
“Codex automatically uses this endpoint to compact the conversation when the [auto_compact_limit”article, stated

Treat assistant message as turn termination, not sole output

Chose Code edits as primary work product plus assistant summary over Text-only chat answer model.

Rationale: A software agent's meaningful output is often file changes on the user's machine, while the assistant message returns control to the user.

3 supporting quotes
“the primary output of a software agent is the code it writes or edits on your machine.”article, stated
“Nevertheless, each turn always ends with an assistant message—such as “I added the architecture.md you asked for”—which signals a termination state in the agent loop.”article, stated
“signals a termination state in the agent loop. From the agent’s perspective, its work is complete and control returns to the user.”article, stated

Expose multiple Responses API endpoints

Chose ChatGPT, OpenAI API key, local gpt-oss, LM Studio/Ollama, and Azure-compatible endpoints over One fixed hosted inference endpoint.

Rationale: Endpoint flexibility supports different authentication modes, local/open-weight usage, and cloud-provider deployments.

3 supporting quotes
“window) with OpenAI hosted models, it uses https://api.openai.com/v1/responses as the endpoint * When running Codex CLI with --oss to use”article, stated
“Codex CLI can be used with the Responses API hosted by a cloud provider such as Azure”article, stated

Gotchas (what bit them)

Conversation-history replay makes the agent loop look quadratic.

Root cause: Each new request includes prior conversation messages and tool calls, so JSON sent to the API grows over time.

Resolution: Keep stateless requests for ZDR, but rely on exact-prefix prompt caching so model sampling stays linear under cache hits.

3 supporting quotes
“isn’t the agent loop quadratic in terms of the amount of JSON sent to the Responses API over the course of the conversation?” And you would be right.”article, stated
“Codex does not use it today, primarily to keep requests fully stateless and to support Zero Data Retention (ZDR) configurations.”article, stated
“When we get cache hits, sampling the model is linear rather than quadratic.”article, stated

Changing tools mid-conversation can destroy prompt-cache efficiency.

Root cause: Prompt caching requires exact prefix matches, and tool definitions are part of the prompt prefix.

Resolution: Maintain stable tool ordering and be cautious with dynamic MCP tool-list changes.

3 supporting quotes
“Cache hits are only possible for exact prefix matches within a prompt.”article, stated
“Changing the tools available to the model in the middle of the conversation.”article, stated
“our initial support for MCP tools introduced a [bug where we failed to enumerate the tools in a consistent order”article, stated

MCP servers can change available tools while a conversation is in progress.

Root cause: MCP servers can send tool-list-changed notifications, but honoring them changes prompt tool definitions and can trigger expensive cache misses.

Resolution: Treat dynamic MCP tool lists as a performance-sensitive design decision rather than blindly updating prompt state.

“MCP servers can change the list of tools they provide on the fly via a [notifications/tools/list_changed”article, stated
“Honoring this notification in the middle of a long conversation can cause an expensive cache miss.”article, stated

Tool security boundaries differ by tool source.

Root cause: Codex sandbox instructions only govern the Codex-provided shell tool; MCP tools are external and must implement their own safeguards.

Resolution: Document and enforce tool-specific guardrail responsibility instead of assuming one sandbox covers every tool.

“applies only to the Codex-provided_ _shell_ tool defined in the tools section.”article, stated
“MCP servers, are not sandboxed by Codex and are responsible for enforcing their own guardrails.”article, stated

Long coding conversations can exhaust the context window.

Root cause: Every turn appends conversation history, messages, and tool calls, and a single turn may have hundreds of tool calls.

Resolution: Compact the conversation into a smaller representative item list using /responses/compact when auto_compact_limit is exceeded.

3 supporting quotes
“This means that as the conversation grows, so does the length of the prompt used to sample the model.”article, stated
“an agent could decide to make hundreds of tool calls in a single turn, potentially exhausting the context window.”article, stated
“replace the input with a new, smaller list of items that is representative of the conversation”article, stated

Evaluation

The article is architectural rather than benchmark-driven. It evaluates production readiness through design invariants and operational properties: stateless ZDR compatibility, exact-prefix preservation for prompt caching, automatic compaction before context exhaustion, correct SSE event handling, clean turn termination, and explicit sandbox boundaries for tool sources.

Metrics: Exact prefix preservation for cache hits · Linear rather than quadratic sampling under prompt cache hits · ZDR-compatible stateless requests · Context-window utilization and auto_compact_limit triggering · Consistent MCP tool enumeration order · SSE event transformation into UI deltas and future input items · Assistant-message termination of each turn

6 supporting quotes
“In particular, note how the old prompt is an exact prefix of the new prompt. This is intentional, as this makes subsequent requests much more efficient because it enables us to take advantage of prompt caching (which we’ll discuss in the next section on performance).”article, stated
“When we get cache hits, sampling the model is linear rather than quadratic.”article, stated
“Codex does not use it today, primarily to keep requests fully stateless and to support Zero Data Retention (ZDR) configurations.”article, stated
“context window management_ is one of the agent’s many responsibilities.”article, stated
“events like response.output_item.added are transformed into objects that are appended to the input for subsequent Responses API calls.”article, stated
“Nevertheless, each turn always ends with an assistant message—such as “I added the architecture.md you asked for”—which signals a termination state in the agent loop.”article, stated

Outcomes

The article gives architecture scale rather than usage volume: Codex spans CLI, Cloud, and VS Code extension offerings; user instructions can include up to 32 KiB of project documentation by default; a single turn can involve hundreds of tool calls; and the CLI can target ChatGPT, OpenAI API, local localhost:11434, and Azure Responses API endpoints.

6 supporting quotes
“cross-platform local software agent, designed to produce high-quality, reliable software changes while operating safely and efficiently on your machine”article, stated
“at OpenAI, “Codex” encompasses a suite of software agent offerings, including Codex CLI, Codex Cloud, and the Codex VS Code extension.”article, stated
“Looking back at our first diagram of the agent loop, we see that there could be many iterations between inference and tool calling. The prompt may continue to grow until we finally receive an assistant message, indicating the end of the turn:”article, stated
“Codex does not use it today, primarily to keep requests fully stateless and to support Zero Data Retention (ZDR) configurations.”article, stated
“When we get cache hits, sampling the model is linear rather than quadratic.”article, stated
“Codex automatically uses this endpoint to compact the conversation when the [auto_compact_limit”article, stated