Govern Codex CLI with DVARA
Codex CLI sends its model calls straight to OpenAI. Your security team sees
none of them. From 1.9.0 DVARA serves what Codex sends on the OpenAI Responses
API, POST /v1/responses, with Codex's default settings. Point Codex at the
DVARA AI governance platform and every model call it makes is governed and billed to one DVARA workspace.
Tested with Codex CLI 0.155.1.
What DVARA governs
Each model call Codex makes runs the same controls as
/v1/chat/completions: policy, PII rules, guardrails, budgets, rate limits,
cost records and the audit chain. That includes the tool calls the model asks
for and the tool output Codex sends back, so a guardrail or PII rule sees the
files and command output that reach the model.
Point Codex CLI at DVARA
You need:
- A running DVARA 1.9.0 Gateway that Codex can reach.
- A provider for the models Codex asks for. For OpenAI models, set
OPENAI_API_KEYon the Gateway. - A DVARA workspace API key. If the key has scopes, it needs
completions:write.
Add a provider for DVARA to ~/.codex/config.toml:
model_provider = "dvara"
model = "<model-id>" # a model your Gateway routes
web_search = "disabled" # required: see below
[model_providers.dvara]
name = "DVARA"
base_url = "https://gateway.acme.example.com/v1"
env_key = "DVARA_API_KEY"
wire_api = "responses"
Then set the key where Codex runs, and start Codex as usual:
export DVARA_API_KEY=<dvara-workspace-key>
codex
base_urlends in/v1. Codex adds/responsesitself.env_keynames the variable that holds the key. Codex sends it asAuthorization: Bearer. Use a DVARA key, not an OpenAI key.wire_api = "responses"makes Codex use the Responses API.
Turn off Codex's built-in web search
Codex asks OpenAI to search the web for it by default. That search runs at OpenAI, outside DVARA, so DVARA cannot check what it fetches. DVARA refuses a request that asks for it, and Codex shows:
the tool type web_search is not supported on /v1/responses: it runs at the
provider, outside the gateway's checks. In Codex CLI, set web_search = "disabled"
in config.toml.
Set web_search = "disabled" as in the example above.
What happens on each route
On a route to OpenAI or Azure OpenAI, DVARA sends Codex's request to the provider's own Responses API as Codex sent it. It changes only what governance changes, such as redacted text or the routed model. Codex's encrypted reasoning goes back and forth between turns unchanged, so a long session keeps its reasoning. The answer comes back as the provider sent it. Usage and cost come from the provider's own figures, including cached and reasoning tokens.
On a route to another provider, such as Anthropic or Gemini, DVARA translates the request to that provider's chat API:
- Codex's own tools, including its patch tool and tool search, become tools the provider understands. Their calls come back in the shape Codex expects.
- Images in a tool's output reach the model.
- The answer carries no reasoning. Earlier reasoning from Codex is left out.
- Settings only OpenAI understands, such as reasoning effort, are left out.
What DVARA refuses
DVARA refuses with 400 unsupported_capability anything that would run or be
stored outside the Gateway, and says what to change:
| Refused | Why | What to do |
|---|---|---|
| Built-in tools: web search, file search, code interpreter, computer use, image generation, remote MCP | They run at the provider, outside DVARA's checks | Set web_search = "disabled" in Codex |
store: true, previous_response_id | They keep the conversation at the provider | Codex's defaults do not send them |
| A file part in a tool's output | Most providers cannot take one there | — |
A refusal before the stream starts comes back as a normal HTTP error with a JSON body, so Codex shows the reason.
Known limits
- Codex's local actions are not governed. File edits and shell commands run on the developer's machine and never reach DVARA. DVARA sees what Codex sends to the model, including the output of those commands.
- A cached answer has no reasoning items. If you turn on DVARA's response cache, an answer served from it is built by DVARA.
- No reasoning on a translated route. Use an OpenAI or Azure OpenAI route if your sessions depend on reasoning.
Where to go next
- Data-plane API overview
for everything
/v1/responsesaccepts. - Agent sessions to tie a session's calls together.
- Authenticate data-plane calls for key scopes.