Skip to content

Add Codex CLI container harness - #47

Open
CrypticSwarm wants to merge 3 commits into
masterfrom
codex-cli-harness
Open

Add Codex CLI container harness#47
CrypticSwarm wants to merge 3 commits into
masterfrom
codex-cli-harness

Conversation

@CrypticSwarm

@CrypticSwarm CrypticSwarm commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Adds containerized support for OpenAI's Codex CLI as a fourth harness, following the Claude and Grok pattern: a persistent credentialed home, the harness's native skills location, and the stable repo-slug mount path.

make build_codex then make run_codex PROJECT_DIR=$(pwd).

Two places Codex does not fit the existing shape

The release is not a single file. bin/codex resolves ripgrep, bwrap, and a bundled zsh beside itself, so the image cannot relocate one binary the way the other three arms do. The package stays whole under /opt/codex and the installer's own symlink is what lands at /usr/local/bin/codex. CODEX_HOME is set for the build only, so the runtime config dir is still ~/.codex.

Its skills location is the harness-neutral one. Codex reads ~/.agents/skills, the same convention the portable overlay layers are already written in, so that is the dir masked with tmpfs. It has no user-defined slash commands — skills replaced ~/.codex/prompts — so copy_shared_assets leaves the commands destination empty and copy_dir_entries now treats an empty destination as nothing to do.

MCP tongs

Codex reads servers in the same shape Grok does — TOML [mcp_servers.<name>] tables where a url key selects the remote transport — and merges into a persistent home the same way. Rather than add a second copy of each, swarmforge.config.merge_grok_mcp becomes merge_toml_mcp and tongs.mcp_config_grok becomes mcp_config_toml, with both harnesses pointed at them. Neither had anything Grok-specific beyond the name.

Config layering

Same three sources and order of trust as Claude, merging into ~/.codex with reset disabled. The merge skips packages/ — the host installer's release tree, which the container has no use for — along with sessions/, history.jsonl, and log/, so one machine's transcripts do not follow the user config layer into the container's home.

Codex's own sandbox is left enabled, as Claude's approvals are; CODEX_ARGS and a sandbox_mode config layer are the two ways to relax it.

Add containerized support for OpenAI's Codex CLI, following the Claude and
Grok pattern: a persistent credentialed home, the harness's native skills
dir, and the stable repo-slug mount path.

Codex is the first harness whose release is not a single file. bin/codex
resolves ripgrep, bwrap, and a bundled zsh beside itself, so the image
cannot relocate one binary the way the other three arms do -- the package
stays whole under /opt/codex and the installer's own symlink is what lands
at /usr/local/bin/codex. CODEX_HOME is set only for the build, so the
runtime config dir is still ~/.codex.

It is also the first harness whose skills location is the harness-neutral
one: Codex reads ~/.agents/skills, the same convention the portable overlay
layers are already written in. Only that dir is masked with tmpfs, because
Codex has no user-defined slash commands -- skills are its one extension
point -- so copy_shared_assets leaves the commands destination empty and
copy_dir_entries now treats an empty destination as nothing to do.

- Makefile: build_codex/update_codex/run_codex/stop_codex and the matching
  image/home/args vars; config dest ~/.codex with reset disabled so
  credentials persist across runs.
- entrypoint: exclude the host installer's packages/ tree from the layered
  merge, along with the sessions, history, and log a persistent home would
  otherwise keep from another machine.
A session with an mcp-interface tong refused to launch under run_codex
because no MCP config emitter existed for the harness. Codex reads servers
in the same shape Grok does -- TOML [mcp_servers.<name>] tables where a url
key selects the remote transport -- and merges into a persistent home the
same way, so the two harnesses now share one emitter and one renderer
instead of gaining a second copy of each.

Rename swarmforge.config.merge_grok_mcp to merge_toml_mcp and
tongs.mcp_config_grok to mcp_config_toml, and point both harnesses at them
from MCP_EMITTERS and the entrypoint's per-harness dispatch. Neither had
anything Grok-specific in it beyond the name: the managed-block behaviour
(rewritten every run, stripped when a session has no MCP tongs, yielding to
a same-named server the user defines) is what any harness merging generated
servers into a persistent config.toml needs.
Add a Codex CLI section to the README: the package-shaped install, the
persistent ~/.codex home, AGENTS.md discovery, skills delivery through the
.agents convention, MCP tongs, and config layering.

Codex's own sandbox is the one thing a reader has to act on rather than
just know about. It is redundant inside an anvil and may not initialize in
one at all, so the section names both ways to relax it.

A fourth harness also makes the two-harness prose above wrong in two more
places. Point the org-config root and the repo config layer at every
harness instead of enumerating a pair.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant