Repository navigation
Description
Version
codebase-memory-mcp 0.9.0- Independently reproduced with
codebase-memory-mcp 0.9.1-rc.1
Platform
macOS (Apple Silicon)
Install channel
GitHub release archive / install.sh (installed to ~/.local/bin)
Binary variant
standard
What happened, and what did you expect?
codebase-memory-mcp install recognizes its managed Codex SessionStart hook by the # >>> codebase-memory-mcp SessionStart >>> marker comments. If a previously installed hook is present in ~/.codex/config.toml in a semantically equivalent inline form without those markers—for example after a settings migration or another normalization step that removes comments—the installer appends another [[hooks.SessionStart]] table.
The inline assignment already defines hooks.SessionStart, so the appended array-of-tables definition makes the TOML invalid. Codex then fails to load the entire configuration instead of starting or resuming a thread.
Expected: install/update must keep config.toml parseable and remain idempotent even when formatting or comments have changed.
Reproduction
The reproduction is sandboxed: both HOME and CODEX_HOME point to a temporary directory, so the real Codex configuration is not modified.
sandbox="$(mktemp -d)"
mkdir -p "$sandbox/.codex"
cat > "$sandbox/.codex/config.toml" <<'EOF'
[hooks]
SessionStart = [{ matcher = "startup|resume|clear|compact", hooks = [{ type = "command", command = "echo \"Code discovery: prefer codebase-memory-mcp\"" }] }]
[mcp_servers.codebase-memory-mcp]
command = "/Users/me/.local/bin/codebase-memory-mcp"
EOF
# Control: the inline-only configuration is valid and Codex can load it.
CODEX_HOME="$sandbox/.codex" codex features list >/dev/null
# Reinstall into the sandbox.
HOME="$sandbox" codebase-memory-mcp install -y
# Fails after install because hooks.SessionStart is now defined twice.
CODEX_HOME="$sandbox/.codex" codex features listActual result: install -y exits successfully, but appends its marked [[hooks.SessionStart]] block after the existing inline hook. The subsequent Codex command fails with duplicate key.
Control case: if config.toml contains the installer's marked block and the markers remain intact, a second install replaces/skips that block correctly and the file stays valid. The current idempotency therefore depends on the marker comments surviving.
Logs
Error from the original configuration:
ChatGPT can't load config.toml, so this thread can't resume.
Fix ~/.codex/config.toml:843:9: duplicate key.
Error from the sandboxed reproduction:
Error: <sandbox>/.codex/config.toml:10:9: duplicate key
Caused by:
TOML parse error at line 10, column 9
|
10 | [[hooks.SessionStart]]
| ^^^^^^^^^^^^
duplicate key
How users hit this in practice
codebase-memory-mcp installadds the managed hook with marker comments.- A configuration migration or normalization leaves the equivalent hook in inline
SessionStart = [...]form but does not preserve the comments. - A later
codebase-memory-mcp installorupdatedoes not recognize the inline hook and appends another definition. - Codex can no longer parse
config.tomluntil the duplicate is repaired manually.
The exact component that performed the original normalization was not isolated; the bug does not depend on it, because the sandboxed inline fixture reproduces the installer failure directly.
Expected behavior
The installer should structurally reconcile its owned Codex lifecycle hooks across supported TOML representations. After install/update:
config.tomlremains parseable;- exactly one owned
SessionStarthook is present; - unrelated user hooks are preserved;
- a repeated install is idempotent even if comments or formatting changed.
If ownership cannot be determined safely, the installer should fail without modifying the file and report an actionable error instead of writing invalid TOML.
Workaround
For 0.9.0, remove the newly appended marked block and keep the existing equivalent inline hook, then validate the file before restarting Codex. When updating the binary while retaining an already working configuration, the GitHub installer can be run with --skip-config to avoid rewriting Codex configuration.
Related issues
- Follow-up to feat: add Codex SessionStart reminder hook for codebase-memory tool discovery #330: its acceptance criteria require preserving existing user hooks and idempotent install/update behavior.
- Related to, but distinct from Installer adds hooks to both hooks.json and config.toml #570: Installer adds hooks to both hooks.json and config.toml #570 concerns hooks loaded from both
hooks.jsonandconfig.toml; this issue creates conflicting definitions inside oneconfig.tomland prevents the config from loading at all.
Confirmations
- I searched existing issues and this is not a duplicate.
- My reproduction uses shareable synthetic configuration, not proprietary code or logs.
Activity
DeusData commentedon Aug 13, 2026
Fixed on main by @astandrik's #1443 (merge
6b2650c0) — shipping in the next release.A reinstall no longer appends a duplicate
[[hooks.SessionStart]]block: an owned inline hook assignment is now reconciled into the canonical marked block instead of being ignored and re-added alongside. Foreign hook entries are preserved untouched, and genuinely ambiguous TOML is refused without modifying the file at all.feat(cli): give Codex shell searches graph context through a PreToolU…
feat(cli): give Codex shell searches graph context through a PreToolU…