Skip to content

feat(codex): full Codex support via --ide=codex (hooks, config.toml, AGENTS.md) - #161

Merged
George-iam merged 2 commits into
mainfrom
feat/codex-support-20261102
Nov 2, 2026
Merged

George-iam merged 2 commits into
mainfrom
feat/codex-support-20261102

Conversation

@George-iam

Copy link
Copy Markdown
Contributor

Summary

Full Codex (OpenAI) support, CLI-first, mirroring the Cursor Phase 1 shape (D-143/D-144/D-145) and recorded as D-160:

axme-code setup --ide=codex

writes three project-level files and leaves Claude Code's untouched:

  • .codex/config.toml — [mcp_servers.axme] with an absolute, PATH-independent node <cli> serve command (Codex launched from the IDE extension or desktop app does not necessarily see the login-shell PATH).
  • .codex/hooks.json — SessionStart, PreToolUse, PostToolUse (matcher apply_patch|Edit|Write), SessionEnd (timeout 3s, Codex's hard cap; measured 0.12s).
  • AGENTS.md — the ## AXME Code section (CLAUDE.md analogue) plus the #!axme git gate rule. The writer refreshes only our section and keeps user content after it.

What changed

  • src/hooks/adapters/codex.ts — Codex's hook protocol is Claude-Code-compatible (PascalCase events, same hooks.json shape, same hookSpecificOutput.permissionDecision deny envelope), so the output adapter is the Claude Code one re-exported. The input adapter normalizes apply_patch (patch text in tool_input.command, several files per call) to Edit and lists every touched path in a new NormalizedHookEvent.filePaths, resolved against the payload cwd.
  • pre-tool-use / post-tool-use / session-end — select the codex adapter; the Edit/Write branches iterate filePaths (Claude Code / Cursor keep the single file_path path).
  • src/hooks/session-start.ts + hook session-start — prints [AXME Code] Knowledge base ready. Call axme_context now.; Codex injects SessionStart stdout as developer context.
  • checkBash shell-side denied paths — Codex has no Read tool, every read is a shell command, so the filesystem deny rules did not apply there at all. checkBash now runs anchored deny patterns (/..., ~/...) against path-like shell tokens (quote-aware tokenizer, so cat "~/.ssh/id_rsa" is caught). Bare basename patterns (.env, *.pem) are deliberately excluded: matched against free text they would block commit messages and heredocs that merely mention a file. This also closes the same gap for Bash on Claude Code and Cursor.
  • IdeKind gains "codex"; --ide=codex is accepted by setup and the hook dispatcher; no stdin heuristic for Codex on purpose (its payload is Claude-shaped), the writers always pass --ide codex explicitly.
  • Docs: docs/MULTI_CLIENT.md Codex section + matrix, README matrix, CHANGELOG.

Tests

  • npx tsc --noEmit clean, npm run build clean.
  • npm test: 650 tests, 649 pass, 1 fail — audit-dedup.test.ts › ensureAxmeSessionForClaude - parallel processes (E2E), a timing test that failed under full-suite load and passes in isolation (11/11). Unrelated to this change.
  • New: test/codex-hook-adapter.test.ts, test/codex-setup-writers.test.ts, test/codex-hooks-e2e.test.ts (spawns the real CLI with Codex payloads: force-push deny, shell denied-path deny, apply_patch allowed and tracked into the AXME session, MCP tool call allowed, session-start output), additions to ide-detect and safety-bash tests.
  • Live check on this machine with codex-cli 0.166.0: setup --ide=codex on this repo, codex mcp list shows axme from the trusted project config, session-start / pre-tool-use gate / session-end verified against the built dist/cli.mjs.

Notes for review

  • Branched from the default branch per D-047 while feat(kb): hygiene release v0.6.4 — slug data loss, audit-kb silent failure, format contract #159 (v0.6.4 hygiene) is still open; expect a small textual conflict in src/cli.ts (template constants) whichever merges second.
  • Size is over the D-050 soft limit (1045 insertions); roughly half is tests. The adapter, writers and CLI wiring are interdependent for anything to work, so it is one PR rather than a stacked train.
  • Deferred on purpose, see D-160: a Codex rollout-transcript parser for the auditor, a codex exec auditor backend (for users without Claude auth), and a Codex plugin (hooks-bearing plugins are not accepted in the public Codex directory anyway).
  • Codex loads a project's .codex/ layer only for trusted projects; setup prints the reminder.

🤖 Generated with Claude Code

George-iam and others added 2 commits November 2, 2026 08:09
…AGENTS.md)

- codex hook adapter: Codex's hook protocol is Claude-Code-compatible, so the
  output adapter is re-exported; the input adapter normalizes apply_patch
  (patch text in tool_input.command, several files per call) to Edit with
  every touched path in NormalizedHookEvent.filePaths; MCP tool calls fall
  through the safety switch untouched
- setup --ide=codex writes .codex/config.toml ([mcp_servers.axme] with an
  absolute, PATH-independent command), .codex/hooks.json (SessionStart +
  PreToolUse + PostToolUse + SessionEnd; SessionEnd timeout 3s, Codex's cap)
  and the "## AXME Code" section in AGENTS.md (refreshes only our section)
- new `hook session-start`: prints the axme_context nudge, which Codex
  injects as developer context
- checkBash: shell-side enforcement of anchored denied paths ("/...", "~/...")
  since Codex has no Read tool; basename patterns (.env, *.pem) excluded to
  keep commit messages and heredocs that mention them unblocked
- pre/post-tool-use iterate filePaths for multi-file edits
- tests: adapter unit tests, writer tests, hooks e2e (spawned CLI with Codex
  payloads: force-push deny, shell denied-path deny, apply_patch tracking,
  session-start), ide-detect + safety additions; docs + changelog

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…heck, platform-independent test paths

checkShellPaths compared homedir()-expanded tokens (backslashes on Windows)
against deny patterns written with '/', so 'cat ~/.ssh/id_rsa' was never
blocked there. Both sides now go through expandHome + normalizePathForSafety
and matchesPattern directly. Tests: expected paths built with path.resolve,
no RegExp from a temp dir path, filesChanged compared separator-agnostic.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@George-iam
George-iam merged commit 27a7144 into main Nov 2, 2026
12 checks passed
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.

1 participant