A Claude Code plugin that runs automatic, read-only Codex inspections of document-like artifacts — plans, designs, proposals — and loops on the findings until they are fixed or waived. It is the document-side sibling of codex-review (which reviews code commits).
Prerequisites: see Requirements.
/plugin marketplace add sorelmitra/codex-inspect
/plugin install codex-inspect@sorelmitra-inspect
/reload-plugins
Pull updates later with:
/plugin marketplace update sorelmitra-inspect
/plugin update codex-inspect@sorelmitra-inspect
/reload-plugins
/codex-inspect-artifact [<work-item> <artifact>] | [<path>]— inspect a document. The command runs a small sentinel script; the plugin's PostToolUse hook detects its token, runscodex execwith a strict prompt contract, parses[P1]/[P2]/[P3]findings with the parser vendored from codex-review, and returns a verdict.<work-item>: if using the directory layout (see below), specifies the work item where the inspections would land and be read from<artifact>: specifies the artifact for the same directory layout<path>: full path to artifact to inspect; Codex will probably ask for a work item if you have the directory layout enabled- if none of the above is specified:
- if directory layout is on, it will search for the latest artifact by modification date
- else it will ask for it
- Optional opinionated directory layout for reading artifacts and storing inspection results: Enable
workItemLayout, configuredocRoot, and thencodex-inspectwill :- look for artifacts to review under
<docRoot>/<work-item>/plan/ordocuments/ - expect specifications (based on which artifacts are inspected) under
spec/ - write inspection result as the next
<docRoot>/<work-item>/inspect/inspect-NN-...mdwith a JSON metadata block. Without a layout, findings return through hook context. This suggest the following user flow: -> Write your spec that the agent should work on inspec/-> Have the agent produce artifacts (plans, analysis, any documents) based on the spec -> Inspect the artifacts with this plugin's layout, with the benefit of having all requirements, decisions, designs and plans documented.
- look for artifacts to review under
- Optional loop (enable
loop): a FAIL blocks the session until the findings are applied and a re-inspection passes, capped atloopMaxrounds. WithfirstStopHumanReviewon (default), the first FAIL hard-stops the turn so the user can decide if the inspector is moving in the right direction before any automatic iteration. The first-stop messages carry aHUMAN REVIEW REQUIREDbanner with the operator's steps: where the result is,/codex-inspect-waiveto overrule,/codex-inspect-resumeto continue. Once the loop starts, the human operator doesn't have further checkpoints, but can interrupt it at any time using standard Claude Code commands (Esc). /codex-inspect-waive— waive a disputed finding./codex-inspect-resume— the only way out of the first-stop review: applies waivers, then either releases or continues the loop./codex-inspect-settings— show/change settings, toggle the skip switch (see "safety" section below).
${CLAUDE_CONFIG_DIR:-~/.claude}/codex-inspect/settings.json, strictly validated (unknown keys rejected; invalid settings stop inspections visibly):
{
"workItemLayout": true,
"docRoot": "~/1data/work/doc",
"loop": true,
"loopMax": 5,
"firstStopHumanReview": true,
"sandboxMode": "read-only",
"valveMax": 5
}Defaults:
docRoot: nullworkItemLayout: falseloop: falseloopMax: 5firstStopHumanReview: truesandboxMode: "read-only"; accepts onlyread-only,workspace-write,danger-full-access(elevated values warn visibly; there is no "bypass" value). You will needdanger-full-accessif your Claude Code is already in a sandbox.valveMax: 5— Stop-valve budget: blocked turn-ends without a new inspection or a user prompt before the loop force-releases. Values above Claude Code's consecutive-block limit of 8 let the harness cut off first.
An active saga runs on the settings snapshot taken when it started. valveMax is the exception: the Stop hook reads it live, so a change applies to the running saga too.
Each inspect-NN file (layout mode) has three parts:
- A JSON metadata block — source path and hash, request and session ids, verdict, disposition, round.
## Findings— the parsed finding lines, one per finding, marked(waived)where a waiver applies. This is the index the loop enforces: blocking counts and waive keys come from it.## Inspector notes— Codex's final message, verbatim. It carries what the findings list cannot: the legend, the overall assessment, the commentary — and it is the ground truth the findings are parsed from, so a malformed finding line the parser missed still shows up there.
The two sections overlap on purpose: the notes keep the verbatim record, the findings keep the machine-readable one.
- The inspector is sandbox-enforced read-only by default; it never edits the artifact or prior inspections. Even if you enable
danger-full-access, Codex is instructed to not touch your artifacts. - Every inspection runs against a hashed context manifest; inputs that change, appear, or disappear during the run make it ERROR, never a verdict.
- Every verdict requires read evidence: the full contents of each input must appear in the Codex event stream and hash-match the manifest. A clean exit with no such evidence is INCONCLUSIVE (avoiding fake negative findings), and findings without read proof never block.
- Enforcement is fail-closed: blocking state is published only after the inspection file and history entry are durable; releases (waive, valve, skip, staleness) are recorded as history transitions.
- Escape hatches:
/codex-inspect-settings skip on(mid-session kill switch),CODEX_INSPECT_SKIPenv, a Stop-hook safety valve (valveMaxblocked turn-ends, default 5), and age-based state Garbage Collection. - The valve targets unattended stuck loops only: any user prompt resets its counter (an attended session is not a stuck one), and a new inspection resets it too. Only a silent, unattended blocked loop releases at the budget; the release stays visible and audited (
valve-releasedin the history).
On every turn end the Stop hook atomically writes stop-decision.<session>: {sessionId, eventId, epoch, decision}, where decision is blocked (the loop held the session), released (a blocking saga was force-released), or none, and eventId is the transcript's last assistant-message uuid at that Stop event (attachment and feedback entries appended by other hooks mid-event do not move it). Notification tooling (e.g. a Stop-hook sound script) can wait briefly for the marker matching its own event id and mute the blocked dings a fix loop would otherwise fire every round; everything else — released, none, no marker — should ring. The marker is observational only; it changes no plugin decision.
Inspections also export CC_NOTIFY_SILENCE=1 to the Codex process. Codex fires the user's trusted ~/.codex/config.toml hooks even under exec (and -c overrides cannot clear them), so notification tooling wired into those hooks can honor the variable to stay silent during automated inspection rounds.
Under ${CLAUDE_CONFIG_DIR:-~/.claude}/codex-inspect/:
settings.jsonstate.<session>last.<session>(pointer)stopcount.<session>(Stop-valve counter)stop-decision.<session>(per-event Stop decision marker)codex-inspects.jsonl(append-only history: inspections + disposition transitions)requests/(sentinel request files)waived(no-layout waivers)skip.
Directory-layout mode waivers live in <work-item>/inspect/.codex-inspect-waived.
Hand-written legacy inspections can be attributed via <work-item>/inspect/.codex-inspect-legacy-map (JSONL: {"file": ..., "path": ...}).
- Waive-key normalization is copied from
codex-review, including its global:Nstripping — a title carrying a meaningful colon-number token (port:8080) shares its waive key with a sibling differing only in that number. Kept for behavioral parity.
- OpenAI Codex CLI on PATH (or
CODEX_BIN), authenticated jq,git
Local install from a clone (sideload):
/plugin marketplace add /path/to/codex-inspect
/plugin install codex-inspect@sorelmitra-inspect
/reload-plugins
Tests:
npx --yes bats tests— hook, resume, and waive teststests/parser-parity.sh— proves the vendored parser matches the codex-review clone (CODEX_REVIEW_CLONEto point elsewhere); dev-only