Skip to content

feat(codex): Add first-class Codex support - #79

Merged
JordanCoin merged 6 commits into
JordanCoin:mainfrom
reneleonhardt:feat/codex-first-class
Jul 27, 2026
Merged

feat(codex): Add first-class Codex support#79
JordanCoin merged 6 commits into
JordanCoin:mainfrom
reneleonhardt:feat/codex-first-class

Conversation

@reneleonhardt

@reneleonhardt reneleonhardt commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

  • Add first-class Codex project setup, hooks, MCP configuration, plugin installation, upgrades, and diagnostics without replacing Claude integration.
  • Use absolute, versioned executable paths so managed integrations do not depend on a restricted host PATH.
  • Validate Codex hook trust and distinguish CLI and Desktop runtimes independently.
  • Make setup and plugin installation idempotent while preserving unrelated user configuration.
  • Allow hooks-only setup with --no-mcp when the Codex plugin owns MCP.
  • Document the one-time plugin-first setup order and per-project upgrade refresh workflow.
  • Unify codemap mcp and codemap-mcp option parsing and server behavior.

Type of change

  • Bug fix
  • New feature
  • New language support
  • Documentation
  • Other (describe below)

Checklist

  • I've tested this locally with go build && ./codemap .
  • I've read CONTRIBUTING.md (for new language support)
  • I've updated documentation if needed

Additional notes

Codemap was Claude-first. Codex integrations could fail because of restricted host PATHs, stale project overrides, untrusted hooks, and unclear plugin upgrades. This change lets both agents operate independently or together without overwriting existing configuration.

The final MCP commit routes both executable entrypoints through the same runtime-option parser and server constructor. A black-box parity test compares option errors, tool discovery, status guidance, and file-search responses.

Formatting, modules, vet, staticcheck, focused and race tests, debug smoke,
entrypoint parity, repeated plugin/setup, and CLI-less doctor validation pass.

Reviewer setup:

set -euo pipefail

ROOT=$PWD
BRANCH=feat/codex-first-class
REVIEW_ROOT=$(mktemp -d "${TMPDIR:-/tmp}/codemap-codex-review.XXXXXX")
WT="$REVIEW_ROOT/worktree"
DEBUG_BIN="$REVIEW_ROOT/codemap-debug"
COVERAGE_OUT="$REVIEW_ROOT/coverage.out"

cleanup() {
  cd "$ROOT"
  git worktree remove --force "$WT"
  rm -rf "$REVIEW_ROOT"
}
trap cleanup EXIT

git worktree add --detach "$WT" "$BRANCH"
cd "$WT"
go fmt ./...
git diff --exit-code
go mod verify
go vet ./...
staticcheck ./...
go test . ./cmd ./mcp ./plugins ./internal/buildinfo -count=1
go test -race -coverprofile="$COVERAGE_OUT" ./...
go build -gcflags='all=-N -l' -o "$DEBUG_BIN" .
"$DEBUG_BIN" --version
"$DEBUG_BIN" .

REVIEW_HOME="$REVIEW_ROOT/home"
PROJECT="$REVIEW_ROOT/project"
NO_AGENT_PATH="$REVIEW_ROOT/no-agent-bin"
mkdir -p "$REVIEW_HOME" "$PROJECT/.git" "$NO_AGENT_PATH"
printf 'package main\n' > "$PROJECT/main.go"

HOME="$REVIEW_HOME" "$DEBUG_BIN" plugin install --home "$REVIEW_HOME" --no-activate
HOME="$REVIEW_HOME" "$DEBUG_BIN" plugin install --home "$REVIEW_HOME" --no-activate
HOME="$REVIEW_HOME" PATH="$NO_AGENT_PATH" "$DEBUG_BIN" setup --agent codex "$PROJECT"
HOME="$REVIEW_HOME" PATH="$NO_AGENT_PATH" "$DEBUG_BIN" setup --agent codex "$PROJECT"
HOME="$REVIEW_HOME" PATH="$NO_AGENT_PATH" "$DEBUG_BIN" doctor "$PROJECT"
cleanup
trap - EXIT

To test the live MCP integration, run Codex against the generated project, trust the hooks from /hooks in CLI or Settings > Hooks in Desktop, and start a new task. The generated project configuration already points to the exact debug binary.

Developed with carefully directed, manually reviewed AI assistance. Allow edits by maintainers is enabled, so maintainers are welcome to fix wording or make minor cleanup directly; broader review feedback will be incorporated.

Co-Authored-By: GPT-5.6 Sol codex@openai.com

reneleonhardt and others added 3 commits July 13, 2026 00:21
Co-Authored-By: GPT-5.6 Sol <codex@openai.com>
Co-Authored-By: GPT-5.6 Sol <codex@openai.com>
Co-Authored-By: GPT-5.6 Sol <codex@openai.com>
@reneleonhardt
reneleonhardt force-pushed the feat/codex-first-class branch from 55d847c to 14bf9eb Compare July 13, 2026 12:13
Co-Authored-By: GPT-5.6 Sol <codex@openai.com>

