Codex Hooks Integration¶
What this integration does¶
StatePlane can use Codex hooks as a local event source for shell-driven coding work.
The integration records:
- user prompts
- Bash commands before execution
- Bash command results after execution
- pytest failures when the output is parseable
- changed files discovered at
Stop - replay, diff, and artifact receipts for the Codex turn
It then injects compact StatePlane context back into Codex so the next turn starts from governed state instead of raw transcript replay.
Why hooks are useful for StatePlane¶
Codex hooks are a practical local-first boundary:
- Codex already emits prompt and Bash lifecycle events
- StatePlane already knows how to persist events, rebuild coding state, replay, diff, and export receipts
That means the integration can stay small:
Codex hook payload
-> StatePlane recorder
-> structured state
-> replay and diff
-> compact StatePlane context back into Codex
Current Codex hook limitations¶
Codex hooks are currently best suited for shell-driven coding workflows.
The current PreToolUse and PostToolUse events are Bash-focused.
They do not provide a complete event stream for every Codex action.
StatePlane therefore records Bash commands and command results directly, then discovers changed files at Stop using git diff.
This is useful, but it is not complete prompt-injection protection and it is not a full runtime trace of every Codex action.
Install¶
- Enable Codex hooks:
-
Add
.codex/hooks.jsonto your repo. -
Ensure the
stateplanepackage is importable in the environment where Codex runs. -
Start Codex from the repository root or a subdirectory inside the repo.
You can also write starter files locally with:
Configure Codex hooks¶
The example starter hook file is:
examples/codex_hooks_integration/.codex/hooks.json
Its command target is:
If you are working from a source checkout rather than an installed CLI, change that command to your local invocation, for example:
Hook event mapping¶
| Codex hook | StatePlane behavior |
|---|---|
SessionStart |
Load latest snapshot and inject compact context |
UserPromptSubmit |
Start or continue a StatePlane run and record the user prompt |
PreToolUse Bash |
Record planned command and optionally flag or block dangerous commands |
PostToolUse Bash |
Record command result and parse pytest output when possible |
Stop |
Record assistant message, discover changed files, complete run, export artifacts |
Session and run mapping¶
The StatePlane session id is repo-scoped by default:
This keeps state stable across multiple Codex sessions in the same repository.
The default local database path is:
Run ids are turn-scoped when Codex exposes turn_id:
Fallbacks use the Codex session id or a deterministic unknown-turn hash.
What gets recorded¶
The integration uses the existing StatePlane APIs instead of inventing a second recorder:
observe_user_message(...)observe_tool_call(...)observe_tool_result(...)record_command(...)record_test_run(...)record_file_patch(...)record_risk(...)start_run(...)complete_run(...)export_run_artifacts(...)
That means Codex hook data flows into the same replay, diff, snapshot, and artifact system already used by the structured coding-state examples.
What gets injected back into Codex¶
When there is useful prior state, the integration returns compact additional context such as:
StatePlane context for this repository:
STATEPLANE CONTEXT
Hard constraints:
- Do not edit tests.
Active goals:
- Fix the failing CLI test
Receipts:
- .stateplane/codex/latest_snapshot.md
- .stateplane/codex/latest_diff.md
- .stateplane/codex/latest_manifest.json
The injected context is truncated to stay compact and does not include raw long logs or raw quarantined instructions. If there is no useful prior state, StatePlane can intentionally inject no model-visible context at all.
Artifact layout¶
.stateplane/codex/
state.db
latest_snapshot.md
latest_diff.md
latest_context.md
latest_manifest.json
raw_hooks/
artifacts/
codex-turn-turn-1/
manifest.json
events.json
run.json
coding_projection.before.json
coding_projection.after.json
coding_diff_from_previous.json
state_records.json
snapshot.json
snapshot.md
receipt.md
prepared_openai_request.json
receipt.json
The exact run-artifact directory name depends on the turn or fallback run id.
Safety behavior¶
The default behavior is non-blocking.
StatePlane can flag obviously dangerous Bash commands and record them as risks. Blocking only happens when:
Bash output is treated as evidence, not authority. It may become:
- command evidence
- structured test evidence
- risks
- quarantined risks
It does not become a high-trust user constraint automatically.
Run the simulation¶
That script does not require Codex, network access, or an OpenAI API key.
Troubleshooting¶
- If no latest files appear, make sure Codex started inside the repository you expect.
- If hook commands do not run, verify the command in
.codex/hooks.jsonmatches your environment. - If you are using a source checkout, prefer a
uv run ... stateplane codex hookcommand in the hook file. - If
Stopdoes not record changed files, confirm the repository is a git worktree and the files are tracked by git diff.
Limitations¶
- Codex hooks are experimental.
- Current
PreToolUseandPostToolUsecoverage is Bash-focused. - This integration does not observe every Codex action directly.
- File edits are inferred at
Stopviagit diff. - No live OpenAI calls are made by this integration.
- No network access is required.
Next steps¶
- Start with the simulation example.
- Use
stateplane codex install --repo .to create starter local hook files. - Inspect
.stateplane/codex/latest_snapshot.mdand the exported artifact directory after a real Codex turn.