Codex uses the @zed-industries/codex-acp adapter for ACP support.
The recommended working directory for the Codex image is /home/node; this is
also the container HOME, so Codex auth, sessions, generated images, and skills
live under /home/node/.codex/.
docker build -f Dockerfile.codex -t openab-codex:latest .The image installs @zed-industries/codex-acp and @openai/codex globally via npm.
helm install openab openab/openab \
--set agents.kiro.enabled=false \
--set agents.codex.discord.enabled=true \
--set agents.codex.discord.botToken="$DISCORD_BOT_TOKEN" \
--set-string 'agents.codex.discord.allowedChannels[0]=YOUR_CHANNEL_ID' \
--set agents.codex.image=ghcr.io/openabdev/openab-codex:latest \
--set agents.codex.command=codex-acp \
--set agents.codex.workingDir=/home/nodeSet
agents.kiro.enabled=falseto disable the default Kiro agent.
[agent]
command = "codex-acp"
args = []
working_dir = "/home/node"kubectl exec -it deployment/openab-codex -- codex login --device-authFollow the device code flow in your browser, then restart the pod:
kubectl rollout restart deployment/openab-codex| Path | Contents |
|---|---|
/home/node/.codex/auth.json |
Codex login credentials |
/home/node/.codex/config.toml |
Codex CLI settings and feature flags |
/home/node/.codex/sessions/ |
Session history |
/home/node/.codex/generated_images/ |
Built-in image generation outputs |
/home/node/.codex/skills/ |
User-created Codex skills |
Codex built-in image generation uses the gpt-image-2 model under the hood.
It is controlled by the Codex CLI feature flag image_generation. Enable it
once inside the pod:
kubectl exec -it deployment/openab-codex -- \
codex features enable image_generationThis writes the following to /home/node/.codex/config.toml:
[features]
image_generation = trueYou can verify it with:
kubectl exec -it deployment/openab-codex -- \
codex features list | grep image_generationGenerated images are saved by Codex under
/home/node/.codex/generated_images/.... If the user needs a stable path, ask
Codex to copy the selected output into /home/node, for example
/home/node/sky-birds.png.
Note: Codex image generation may return a model-native size rather than the exact dimensions requested in the prompt. If exact dimensions matter, resize only when the user explicitly asks for it.
kubectl exec -it deployment/openab-codex -- \
codex exec \
--dangerously-bypass-approvals-and-sandbox \
--enable image_generation \
--skip-git-repo-check \
-C /home/node \
"Use the imagegen skill and the built-in image_gen tool. Generate a simple image of birds flying across a bright sky. Save or copy the final PNG to /home/node/sky-birds.png. Report the output path and dimensions."Then check for output:
kubectl exec -it deployment/openab-codex -- \
sh -lc 'ls -lh /home/node/sky-birds.png /home/node/.codex/generated_images/*/* 2>/dev/null | tail'OpenAB streams text over ACP only. It does not relay image attachments from Codex back to Discord. To send a generated image, Codex must call the Discord REST API directly. See sendimages.md for the full protocol.
The agent should:
- Read
thread_idfrom OpenAB's<sender_context>and use it as the Discord target channel. Ifthread_idis absent, fall back tochannel_id. - Upload the file with
POST /channels/{id}/messagesusing multipart form data. - Read the token from
DISCORD_FILE_BOT_TOKENif available, otherwiseDISCORD_BOT_TOKEN.
Example upload from inside the pod:
THREAD_ID="1499442140172910654"
IMAGE="/home/node/sky-birds.png"
curl -X POST "https://discord.com/api/v10/channels/${THREAD_ID}/messages" \
-H "Authorization: Bot ${DISCORD_FILE_BOT_TOKEN:-$DISCORD_BOT_TOKEN}" \
-F "content=Here is the generated image" \
-F "files[0]=@${IMAGE}"The Discord bot token configured under [discord] is consumed by OpenAB itself.
For safety, OpenAB clears the inherited environment before spawning the agent and
only passes variables listed in [agent].env. If Codex should upload images
itself, explicitly expose an upload token to the agent:
[agent]
command = "codex-acp"
args = []
working_dir = "/home/node"
env = { DISCORD_FILE_BOT_TOKEN = "${DISCORD_FILE_BOT_TOKEN}" }For production, prefer a dedicated "File Deliverer" Discord bot with only
Send Messages, Send Messages in Threads, and Attach Files permissions.
For small personal deployments, using the same bot token is simpler but gives
the agent the same Discord permissions as the main OpenAB bot.
For repeated image requests, save the imagegen + Discord upload workflow as a
Codex skill under /home/node/.codex/skills/, for example:
/home/node/.codex/skills/discord-imagegen-deliver/
+-- SKILL.md
`-- scripts/
`-- send-discord-image.sh
The skill should instruct Codex to:
- Use the built-in
imagegenskill andimage_gentool for raster images. - Keep the generated image size as-is unless the user explicitly asks for resizing.
- Copy the selected file from
/home/node/.codex/generated_images/...to a stable path under/home/node. - Upload it to
thread_idorchannel_idusing the Discord REST API. - Avoid printing token values.
Example user prompt after creating such a skill:
Use $discord-imagegen-deliver to generate a warm hand-painted sky with birds and send it back to this Discord thread.
Codex offers three approval modes that control what happens when the agent tries to act outside the sandbox (network calls, running scripts, etc.):
| Mode | Behaviour | Best for |
|---|---|---|
Manual (approval_policy = "on-request") |
Every out-of-sandbox action waits for a human to approve | Interactive, attended sessions |
Auto-review (approval_policy = "auto-review") |
A separate reviewer agent (GPT-5.4 Thinking) approves or denies automatically | OpenAB / unattended agents |
Full Access (approval_policy = "full-access") |
No sandbox enforcement at all | Trusted, isolated environments only |
For OpenAB deployments, Auto-review is the recommended mode. OpenAB agents run as long-lived background processes with no human watching the terminal, so manual approval is impractical and Full Access removes all guardrails.
Enable Auto-review in /home/node/.codex/config.toml:
[sandbox]
approval_policy = "auto-review"Or pass it at install time via Helm:
helm install openab openab/openab \
--set agents.codex.discord.enabled=true \
# ... other flags ...
--set-json 'agents.codex.extraConfig={"sandbox":{"approval_policy":"auto-review"}}'- Approves ~99% of legitimate out-of-sandbox actions automatically.
- Blocks actions that could exfiltrate data, expose secrets, delete data, or weaken security settings.
- When it rejects an action, it gives the agent a rationale so Codex can find a safer alternative (succeeds >50% of the time without human input).
- Stops the trajectory after repeated denials to prevent gaming.
Auto-review is not a security guarantee. It can be misled by adversarial inputs and cannot detect a model that hides malicious intent within the sandbox. Treat it as a strong default, not a replacement for network-level controls and secret management.
For more details, see the OpenAI Alignment Blog post on Auto-review.
Some Kubernetes environments do not allow unprivileged user namespaces, which can
block Codex's default sandbox when running nested codex exec commands. For
manual smoke tests inside an already isolated pod, use:
codex exec --dangerously-bypass-approvals-and-sandbox ...Do not use this flag on an untrusted host.
Check whether an image was generated even if the CLI has not returned yet:
find /home/node/.codex/generated_images -type f -name '*.png' -printf '%T@ %p %s\n' | sort -n | tailIf a file exists, copy it to a stable path and upload it manually with the Discord API command above.
Verify the agent can see an upload token:
kubectl exec -it deployment/openab-codex -- \
sh -lc 'test -n "$DISCORD_FILE_BOT_TOKEN$DISCORD_BOT_TOKEN" && echo token-present || echo token-missing'Also confirm the bot has Send Messages, Send Messages in Threads, and
Attach Files permissions in the target channel or thread.