@JordanCoin JordanCoin left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Impressive work — this got a deep review, including hands-on verification of the risky parts. The idempotency and config-preservation claims hold up: TOML comments and unrelated tables in .codex/config.toml survive, unknown JSON keys and user hooks are preserved, a second run is a byte-identical no-op, and a codemap MCP entry codemap didn't write is refused rather than clobbered. Hook trust stays read-only (nothing auto-trusts), the process-probe code is bounded and defensive, and pelletier/go-toml/v2 is a good pinned choice. The codemap mcp/codemap-mcp parity test is a nice touch. CI is green.

Requesting changes on four points before merge:

  1. Bug: silent integer corruption in ~/.claude.json. ensureClaudeMCPWithExecutable (cmd/setup.go) round-trips the whole file through map[string]any, so integers > 2^53 get float64-mangled — reproduced locally: "bigInt": 9007199254740993 becomes 9007199254740992 after setup --global. That's Claude Code's monolithic state file. Please use json.Decoder.UseNumber() (same pattern applies to the hooks/marketplace writers), and write via temp-file + rename so a crash can't truncate the file — the whole-file rewrite is currently non-atomic and can race a running Claude Code session.

  2. Default behavior change for every user. Plain codemap setup (default --agent both) now writes .codex/hooks.json, .codex/config.toml, and — notably — a machine-specific absolute path into project .mcp.json, which is conventionally a committed, shared file. Teammates who pull that get broken entries pointing at someone else's filesystem. Suggest defaulting to detected agents (doctor already knows how to detect them) and/or warning when an absolute path is about to land in a committed file.

  3. Test coverage doesn't match the change. Roughly ~860 lines of new branching logic — RunDoctor, validateCodexHookTrust, the TOML surgery (replaceCodexMCPCommand, tomlCommentIndex), migrateOwnedHookCommand, and the session-lease code — have no unit tests. The tricky parts here (line-surgery on user config, stale-lock reclaim) are exactly where regressions will hide; they deserve coverage matching their subtlety.

  4. Consider splitting the MCP entrypoint unification (cmd/mcp.go, the mcp/main.go RuntimeOptions work, internal/buildinfo + goreleaser ldflags, mcp_entrypoints_test.go, launcher-script deletion) into its own PR — it's independently mergeable, and slicing it out would make the Codex-specific remainder much easier to re-review.

One observation for the docs rather than a change request: codemap doctor executes binaries at absolute paths recorded in project-local config (.codex/config.toml / .mcp.json), so running doctor inside an untrusted repo runs a repo-chosen path. The args-shape and absolute-path checks bound this well, but it's worth a note in the doctor docs.

(FYI: the scanner/TestFindBundledAstGrepBinaryPrefersSiblingAstGrep failure you may see in full-suite local runs is a pre-existing timeout flake unrelated to this PR.)

Happy to see this land — the direction is right and the config-handling care really shows.

JordanCoin and others added 2 commits July 27, 2026 14:39
# Conflicts:
#	cmd/codemap-mcp/main.go
#	cmd/hooks.go
#	cmd/mcp.go
#	main.go
…fault, tests

- Decode ~/.claude.json, settings.json, plugin .mcp.json, and marketplace.json
  with UseNumber so integers beyond 2^53 survive the round-trip, and write all
  of them (plus Codex TOML) via temp-file + rename so a crash can't truncate a
  file a running agent session may have open.
- Default plain `codemap setup` to detected agents instead of unconditionally
  configuring both; accept --agent both explicitly and note when .mcp.json
  gains a machine-specific absolute path.
- Tolerate legacy positional MCP arguments instead of refusing to start.
- Add tests for the TOML surgery, hook-command migration, Codex hook trust
  validation, session leases (incl. stale lock/lease reclaim), doctor, and
  agent detection.
- Document that doctor executes binaries recorded in project-local config.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@JordanCoin

Copy link
Copy Markdown
Owner

Pushed a commit addressing the outstanding review points directly on this branch (thanks for enabling maintainer edits, and for splitting out #83 — that's merged, and this branch is now merged up with main):

  1. JSON number corruption + atomicity: all user-config JSON round-trips (~/.claude.json, hook settings, plugin .mcp.json, marketplace.json) now decode with UseNumber and write via temp-file + rename; the Codex TOML writer is atomic too.
  2. Default behavior: plain codemap setup now defaults to detected agents (~/.claude/~/.codex markers or CLIs on PATH) instead of unconditionally configuring both, --agent both is accepted explicitly, and setup prints a note when .mcp.json gains a machine-specific absolute path.
  3. Test coverage: added tests for the TOML surgery (comment/table preservation + refusal shapes), migrateOwnedHookCommand, validateCodexHookTrust (via the probe seam), session leases incl. stale lock/lease reclaim, RunDoctor, and agent detection.

Also: legacy positional MCP args are tolerated again (main's entrypoint parity test requires it), and the doctor security observation is now documented in the README. Full -race suite passes locally.

@JordanCoin
JordanCoin merged commit 0914e2a into JordanCoin:main Jul 27, 2026
12 checks passed
@reneleonhardt
reneleonhardt deleted the feat/codex-first-class branch July 27, 2026 22:14
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.

3 participants