Skip to Content
DocsDeploymentDockerClaude Code & Codex

Coding agents in the container

The image installs both Claude Code and Codex, so the container has a coding agent the moment it boots. You sign each one in once, with the subscription you already pay for. There is no API key to configure anywhere.

TL;DR

Run make claude-login and make codex-login. Each prints a URL and a code: approve in your browser, paste the code back. The token lands in the git-ignored ./agents directory on the host, so it survives image rebuilds.

Sign in

make claude-login make codex-login

Both use a device-code flow, which is what makes them work in a container at all: the browser step happens on your machine, and only the resulting token comes back. Check either at any time:

make agents-status

There is deliberately no API-key setting for either agent. Metered API billing is a different and far more expensive product than the subscription these CLIs authenticate against, so the container only supports the interactive sign-in.

Where the login is stored

Both CLIs are redirected to write everything they own into one host directory:

agents/ claude/ credentials, session history, project state codex/ credentials, configuration

That directory is a bind mount, not a volume, and the split is deliberate. The executables belong to the image, so a rebuild replaces them with current versions. The credentials belong to the host, so a login outlives an image rebuild, a container recreation, and even a down --volumes reset of the relay’s own identity.

Treat agents/ as private key material. It holds live logins and the session history alongside them. It is git-ignored, and the repository’s commit hook refuses any staged path under it — but that protects the repository, not a backup, an archive, or a support bundle. Never copy it to share a setup.

Updates

Automatic self-update is switched off in the image, on purpose. The binaries live in a root-owned path that the runtime user cannot write, so an enabled updater would report a permission failure on every run and never actually update. The supported update path is an image rebuild, which resolves the current version of both CLIs:

docker compose build --no-cache docker compose up -d

Your logins are untouched by this — they are on the host, not in the image.

Codex and its sandbox

Codex runs each command it executes inside its own sandbox. On Linux that sandbox is built on an unprivileged user namespace, and a container frequently cannot create one. When that happens the failure is total rather than graceful: every command Codex tries to run fails.

CMDOP_CODEX_SANDBOX decides how to handle that, and auto tests the sandbox at startup rather than guessing from the kernel version:

ValueBehavior
auto (default)Probe the sandbox on boot. Use the restricted mode when it works, fall back when it does not, and say which it chose in the log.
workspace-writeForce the sandbox on. Codex fails if the container cannot start it.
read-onlyForce the sandbox on, with no writes.
danger-full-accessNo inner sandbox.

The fallback is a considered trade, not a shortcut: the container is already the security boundary, and the alternative — granting the container the privileges its inner sandbox needs — weakens the real boundary to restore a nested one.

Do not “fix” a sandbox failure with --privileged, seccomp=unconfined, or by adding SYS_ADMIN. Each of those weakens the boundary that is actually protecting your host, in order to reinstate one that is protecting a directory inside a container you can delete.

Leaving one out

Both are build arguments, so a build can omit either:

CMDOP_CLAUDE_CODE=0 CMDOP_CODEX=0

The image builds and runs normally without them; the Cmdop agent itself is unaffected.

Last updated on