Skip to content

D58 — Real Codex CLI integration: managed-block config.toml, TOML agents, hook engine

The bug. Since D23, emitCodex wrote .codex/config.json Claude Code-style — but Codex CLI never reads that file: the only configuration it consults is ~/.codex/config.toml, section [mcp_servers.<id>]. The MCP integration with Codex never worked in practice.

Decision. Three extensions, verified against the official Codex docs: - MCP → managed-block config.toml. config.toml is hand-curated (comments, order): never parsed/reserialized as generic TOML. emitCodex generates only the body of the [mcp_servers.cartographer] block; Apply/Remove materialize it with the new generic internal/blocktext package (Write/Remove/ReplaceBetween on text markers) inside dedicated markers. Remove also cleans up any legacy pre-D58 .codex/config.json. - Agent → .codex/agents/<nome>.toml. destDir maps agent×codex to this path; translateAgentForCodex (parallel to D55) extracts description and puts the body in developer_instructions. Fields with no reliable equivalent (tools, model) omitted, same policy as D55: never guess a value. - Hook → materialization + hooks engine. destDir maps hook×codex to .codex/hooks/<nome>/; registration goes inside the managed block of config.toml as an array of TOML tables, with a per-hook marker (# cartographer:hook:<nome>:begin/end) — same ownership-per-block principle as D57, here per-marker in text instead of per-substring in JSON. Rationale. internal/blocktext factors out a problem that now recurs twice in config.toml (MCP entry + N hooks); the pre-existing version for instructions (D56, HTML markers) remains unrefactored — stable code, no reason to touch it alongside an unrelated change. Open question. The hook.json matcher is written for Claude Code (free substring); Codex interprets it as a regex — no automatic conversion planned. Details: docs/sync.md §Agents and hooks. Follow-up (July 2026). The TUI dashboard (mcpConfigStatus in cmd/cartographer/tui.go) checked for the MCP entry's presence with a single json.Unmarshal, still calibrated on the old config.json: for Codex the file is TOML, so the parse always failed and the mcp-config badge showed missing even with a correct config. Now, for providers with a FilePath ending in .toml, the check looks for the [mcp_servers.<name>] table instead of parsing JSON.