Codex
Protect a Codex CLI session without changing any code — point it at a local relay instead of the OpenAI Responses API.
tawa-codex-proxy is the Codex CLI counterpart to
the Claude Code relay: a standalone process that sits
between Codex CLI and OpenAI, so you get scanning without editing Codex
itself or writing any integration code.
Built, not yet proven against a real Codex CLI session
This relay is implemented and tested against the documented Responses API
wire protocol (cross-checked against a third-party Codex proxy's own
reverse-engineered event types), the same way
the Claude Code relay was before it was verified — but
it hasn't yet been run end-to-end against a real codex binary the way
that one has. Treat the design as high-confidence, not proven. This page
will be updated once that verification pass happens.
Codex CLI reads OPENAI_BASE_URL once at startup and routes every request
through whatever's listening there. Point that at tawa-codex-proxy instead
of api.openai.com directly, and every request is scanned before it goes
anywhere near OpenAI:
┌─▶ your Tawa account's hosted
│ detection (request scan)
│
Codex CLI ──OPENAI_BASE_URL──▶ tawa-codex-proxy ──▶ api.openai.com
│ │
│ (streamed response) ◀───┘
└─▶ your Tawa account's hosted
detection (action-call scan + model's own
reply, before either reaches Codex CLI)What gets scanned
Both directions of every POST /v1/responses are inspected.
Inbound, before it reaches OpenAI: the relay looks at the newest content
in the input array — Codex CLI resends the whole array every turn (it
doesn't use previous_response_id), but only appends new items since its
last request, so scanning just those keeps cost flat instead of growing
with the conversation.
- If it's a fresh human turn, it's scanned as
user_prompt. - If it's one or more
function_call_outputitems being fed back into context, they're scanned astool_output. Codex can request several tool calls in parallel, so this is a trailing run of new output items, not just the last one — the generalization of the same rule the Claude Code relay uses for a single tool result.
Outbound, before Codex CLI (or you) can act on it: two kinds of output
item are buffered and scanned — everything else (reasoning items,
response-level lifecycle events) streams through live, unbuffered.
- An action item — a
function_call(the confirmed, common shape: MCP tools and Codex's own shell/patch actions both go through this today) or any other non-text item type — is scanned before Codex CLI can act on it. Rather than hardcode a parser per item type, every item type other thanmessageandreasoningis gated the same generic way: buffered between itsresponse.output_item.addedandresponse.output_item.doneevents (every item type has both, regardless of its own delta shape) and scanned from whatever the final item JSON contains. This is deliberately conservative — a future action-shaped item type this proxy has never seen still gets gated, not silently forwarded. - The model's own visible reply — any
messageitem — is scanned too, on by default, in the same streaming checkpoints as the Claude Code relay uses for its text output.
Any direction: a BLOCK, HARD_BLOCK, or SANDBOX verdict stops it —
a plain OpenAI-shaped 400 error on the request side, or a synthetic
mid-stream error SSE event on the response side (the Responses API's own
documented, in-band mechanism for a stream that already returned 200 OK
to fail partway through) that ends the stream before the gated item ever
reaches the client. Every other verdict forwards through by default, same
policy as the Claude Code relay. A REVIEW the gateway has already collapsed
to BLOCK for the app's content-type setting is a block here. See
Configuration for how that's decided.
Scope today
What's covered:
- Every user prompt and every tool output read back into context, including parallel tool-call turns.
- Every action item (
function_calltoday; any future item type generically), scanned before Codex CLI can act on it. - The model's own visible reply, scanned before it reaches Codex CLI (on by default, toggleable).
What isn't built yet:
- Not yet run against a real Codex CLI session. See the callout above — this is the single most important gap before relying on this for anything real.
- No session correlation. The Claude Code relay forwards Claude Code's own session-id header through to Tawa so related scans can be correlated in Tawa's event stream/audit trail. There's no confirmed equivalent header for Codex CLI yet, so this relay doesn't attempt one rather than guess at a name that might not exist.
- Per-user identifiers and Policy Studio directives aren't wired in — same gap as the Claude Code relay.