Codex
Codex is code-verified, unit-tested (test_codex_hooks.py), and live-validated
on the capture side: real Codex sessions have been serialized into checkpoints
since 2026-08-06 — the maintainer's serialize log records both codex-session-end
and throttled codex-stop captures from rollout transcripts, and checkpoints
whose session id is the rollout file are on record. The transcript parser tracks
Codex's rollout format as it drifts (0.147.0's item_completed events are
handled since daimon 0.27.0). Scope honestly stated: validation is one
maintainer machine deep, not a fleet.
Install
Adds Daimon's capture -> inject loop to Codex from the released package (no repo clone needed):
daimon hooks install codex
This copies the five hook scripts and the modules they share to
~/.codex/hooks/ and registers SessionStart, SessionEnd, Stop,
PreToolUse and UserPromptSubmit in ~/.codex/hooks.json, preserving any
unrelated entries already there. It is idempotent, re-run it after every
uv tool upgrade daimon-briefing to refresh the scripts to match the installed
CLI. After installing, open /hooks in Codex to review and trust the hook
definitions — Codex skips untrusted hook definitions until you do.
A stale installed copy keeps working on old behavior, so drift is invisible.
Run daimon hooks status to audit the installed copies against the packaged
versions (CURRENT/STALE/MISSING, plus the hooks.json registration state); the
audit covers the MCP wrapper (below) too, not just the five hook scripts. It
exits non-zero when anything drifted, and daimon hooks install codex refreshes
it in place.
Requires the daimon CLI on PATH (the deprecated daimon-briefing alias
also works as a fallback):
uv tool install 'daimon-briefing[pretty]'
Manual install (from a clone)
Working from a source checkout, the standalone lifecycle manager offers the same
integration plus uninstall and status:
python3 hook/codex-hooks.py install [--dry-run]
python3 hook/codex-hooks.py uninstall [--dry-run]
python3 hook/codex-hooks.py status
What each script does
-
daimon-codex-session-start.py—SessionStarthook. Reads the latest project checkpoint and returns CodexadditionalContextJSON, so the briefing is injected as developer context. -
daimon-codex-user-prompt-submit.py:UserPromptSubmithook, measured live on Codex CLI 0.153.1: it fires once per user prompt and its plain stdout reaches the model, noadditionalContextenvelope needed. Codex already gets its briefing fromSessionStartabove, so this hook carries recall injection only: the proactive "you worked on this before" pointer, shelled out todaimon recall-injectexactly as the Claude Code and Kimi prompt hooks do, plus opt-in live request delivery (#756). -
daimon-codex-session-end.py—SessionEndhook. Serializes the finished session in the background when Codex ends it gracefully. -
daimon-codex-stop.py—Stophook. Codex exposesStopat turn scope.SessionEndcovers the graceful end of a session, so this hook serializes opportunistically and is throttled byDAIMON_CODEX_MIN_SERIALIZE_INTERVAL(default300seconds per session). Set it to0to serialize every turn, or setDAIMON_CODEX_SERIALIZE_ON_STOP=0to disable Codex capture while leaving briefing injection installed. -
daimon-codex-pre-action.py—PreToolUsehook, matcherBash|shell. This is the first daimon hook that can fail a host action. Before a shell command runs, it runs this project's armed checks against it and returns Codex's structured deny when a check ratified with intentenforcereports a violation or daimon could not read what the command sends. Codex documents no channel for a warning, so intentwarndegrades torecord-onlyhere: the run is logged and nothing is shown. Exits 0 on every path. See Checks at runtime.Every run appends one row to
~/.daimon/logs/checks.jsonl. A row proves the check RAN. Onlydecision_emitted: denyunderenforcecloses the gap between a check that ran and a check that was honored. The file is capped at 256 KiB, the last 64 KiB kept, so the counts daimon reports from it cover a window and every surface that prints them says where that window starts.DAIMON_DISABLE=1in the host's environment turns every daimon hook off, this one included, and is the way out of anenforcecheck whose pattern matches more than you meant: the command that retires the ruling is itself a shell action the check would otherwise deny.The budget is shared across the whole action, not given to each check, so on a crowded manifest a later check can find the time already spent and report
unresolved, which denies underenforceand warns underwarn. Keep a project's armed checks few and their bodies fast.
Codex docs note that transcript_path is provided for convenience but its
format is not a stable interface. Daimon's JSONL parser is intentionally
best-effort and ignores unknown rows rather than treating raw JSON as
transcript text.
MCP
daimon hooks install codex also registers the read-only
MCP server in ~/.codex/config.toml's
[mcp_servers.daimon], alongside the hook registration above. That table
points at a copied wrapper script under ~/.codex/hooks/, audited by
daimon hooks status the same way as the five hook scripts. daimon hooks remove codex takes the table back and deletes that wrapper with it, leaving
the hook scripts and their hooks.json registration untouched. Once the
table exists, the recall hint (the per-prompt "you worked on this before"
pointer, emitted by daimon-codex-user-prompt-submit.py above) names the
daimon_recall tool instead of the daimon recall "..." shell command.
Teach the agent the protocol
daimon skill install codex # managed block in ~/.codex/AGENTS.md
On the shared AGENTS.md file, daimon only ever touches its own marker
block — daimon skill uninstall codex removes exactly that block. Re-run
install after upgrading daimon to refresh the content.
Verify
daimon status
daimon status reports capture health honestly, including failures, skips,
and crashes.