Run a Codex agent
The Codex runtime replaces the PromptKit runtime container with one that drives the Codex CLI. The agent’s inference is billed to an OpenAI API key or, signed in with ChatGPT, to one person’s ChatGPT plan. Every session the agent serves uses that one credential.
It works like the Claude Code runtime: the facade, sessions and exposure work as for any agent, and the CLI’s tools are the agent’s ToolRegistry tools, run the same way as for a PromptKit agent. Codex’s own shell, file, web search, browser and image features are off, so nothing runs on the runtime pod.
Prerequisites
Section titled “Prerequisites”- An OpenAI API key, or the Codex CLI on a machine signed in to a ChatGPT plan.
- A PromptPack for the agent’s
promptPackRef.
Create the credential
Section titled “Create the credential”With an API key, store it in a Secret in the agent’s namespace:
kubectl create secret generic codex-credential --from-literal=api-key=<key>To bill a ChatGPT plan instead, sign in on a machine with codex login, and
store the file it writes:
kubectl create secret generic codex-credential --from-file=auth.json=$HOME/.codex/auth.jsonDeploy the agent
Section titled “Deploy the agent”apiVersion: omnia.altairalabs.ai/v1alpha1kind: AgentRuntimemetadata: name: codexspec: promptPackRef: { name: codex-pack } framework: type: custom image: ghcr.io/altairalabs/omnia-codex-runtime:main facades: - type: websocket runtime: replicas: 1 extraEnv: - name: OPENAI_API_KEY valueFrom: secretKeyRef: { name: codex-credential, key: api-key } volumes: - name: cli-home emptyDir: {} volumeMounts: - { name: cli-home, mountPath: /home/codex }With a ChatGPT sign-in, replace OPENAI_API_KEY with CODEX_AUTH_JSON taken
from the auth.json key. The runtime writes it where Codex looks for it when
it starts.
Put the credential and the volume under spec.runtime. It applies to the
runtime container only. podOverrides applies to the facade container too,
and would expose the credential to it.
Keep replicas: 1 and leave autoscaling off. A session’s CLI process lives in
the pod that started it.
The cli-home volume is required. The runtime container’s root filesystem is
read-only, and Codex keeps its own state under /home/codex. Without the
volume the runtime exits at startup with a message naming it.
To choose the model, add OMNIA_CLI_MODEL to extraEnv. Unset uses Codex’s
default.
Give the agent tools
Section titled “Give the agent tools”Reference a ToolRegistry, exactly as for a PromptKit agent:
spec: toolRegistryRef: { name: codex-tools }Codex sees the tools under their own names, grouped as an MCP server named
omnia. Each call goes through the same executor as a PromptKit agent’s, so
ToolPolicy decisions, injected headers, credentials and delegation apply to
it. Calls appear on the session’s tool calls in the dashboard. A handler with
a sandbox block, on an
AgentRuntime with spec.sandbox enabled, gives each session its own sandbox,
as for a Claude Code agent.
Configure the prompt and skills
Section titled “Configure the prompt and skills”The runtime gives Codex the pack’s prompt as developer instructions. The
pack’s skills are listed to Codex by name and description. Codex’s shell is
off, so it cannot open a skill’s files itself. Instead, the runtime serves them
read-only as resources of the omnia MCP server, at
skill://<skill name>/<path>. It also tells Codex to read a skill’s
SKILL.md before using the skill. An agent with skills and no ToolRegistry
works the same way.
Files in a skill’s subfolders are served under their relative path, so a
SKILL.md that points to refs/checklist.md works. Codex can read a skill’s
scripts but cannot run them; make anything the agent must run a ToolRegistry
tool.
Each skill serves at most 200 files, and files over 1 MiB are left out. The runtime logs each file it leaves out when it starts. A changed pack takes effect when the agent’s pods roll out.
Answer the agent’s questions
Section titled “Answer the agent’s questions”When Codex needs a decision it asks, and the question appears in the dashboard console as a card, as for a Claude Code agent. Over A2A, from a function call or on a schedule, Codex is told nobody is available and proceeds on its best judgment.
Limit concurrent sessions and keep conversations
Section titled “Limit concurrent sessions and keep conversations”The concurrency limit (OMNIA_CLI_MAX_CONCURRENT, default four), idle
stopping and resuming all work as for a
Claude Code agent.
So does resuming after a pod restart with a Redis context
store; see
Keep conversations across pod restarts.
A session resumes its Codex thread.
Verify
Section titled “Verify”kubectl get agentruntime codex -o jsonpath='{.status.runtimeCapabilities}'The output is ["invoke","client_tools"]. Open the agent in the dashboard
console and send a message; the reply streams as it is written.
The runtime records token counts on each message with a cost of 0. Each turn
is also recorded as a provider call with the source codex-notional and
Codex’s token counts. Codex reports no price, so its cost is 0 and cost
totals leave it out.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause |
|---|---|
Runtime container exits with HOME ... is not writable | The cli-home volume is missing from spec.runtime. |
Runtime container exits with codex CLI is X but this runtime was built against Y | The image’s CLI was replaced. Use the published image. |
Runtime container exits with CODEX_AUTH_JSON is not JSON | The Secret holds something other than Codex’s auth.json. |
A reply fails with codex CLI turn failed | Codex reported the turn failed; the message names its error, for example an invalid credential. |
| A conversation restarts from scratch after a pod restart | The agent has no Redis context store. |
| The agent says it has no tools | The runtime logs tool bridge init failed at startup when the ToolRegistry’s tools could not be loaded. |
See Authoring a custom runtime for the runtime contract this image implements.