Version
- Installed by
install.sh: codebase-memory-mcp 0.11.0 (upgrading from 0.10.4)
- Codex CLI 0.154.0 / Codex Desktop present on the same machine
Platform
macOS 15 (Darwin 24.6.0), Intel (darwin-amd64)
Install channel
GitHub release archive via install.sh (bash ~/.local/bin/install.sh, installs to ~/.local/bin)
Binary variant
standard
What happened, and what did you expect?
codebase-memory-mcp install (run by install.sh during the 0.10.4 → 0.11.0 upgrade) rewrote the managed # >>> codebase-memory-mcp MCP >>> … # <<< codebase-memory-mcp MCP <<< region of ~/.codex/config.toml and deleted every table that other software had placed between those two markers: [mcp_servers.node_repl] (+ its .env table), [desktop], and all four [marketplaces.*] tables. ~/.codex/config.toml went from 5,841 bytes to 4,371 bytes. Codex Desktop lost its marketplaces, desktop settings and its bundled node_repl MCP server. Nothing was printed for Codex; the install summary reported mcp: ~/.codex/config.toml as if it had succeeded.
How the foreign tables got inside the managed region: the 0.10.4 install had appended its block at the end of the file, so the closing marker was the last line. Codex Desktop later appended its own tables, and the trailing comment line stayed last (apparently its TOML editor treats a trailing comment as attached to the document end — I did not verify that in Codex itself), which left the closing marker below Codex's tables. From that point on, the region between the markers contained one cbm-owned table and four foreign ones.
Expected: the installer should never remove a table it did not write. cbm_toml_upsert_managed_block should fail closed (as toml_find_markers already does for orphan markers, #1558) when the span between its markers contains any table header other than [mcp_servers.codebase-memory-mcp] — or, better, replace only the owned table and keep the rest of the span verbatim. The user-added key inside the owned table (startup_timeout_sec = 90, needed because the MCP server takes >10 s to start on a 1.5 GB index) was also dropped; preserving unknown keys, or at least printing a note, would be kinder.
Reproduction
The real-world trigger was simply bash ~/.local/bin/install.sh on a machine whose ~/.codex/config.toml had foreign tables between the cbm markers (state shown in the diff below).
Sandboxed steps that should reproduce it without touching a real Codex configuration (HOME, CODEX_HOME, TMPDIR and the cbm cache/runtime dirs all point at a temp directory). Caveat: I could not execute this on the affected machine — with a live cbm daemon running, install stops with activation could not reserve exclusive access; no activation was committed, because the version-cohort locks live in /private/tmp/cbm-daemon-<uid>/ and are account-wide rather than under CBM_CACHE_DIR/CBM_RUNTIME_DIR. It should run on a machine (or CI job) with no daemon. The evidence for the bug is the real diff and the code path, both below.
sandbox="$(mktemp -d)"
mkdir -p "$sandbox/.codex" "$sandbox/bin" "$sandbox/cache" "$sandbox/runtime" "$sandbox/tmp"
cat > "$sandbox/.codex/config.toml" <<'EOF'
model = "gpt-5"
[mcp_servers.codegraph]
command = "codegraph"
args = ["serve", "--mcp"]
# >>> codebase-memory-mcp MCP >>>
[mcp_servers.codebase-memory-mcp]
command = "/tmp/old/codebase-memory-mcp"
args = []
startup_timeout_sec = 90
[mcp_servers.node_repl]
args = []
command = "/Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl"
startup_timeout_sec = 120
[desktop]
followUpQueueMode = "steer"
[marketplaces.openai-codex]
source_type = "git"
source = "https://github.com/openai/codex-plugin-cc.git"
# <<< codebase-memory-mcp MCP <<<
EOF
cp "$sandbox/.codex/config.toml" "$sandbox/before.toml"
HOME="$sandbox" CODEX_HOME="$sandbox/.codex" XDG_CONFIG_HOME="$sandbox/.config" TMPDIR="$sandbox/tmp" \
CBM_CACHE_DIR="$sandbox/cache" CBM_RUNTIME_DIR="$sandbox/runtime" \
codebase-memory-mcp install -y --dir="$sandbox/bin" --clients=codex
diff "$sandbox/before.toml" "$sandbox/.codex/config.toml"
Expected result (matches what happened for real): [mcp_servers.node_repl], [desktop] and [marketplaces.openai-codex] are gone; only the regenerated [mcp_servers.codebase-memory-mcp] table remains between the markers.
Logs
Diff of the real file, before → after the upgrade (values in node_repl.env elided, $HOME written as ~). Lines 133–178 were replaced by the single env_vars line:
133,178c139
< startup_timeout_sec = 90
<
< [mcp_servers.node_repl]
< args = []
< command = "/Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl"
< startup_timeout_sec = 120
<
< [mcp_servers.node_repl.env]
< NODE_REPL_NATIVE_PIPE_CONNECT_TIMEOUT_MS = "…"
< … (12 more env keys)
<
< [desktop]
< followUpQueueMode = "steer"
< external-agent-import-sync-item-types = "all"
< external-agent-import-sync-enabled = true
< conversationDetailMode = "STEPS_PROSE"
< sansFontSize = 14
< codeFontSize = 13
< ambient-suggestions-enabled = true
<
< [marketplaces.openai-bundled]
< source_type = "local"
< source = "~/.codex/.tmp/bundled-marketplaces/openai-bundled"
<
< [marketplaces.openai-primary-runtime]
< source_type = "local"
< source = "~/.cache/codex-runtimes/codex-primary-runtime/plugins/openai-primary-runtime"
<
< [marketplaces.claude-plugins-official]
< source_type = "git"
< source = "https://github.com/anthropics/claude-plugins-official.git"
<
< [marketplaces.openai-codex]
< source_type = "git"
< source = "https://github.com/openai/codex-plugin-cc.git"
---
> env_vars = ["CBM_CACHE_DIR", "CBM_RUNTIME_DIR"]
Installer output for the Codex section (no warning about the removed tables):
Codex CLI:
mcp: ~/.codex/config.toml
instructions: ~/.codex/AGENTS.md (managed activation pointer)
...
hooks: SessionStart + SubagentStart (dynamic graph context)
Where it happens: src/cli/config_toml_edit.c, cbm_toml_upsert_managed_block() copies existing[0 .. begin_line.start), appends the fresh managed block, then copies existing[end_line.full_end ..). Everything between the two marker lines is discarded, and toml_managed_block_conflicts() only inspects the text outside that span, so foreign tables inside it are neither detected nor preserved.
Project scale (if relevant)
Not index related. (For context: the machine's main index is 567 k nodes / 707 k edges, 1.5 GB.)
Related observations from the same upgrade (not the main report)
~/.codex/hooks.json: the two hook-augment entries had been edited locally to prefix CBM_HOOK_DEADLINE_MS=20000 (see next bullet). The installer treated them as foreign, preserved them, and appended its own canonical SessionStart and SubagentStart groups, so Codex ended up with each hook twice. Matching on the binary path + hook-augment token, rather than the exact command string, would avoid the duplicate.
- Feature ask:
hook-augment has a built-in 2000 ms deadline (only overridable via the CBM_HOOK_DEADLINE_MS env var). On this 1.5 GB index a hook query takes 4–6 s even with a warm daemon, so every hook silently exited empty (127 deadline_exceeded lines in logs/hook-augment-timeouts.log) until the shims were hand-edited — which then makes them "not ours" for the installer. A config set hook_deadline_ms setting honoured by the managed shims would avoid the whole conflict.
Confirmations
Version
install.sh:codebase-memory-mcp 0.11.0(upgrading from0.10.4)Platform
macOS 15 (Darwin 24.6.0), Intel (
darwin-amd64)Install channel
GitHub release archive via
install.sh(bash ~/.local/bin/install.sh, installs to~/.local/bin)Binary variant
standard
What happened, and what did you expect?
codebase-memory-mcp install(run byinstall.shduring the 0.10.4 → 0.11.0 upgrade) rewrote the managed# >>> codebase-memory-mcp MCP >>>…# <<< codebase-memory-mcp MCP <<<region of~/.codex/config.tomland deleted every table that other software had placed between those two markers:[mcp_servers.node_repl](+ its.envtable),[desktop], and all four[marketplaces.*]tables.~/.codex/config.tomlwent from 5,841 bytes to 4,371 bytes. Codex Desktop lost its marketplaces, desktop settings and its bundlednode_replMCP server. Nothing was printed for Codex; the install summary reportedmcp: ~/.codex/config.tomlas if it had succeeded.How the foreign tables got inside the managed region: the 0.10.4 install had appended its block at the end of the file, so the closing marker was the last line. Codex Desktop later appended its own tables, and the trailing comment line stayed last (apparently its TOML editor treats a trailing comment as attached to the document end — I did not verify that in Codex itself), which left the closing marker below Codex's tables. From that point on, the region between the markers contained one cbm-owned table and four foreign ones.
Expected: the installer should never remove a table it did not write.
cbm_toml_upsert_managed_blockshould fail closed (astoml_find_markersalready does for orphan markers, #1558) when the span between its markers contains any table header other than[mcp_servers.codebase-memory-mcp]— or, better, replace only the owned table and keep the rest of the span verbatim. The user-added key inside the owned table (startup_timeout_sec = 90, needed because the MCP server takes >10 s to start on a 1.5 GB index) was also dropped; preserving unknown keys, or at least printing a note, would be kinder.Reproduction
The real-world trigger was simply
bash ~/.local/bin/install.shon a machine whose~/.codex/config.tomlhad foreign tables between the cbm markers (state shown in the diff below).Sandboxed steps that should reproduce it without touching a real Codex configuration (
HOME,CODEX_HOME,TMPDIRand the cbm cache/runtime dirs all point at a temp directory). Caveat: I could not execute this on the affected machine — with a live cbm daemon running,installstops withactivation could not reserve exclusive access; no activation was committed, because the version-cohort locks live in/private/tmp/cbm-daemon-<uid>/and are account-wide rather than underCBM_CACHE_DIR/CBM_RUNTIME_DIR. It should run on a machine (or CI job) with no daemon. The evidence for the bug is the real diff and the code path, both below.Expected result (matches what happened for real):
[mcp_servers.node_repl],[desktop]and[marketplaces.openai-codex]are gone; only the regenerated[mcp_servers.codebase-memory-mcp]table remains between the markers.Logs
Diff of the real file, before → after the upgrade (values in
node_repl.envelided,$HOMEwritten as~). Lines 133–178 were replaced by the singleenv_varsline:Installer output for the Codex section (no warning about the removed tables):
Where it happens:
src/cli/config_toml_edit.c,cbm_toml_upsert_managed_block()copiesexisting[0 .. begin_line.start), appends the fresh managed block, then copiesexisting[end_line.full_end ..). Everything between the two marker lines is discarded, andtoml_managed_block_conflicts()only inspects the text outside that span, so foreign tables inside it are neither detected nor preserved.Project scale (if relevant)
Not index related. (For context: the machine's main index is 567 k nodes / 707 k edges, 1.5 GB.)
Related observations from the same upgrade (not the main report)
~/.codex/hooks.json: the twohook-augmententries had been edited locally to prefixCBM_HOOK_DEADLINE_MS=20000(see next bullet). The installer treated them as foreign, preserved them, and appended its own canonicalSessionStartandSubagentStartgroups, so Codex ended up with each hook twice. Matching on the binary path +hook-augmenttoken, rather than the exact command string, would avoid the duplicate.hook-augmenthas a built-in 2000 ms deadline (only overridable via theCBM_HOOK_DEADLINE_MSenv var). On this 1.5 GB index a hook query takes 4–6 s even with a warm daemon, so every hook silently exited empty (127deadline_exceededlines inlogs/hook-augment-timeouts.log) until the shims were hand-edited — which then makes them "not ours" for the installer. Aconfig set hook_deadline_mssetting honoured by the managed shims would avoid the whole conflict.Confirmations