install: tables Codex Desktop appends above the trailing SessionStart closing marker make the Codex hook preflight refuse (`ambiguous_hook_ownership`)
Version: main 80eb92a7 (also v0.11.0) Platform: Linux (x64) for the reproduction; the layout is platform-independent Install channel: Built from source Binary variant: standard
What happened, and what did you expect?
Same root cause as #2228, other block. When Codex hooks live in config.toml (no ~/.codex/hooks.json), install appends the managed # >>> codebase-memory-mcp SessionStart >>> … # <<< … <<< block at the end of the file, so its closing marker is the last line. Codex Desktop treats a trailing comment as document decor and inserts new tables above it, exactly as reported in #2228 for the MCP block. Once a foreign table sits inside the hooks span, the next install runs the hooks preflight, cbm_toml_reconcile_codex_hooks_detailed no longer sees exactly its own block, and the whole Codex step stops:
error: agent_config agent=Codex CLI op=hook_preflight path=…/.codex/config.toml reason=ambiguous_hook_ownership (target: regular file, N bytes)Nothing is lost (the reconciler fails closed and the file stays byte-identical), but from then on every install and update fails for Codex until the user moves the foreign table out by hand. PR #2434 (fix for #2228) teaches the MCP block editor to leave foreign content in place; the hooks reconciler could use the same span classification: treat the first [[hooks.SessionStart]]/[[hooks.SubagentStart]] group after the opening marker as owned and keep anything behind it.
Reproduction
Sandboxed, no real Codex configuration touched:
sandbox="$(mktemp -d)"; mkdir -p "$sandbox/.codex" "$sandbox/bin" "$sandbox/cache" "$sandbox/rt"
printf 'model = "gpt-5"\n' > "$sandbox/.codex/config.toml"
env HOME="$sandbox" CODEX_HOME="$sandbox/.codex" CBM_CACHE_DIR="$sandbox/cache" CBM_RUNTIME_DIR="$sandbox/rt" \
codebase-memory-mcp install -y --dir="$sandbox/bin" --clients=codex
tail -1 "$sandbox/.codex/config.toml" # "# <<< codebase-memory-mcp SessionStart <<<" is the last line
# what Codex Desktop does when it saves a new table: insert it above the trailing comment
python3 - "$sandbox/.codex/config.toml" <<'PY'
import sys; p = sys.argv[1]; s = open(p).read(); m = "# <<< codebase-memory-mcp SessionStart <<<\n"
open(p, "w").write(s[:-len(m)] + '\n[desktop]\nfollowUpQueueMode = "steer"\n' + m)
PY
env HOME="$sandbox" CODEX_HOME="$sandbox/.codex" CBM_CACHE_DIR="$sandbox/cache" CBM_RUNTIME_DIR="$sandbox/rt" \
codebase-memory-mcp install -y --dir="$sandbox/bin" --clients=codex; echo "exit=$?"Observed on main: second install exits 1 with op=hook_preflight … reason=ambiguous_hook_ownership; the file is unchanged, [desktop] survives.
Logs
Codex CLI:
error: agent_config agent=Codex CLI op=hook_preflight path=/tmp/…/.codex/config.toml reason=ambiguous_hook_ownership (target: regular file, 1054 bytes)
error: one or more agent configurations failed; the published/current executable was kept, and PATH/index cleanup was not attemptedConfirmations
- I searched existing issues; #2228 covers the MCP block, #570/#1432/#1558 cover hook duplication and orphan markers, none cover foreign tables inside the hooks block.
- The reproduction uses a throwaway sandbox, not proprietary code.
Source: DeusData/codebase-memory-mcp