Summary
Codex CLI is a required Client/Harness, but current Codex custom Providers only speak the Responses wire API and ModelPort intentionally has no /v1/responses route. Add only the pinned-Codex subset behind a default-off experimental gate, through the typed Exchange IR and existing governance pipeline.
Actual behavior
The Dashboard correctly blocks Codex CLI and exposes no configuration because POST /v1/responses is absent. Claude Code, Qwen Code, and OpenAI SDK profiles use the existing Messages or Chat Completions ingress.
Expected behavior
A default-off, typed, fail-closed POST /v1/responses path can run a pinned Codex text turn and function-tool round trip through ModelPort with the same auth, policy, routing, quota, ledger, stream, and privacy guarantees as existing ingress. Unsupported Responses semantics remain rejected and no full-API or Tier 1 claim is made.
Steps to reproduce
Install or select a pinned Codex CLI, configure a custom Provider with base_url pointing to ModelPort /v1 and wire_api=responses, and run a synthetic prompt. Current ModelPort has no POST /v1/responses route, so the workflow cannot start; Issue #36 therefore keeps the Codex setup profile blocked.
Environment
ModelPort main at merge commit 14ea1f5; Linux x86_64; locally observed codex-cli 0.148.0-alpha.21 on 2026-08-24.
Acceptance criteria
Additional context
Product and evidence gate
The project owner requires Codex CLI alongside Claude Code, Qwen Code, and SDK
clients. Issue #36 confirmed that a safe Codex profile cannot be emitted today:
Codex custom Providers support only the Responses wire API, while ModelPort has
no POST /v1/responses ingress. The target machine currently has
codex-cli 0.148.0-alpha.21; implementation must pin and record the exact Codex
version used for acceptance.
This is a bounded exception path to the v0.1.x protocol freeze, not a general
Responses compatibility claim. It must remain disabled by default and
experimental until the acceptance evidence below is reviewed. The current
Anthropic Messages and OpenAI Chat Completions routes remain unchanged.
Official contract inputs:
Required protocol boundary
- Add only authenticated
POST /v1/responses over HTTP/SSE, behind an explicit
server-owned experimental flag that defaults off. Do not add WebSocket,
realtime, compact/retrieve/delete/cancel endpoints, background mode,
conversations, hosted built-in tools, image/audio/file inputs, or generic
pass-through.
- Parse a typed Codex-bounded request into the existing Exchange IR. The first
accepted surface is text instructions/messages, function tools,
function_call and function_call_output items, tool_choice=auto, bounded
parallel_tool_calls, stream=true, and store=false. The captured fixture
decides which optional request fields must be accepted. Every other field or
item kind fails before Provider egress with a stable, documented error.
- Treat
include=["reasoning.encrypted_content"], reasoning controls,
verbosity, prompt-cache metadata, service tier, and client metadata
explicitly: validate and preserve supported semantics, or document and
reject them. Never fabricate encrypted reasoning, silently drop a required
capability, forward client metadata as trusted policy, or persist prompt,
response, tool argument/result, or raw body content.
- Render protocol-native Responses lifecycle events with stable IDs and ordered
sequence numbers. Text streaming covers response.created, output-item and
content lifecycle, response.output_text.delta, and terminal
response.completed. Function calls preserve call_id, name, complete JSON
arguments, and the matching output causality. Pre-header failures remain
normal HTTP errors; post-header failure/timeout/cancellation is represented
in the Responses stream and finalized exactly once.
- Reuse the existing authentication, model resolution, API-key/team/IP policy,
rate/stream limits, route eligibility, retry/fallback, quota and spend
reservation, request/attempt ledger, usage provenance, request ID,
idempotency, timeout, body/SSE bounds, credential selection, and egress
controls. The endpoint must not create a second routing or accounting path.
Compatibility evidence and activation
- Add content-free, sanitized fixtures that record request field/item kinds and
event ordering from the pinned Codex version. Do not commit Codex base
instructions, repository context, prompts, tool arguments/results, API keys,
authorization headers, cookies, or full request/response bodies.
- Add an opt-in acceptance command that takes an explicit Codex binary path and
synthetic prompt, uses a disposable config/profile and ModelPort client key,
proves a text turn plus one function-tool round trip, and deletes its
temporary state. It must not read or overwrite the user's ~/.codex files.
- Only after that acceptance passes may the Dashboard change Codex CLI from
blocked to experimental/configurable when the server reports the feature is
enabled. The generated profile uses base_url=<gateway>/v1,
wire_api="responses", env_key="MODELPORT_API_KEY", and never embeds the
client key in TOML. Disabled servers continue to show the current blocked
state and no copy action.
- Update Architecture, API, Configuration, Compatibility, Development,
Operations, and Tool Use evidence docs. The support matrix must continue to
say this is experimental, exact-version evidence—not full OpenAI Responses,
generic Codex/provider compatibility, or Tier 1 support.
Tests and rollback
- Add parser/rendering tests for all accepted items and fields; text and
function-call non-loss; split SSE frames; duplicate/missing/out-of-order
terminal events; invalid JSON arguments; orphan tool outputs; unsupported
items/fields; size, count, timeout, cancellation, and post-header errors.
- Add route tests proving the experimental-off behavior, authentication and
policy rejection before egress, idempotency, bounded fallback, ledger
finalization, usage provenance, and no content persistence.
- Add mock-backed end-to-end coverage for an OpenAI-compatible Provider and an
Anthropic Provider where the Exchange IR can preserve the exact requested
semantics. Unsupported Provider/model capability combinations fail closed.
- Rollback is the experimental flag: disabling it removes the route and
Dashboard copy action without schema rollback, deleting evidence, or changing
the two existing ingress protocols.
Explicit non-goals
- Full Responses API parity or a compatibility percentage.
- Responses-over-WebSocket, Realtime, embeddings, image/audio/file inputs,
hosted web/file/computer/code-interpreter tools, response storage/retrieval,
conversation state, compaction, or background execution.
- Raw JSON pass-through, bypassing the Exchange IR or governance pipeline,
changing Provider credentials/resources, or making Codex a Provider.
- Enabling the route by default or promoting it to Tier 1 without separate,
dated design-partner evidence and a reviewed compatibility decision.
Summary
Codex CLI is a required Client/Harness, but current Codex custom Providers only speak the Responses wire API and ModelPort intentionally has no /v1/responses route. Add only the pinned-Codex subset behind a default-off experimental gate, through the typed Exchange IR and existing governance pipeline.
Actual behavior
The Dashboard correctly blocks Codex CLI and exposes no configuration because POST /v1/responses is absent. Claude Code, Qwen Code, and OpenAI SDK profiles use the existing Messages or Chat Completions ingress.
Expected behavior
A default-off, typed, fail-closed POST /v1/responses path can run a pinned Codex text turn and function-tool round trip through ModelPort with the same auth, policy, routing, quota, ledger, stream, and privacy guarantees as existing ingress. Unsupported Responses semantics remain rejected and no full-API or Tier 1 claim is made.
Steps to reproduce
Install or select a pinned Codex CLI, configure a custom Provider with base_url pointing to ModelPort /v1 and wire_api=responses, and run a synthetic prompt. Current ModelPort has no POST /v1/responses route, so the workflow cannot start; Issue #36 therefore keeps the Codex setup profile blocked.
Environment
ModelPort main at merge commit 14ea1f5; Linux x86_64; locally observed codex-cli 0.148.0-alpha.21 on 2026-08-24.
Acceptance criteria
Additional context
Product and evidence gate
The project owner requires Codex CLI alongside Claude Code, Qwen Code, and SDK
clients. Issue #36 confirmed that a safe Codex profile cannot be emitted today:
Codex custom Providers support only the Responses wire API, while ModelPort has
no
POST /v1/responsesingress. The target machine currently hascodex-cli 0.148.0-alpha.21; implementation must pin and record the exact Codexversion used for acceptance.
This is a bounded exception path to the v0.1.x protocol freeze, not a general
Responses compatibility claim. It must remain disabled by default and
experimental until the acceptance evidence below is reviewed. The current
Anthropic Messages and OpenAI Chat Completions routes remain unchanged.
Official contract inputs:
https://developers.openai.com/codex/config-reference/
https://github.com/openai/codex/blob/main/codex-rs/core/src/client.rs
https://github.com/openai/codex/blob/main/codex-rs/core/tests/common/responses.rs
https://developers.openai.com/api/reference/cli/resources/responses/methods/create
https://developers.openai.com/api/docs/guides/streaming-responses
https://developers.openai.com/api/docs/guides/function-calling
Required protocol boundary
POST /v1/responsesover HTTP/SSE, behind an explicitserver-owned experimental flag that defaults off. Do not add WebSocket,
realtime, compact/retrieve/delete/cancel endpoints, background mode,
conversations, hosted built-in tools, image/audio/file inputs, or generic
pass-through.
accepted surface is text instructions/messages, function tools,
function_callandfunction_call_outputitems,tool_choice=auto, boundedparallel_tool_calls,stream=true, andstore=false. The captured fixturedecides which optional request fields must be accepted. Every other field or
item kind fails before Provider egress with a stable, documented error.
include=["reasoning.encrypted_content"], reasoning controls,verbosity, prompt-cache metadata, service tier, and client metadata
explicitly: validate and preserve supported semantics, or document and
reject them. Never fabricate encrypted reasoning, silently drop a required
capability, forward client metadata as trusted policy, or persist prompt,
response, tool argument/result, or raw body content.
sequence numbers. Text streaming covers
response.created, output-item andcontent lifecycle,
response.output_text.delta, and terminalresponse.completed. Function calls preservecall_id, name, complete JSONarguments, and the matching output causality. Pre-header failures remain
normal HTTP errors; post-header failure/timeout/cancellation is represented
in the Responses stream and finalized exactly once.
rate/stream limits, route eligibility, retry/fallback, quota and spend
reservation, request/attempt ledger, usage provenance, request ID,
idempotency, timeout, body/SSE bounds, credential selection, and egress
controls. The endpoint must not create a second routing or accounting path.
Compatibility evidence and activation
event ordering from the pinned Codex version. Do not commit Codex base
instructions, repository context, prompts, tool arguments/results, API keys,
authorization headers, cookies, or full request/response bodies.
synthetic prompt, uses a disposable config/profile and ModelPort client key,
proves a text turn plus one function-tool round trip, and deletes its
temporary state. It must not read or overwrite the user's
~/.codexfiles.blocked to experimental/configurable when the server reports the feature is
enabled. The generated profile uses
base_url=<gateway>/v1,wire_api="responses",env_key="MODELPORT_API_KEY", and never embeds theclient key in TOML. Disabled servers continue to show the current blocked
state and no copy action.
Operations, and Tool Use evidence docs. The support matrix must continue to
say this is experimental, exact-version evidence—not full OpenAI Responses,
generic Codex/provider compatibility, or Tier 1 support.
Tests and rollback
function-call non-loss; split SSE frames; duplicate/missing/out-of-order
terminal events; invalid JSON arguments; orphan tool outputs; unsupported
items/fields; size, count, timeout, cancellation, and post-header errors.
policy rejection before egress, idempotency, bounded fallback, ledger
finalization, usage provenance, and no content persistence.
Anthropic Provider where the Exchange IR can preserve the exact requested
semantics. Unsupported Provider/model capability combinations fail closed.
Dashboard copy action without schema rollback, deleting evidence, or changing
the two existing ingress protocols.
Explicit non-goals
hosted web/file/computer/code-interpreter tools, response storage/retrieval,
conversation state, compaction, or background execution.
changing Provider credentials/resources, or making Codex a Provider.
dated design-partner evidence and a reviewed compatibility decision.