Skip to content

feat(profiles): carry codex_config through to the Codex runtime config.toml - #145

Merged
NagyVikt merged 1 commit into
mainfrom
feat/codex-config-passthrough
Aug 11, 2026
Merged

feat(profiles): carry codex_config through to the Codex runtime config.toml#145
NagyVikt merged 1 commit into
mainfrom
feat/codex-config-passthrough

Conversation

@NagyVikt

Copy link
Copy Markdown
Contributor

Closes #144.

Problem

cue launch codex repoints CODEX_HOME at the materialized runtime, and that config.toml was rendered from MCP servers only:

await writeFile(join(tmpDir, "config.toml"), tomlRender({ mcp_servers: mcpServers }));

Everything else a user had in ~/.codex/config.toml was dropped, with no warning and no profile field to carry it. sandbox_mode, sandbox_workspace_write, approval_policy, shell_environment_policy were all unreachable under cue.

It fails silently — codex starts fine, the setting just has no effect.

Repro that found it

Driving ego-browser from codex. It launches Chromium against a persistent profile outside the workspace, so it needs those roots writable:

$ codex sandbox bash -lc 'ego-browser nodejs <<EOF ... EOF'
Error: EROFS: read-only file system, unlink '~/.local/share/ego-lite-linux/profile/SingletonLock'

Identical values passed as -c overrides instead of via config: H1=Example Domain.

Change

Optional codex_config map in profile.yaml, merged into the rendered config.toml beside mcp_servers. Verbatim TOML, ignored for non-Codex agents.

codex_config:
  sandbox_mode: "workspace-write"
  sandbox_workspace_write:
    writable_roots: ["/home/me/.local/share/ego-lite-linux"]
    network_access: true

Two decisions worth review:

Ordering. Bare keys emit before any [table] header. TOML binds every key after a header to that table, so sandbox_mode written after [mcp_servers.foo] would silently become mcp_servers.foo.sandbox_mode. Directly asserted in a test.

Merge depth — two levels, not one. env is flat strings so shallow is right; this is tables, and selectors here run 10+ profiles wide. A shallow merge would let a profile setting only sandbox_workspace_write.network_access delete a sibling's writable_roots — the same silent-drop class of bug this PR exists to fix. Deeper than two levels replaces wholesale, to keep the rule stateable.

Test plan

  • 5 tests added — key ordering, real Bun.TOML.parse round-trip (not substring matching), empty-config shape, two-level composite merge, leaf collision
  • tsc --noEmit clean
  • biome lint clean on both changed source files
  • Full suite: 34 failing on origin/main, 34 failing here, failing set byte-identical (diff of sorted names is empty). Suite is red at baseline; this adds none. Pass count +5, exactly the new tests.
  • Not covered: no end-to-end check that Codex itself honors a key emitted this way — values are passed through unvalidated, so a typo surfaces as Codex ignoring it. Documented in SCHEMA.md.

Docs

profiles/SCHEMA.md — field row, a worked YAML→TOML example, the ordering rationale, and the merge-depth rule in the inheritance section.

…g.toml

cue launch codex repoints CODEX_HOME at the materialized runtime, whose
config.toml was rendered from MCP servers only. Every other key a user
had in ~/.codex/config.toml was dropped, with no warning and no profile
field to carry it -- so sandbox_mode, sandbox_workspace_write,
approval_policy and shell_environment_policy were unreachable under cue.

Found while driving ego-browser from codex: it needs a writable Chromium
profile dir outside the workspace. Setting sandbox_workspace_write in
~/.codex/config.toml did nothing; the same values as -c overrides worked.
The failure is silent -- codex starts fine and the setting has no effect.

Adds an optional codex_config map to profile.yaml, merged into the
rendered config.toml next to mcp_servers. Emitted verbatim as TOML,
ignored for non-Codex agents.

Two details worth flagging:

- Ordering. Bare keys are emitted before any [table] header. TOML binds
  every key after a header to that table, so sandbox_mode written after
  [mcp_servers.foo] would silently become mcp_servers.foo.sandbox_mode.

- Merge depth. Two levels, not one. Unlike env's flat strings this is
  tables, and selectors here run 10+ profiles wide; a shallow merge
  would let a profile setting only sandbox_workspace_write.network_access
  delete a sibling's writable_roots. That is the same silent-drop class
  of bug this change exists to fix.

Refs #144

Tests: 5 added (ordering, real TOML parse, empty-config shape, two-level
composite merge, leaf collision). Full suite failing set is byte-identical
to origin/main (34 pre-existing failures on both, zero new).
@NagyVikt
NagyVikt merged commit 8555f06 into main Aug 11, 2026
5 of 7 checks passed
@NagyVikt
NagyVikt deleted the feat/codex-config-passthrough branch August 11, 2026 23:13
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.

codex runtime config.toml carries MCP servers only — sandbox/approval keys from ~/.codex are silently dropped

1 participant