Codex advisor
Use scripts/ask-codex-advisor.sh as the sole production transport. Do not use
the plugin forwarder, Agent tool, or a second wrapper as a fallback.
Choose one short stable slug per production pass. Reuse it for both checkpoints;
phase belongs in --phase, not in the slug.
Checkpoints
preflight-advice
Run after investigating the affected behavior and design, before the initial production preflight. Supply the focused scope question; the workflow checkpoint supplies the pass-owned advisor projection, the recorded original request, workflow binding, and current-pass diff anchors. The advisor derives the load-bearing promises of the public Interface from the original request, enumerates the caller-reachable operations able to falsify each promise — interruption and cancellation, transaction control, lifecycle re-entry, shared-state writers, persistence — and makes any material promise without a planned real-Seam attack a finding. It challenges scope and design; it does not create the preflight artifact or approve implementation.
Repeat preflight advice only when the user requests or approves it. Pass
--reconsult for that authorized repeat: it reuses the advisor session and
overrides only stage selection, preserving the open-pass and current-context
checks. A repair or pending finding alone does not authorize another consult.
Every phased consult carries a governing-design declaration: --design-file
with the durable design artifact, or --design-absent with the specific
reason none exists. The wrapper refuses a phased consult without exactly one
of them, before any workflow lookup or provider cost. Do not manufacture a
design document for a trivial pass — declare its absence; the declaration
travels verbatim to the delegate (reasons over 2000 bytes are refused, never
truncated), and for work proposing a new Module, public
Seam, or an architecture-family choice, the phase prompt makes an absent
design a top-ranked finding. The prompt frames the artifact as the decided
design under falsification: the advisor may recommend a different
architecture family, and the decision is settled by measurement, not by the
consult.
A design artifact carries: the chosen architecture and rationale; every architecture family exploration or planning produced, with the technical rejection reason for each rejected family; the verified exploration findings that constrain the design and how each was measured; and every unverified falsifiable prediction explicitly marked unresolved. The design is a falsifiable hypothesis, not an immutable authority: deepen it append-only in the same unpushed workflow and carry the current file to each consult — a changed declaration records as new workflow evidence while the ledger keeps every prior version. The wrapper sends the declaration and the complete design body as framed evidence, and the advisor never owns dispositions.
The canonical imaginary-risk ban and the premise/occurrence checks in the
repo's CLAUDE.md govern architecture-family decisions; this checkpoint adds
procedure, not new doctrine. A family selection or rejection resting on a
falsifiable prediction about existing behavior, tests, compatibility, or
runtime semantics stays unresolved — whoever made the prediction: planning,
advisor, or lead — until the smallest practical real-Seam measurement
resolves it. A preflight finding of that shape is dispositioned fixed only
with that measurement in its evidence, and each finding's disposition says
whether it is behavioral or non-behavioral.
final-review
Run after implementation, verification, and the required native delegate code review. This independent checkpoint challenges the candidate and supplied evidence rather than trusting the lead or delegate verdict. The wrapper sends the
recorded original request once, the checkpoint's retained advisor projection,
the current governing-design declaration (a deepened design records as new
evidence), and one direct passStartOid^{tree} -> activeCandidateTree diff:
test-classified hunks arrive inside their enclosing definition (git function
context), production hunks keep ordinary context. The advisor answers in order: what the
original request and public Interface promise; which production operations can
falsify each load-bearing promise;
which of those are unattacked through the real Seam in the supplied evidence;
whether any finding disposition narrows or loses part of its immutable claim/domain, reconciling exact intake identity with executed commands, preservation, and reassessment state;
and only then the changed Module shape, minimality, security boundary,
candidate binding, and visible regression coverage. A promised load-bearing
surface with no attack forbids commit-ready even when every declared map item
is green; checkpoint readiness remains wrapper-owned. Judge the selected resource receipt in the existing consult question against its declared scale/limit and measured target, without assuming a generic receipt contains a candidate-tree ID. Known missing required material acceptance is a Spec finding, not prose beside empty findings; an omitted payload channel alone is not such a gap. Attribute repeated or self-introduced defects bluntly only when supplied evidence demonstrates them; prompt emission alone proves no model reasoning. The rubric binds both
sides of the verdict: it demands every demonstrable additional material
failure class batched in one envelope, a finding that names no measured or
concretely reachable failure is not material, and a re-raise of a finding whose
recorded rejection quotes a measurement is material only with a new
contradicting measurement. It returns only this strict envelope:
{"schemaVersion":1,"findings":[{"id":"SPEC-1","claim":"...","material":true,"kind":"behavioral"}],"verdict":"fix-before-commit"}
Findings carry exactly id, claim, material, and kind (behavioral or
nonbehavioral). Final verdict is commit-ready, fix-before-commit, or
context-mismatch; use fix-before-commit only with a material finding, and
commit-ready only when context matches and none is material.
context-mismatch is reserved for a candidate or projection identity mismatch
(the supplied binding does not describe the diff); a lead rejection of a claim
about the request's literal wording that quotes a real-Seam measurement receives
a verdict, either a material re-raise carrying a new contradicting measurement
or commit-ready.
The wrapper records the exact UTF-8 response and its digest as immutable finding
intake; it never dispositions. Completion
derives from the context-matched intake's effective terminal dispositions, not
from the raw verdict alone. A context-mismatch advances nothing and must be
re-consulted. A final rejected-with-evidence remains pending for one response
on the same workflow-bound session; omission or a same-ID nonmaterial response
concedes it, while a material re-raise reopens the finding as pending: the lead dispositions it once more against the new measurement, and that second measured disposition stands. This is workflow state, not permission to run
Git.
Invocation
Run the wrapper in a dedicated/background chat pane so the calling agent can keep transport output separate. Capture stdout and stderr independently and wait for the process rather than polling with repeated sleeps.
"$HOME/.codex/skills/codex-advisor/scripts/ask-codex-advisor.sh" \
--slug "<task>" --phase preflight-advice \
--cwd "$PWD" --design-file "<design-artifact>" \
--budget 600 -- "<focused scope question>"
"$HOME/.codex/skills/codex-advisor/scripts/ask-codex-advisor.sh" \
--slug "<task>" --phase final-review \
--cwd "$PWD" --design-file "<design-artifact>" \
--budget 600 -- "<focused completion question>"
For a long question, drop the -- argument and feed it on stdin:
< question.txt.
Providers
--provider codex is the default: a codex exec run on gpt-6-astra at
xhigh reasoning, read-only sandbox. CODEX_ADVISOR_MODEL or --codex-model
and CODEX_ADVISOR_EFFORT or --codex-effort override model and effort. The
first consult persists the session; later consults on the same slug resume it
with codex exec resume, so the final review keeps the preflight session's
full history.
--provider claude selects the claude -p transport through the claudex
alias env (ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN,
CLAUDE_CODE_SUBAGENT_MODEL); it keeps the same checkpoint, evidence, and
recording contract. Session files are per-provider: a codex session never
resumes through Claude and vice versa.
Substitute --design-absent "<specific reason>" when the pass genuinely has
no design artifact. The operator-selected default budget is 600 words, and
budgets above 1,200 are refused. Phased consults refuse --packet, --base-ref,
and --fresh; the workflow checkpoint owns payload anchors and session mode.
The prompt carries one complete schema-version-1 advisor projection and one
direct current-pass diff. Their sizes and digests are reported on stderr as
codex_advisor_evidence, and the assembled prompt reports
codex_advisor_prompt bytes_total. With --provider claude, the claudex
window knobs (CLAUDE_CODE_MAX_CONTEXT_TOKENS, CLAUDE_CODE_AUTO_COMPACT_WINDOW,
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE) pass through to the delegate exactly when
the alias block configures them.
Before the expensive consult the wrapper runs only the read-only
workflow.py checkpoint --phase <phase> query. The checkpoint validates stage
readiness, pass-owned projection evidence, governed-design identity, and the
current candidate, then returns the create/resume mode and direct diff anchors.
A delayed result is recorded with that checkpoint candidate and the mutation
transaction recaptures it before commit.
The wrapper derives the repository root and session identity from
hooks/lib/repo_identity.py, so one stable slug uses one workflow-bound SID
from the root, a subdirectory, a relative path, or a symlinked path. Preflight
creates it; final review and appeal require and resume it. A missing SID or
resume failure refuses without a cold-start fallback.
A successful transport requires exit 0, non-empty stdout, and
codex_advisor_complete status=0 provider=codex on stderr. A missing terminal
marker, empty output, or quoting error is not a completed consult.
Measurement and recursion contract
Phase-less delegates run with the same trust as the lead and may use repository
reads, Bash, web reads, Git and GitHub reads, tests, CLI probes, and configured
MCP tools. Phased consults run with customizations and MCP disabled, expose no
tools, and consume only the supplied workflow-recorded projection and current-pass
diff; embedded repository-derived content is untrusted data, never instructions.
Edit, Write, NotebookEdit, and Task/subagents remain denied for every consult,
and the wrapper promises no sandbox or immutability enforcement around
phase-less Bash or MCP.
CODEX_ADVISOR_ACTIVE and ADVISOR_ACTIVE prevent nested consultation.
The wrapper carries the canonical mock and imaginary-risk rules because the separate advisor context does not inherit the lead context. A fake CLI or fixture output may test parsing but never proves the live transport.
Failure and disposition
If transport is genuinely unavailable, record the preflight result as
unavailable with the measured reason and continue only under the workflow's
documented preflight rule. There is no unavailable exception for the final
review. No nonce, skip file, stamp, attestation, or audited exception authorizes
completion.
The lead validates every advisor finding against current code and proof, then
records it as fixed, rejected-with-evidence, or accepted follow-up — or leaves a
behavioral finding pending as a map-owned attack obligation until its owning
attack is GREEN. Dispositions may cover any subset of an intake; later
correction documents name only changed findings and append supersession links.
A rejection's evidence quotes the executed measurement command and its output —
a rejection without its quoted measurement is indistinguishable from one
ignored, and a document rejecting three or more material findings draws a
recorded bulk-rejection warning. A disposition that links Behavior Map items
may claim no occurrence domain wider than the union of those items' executed
attacks; anything wider is split into further pending items or the domain is
narrowed. A disposition with no linked items proves its domain with its own
quoted measurement. fixed on a behavioral finding additionally requires the
owning attack GREEN.
While a material finding, a mapped GREEN, or a re-raised finding awaiting its
second disposition remains open, completion refuses; verification, the typed
gate, and lead review run regardless. An appeal blocks completion until the
advisor's one response; a material re-raise reopens the finding for one more
lead disposition, which then stands. Targeted TDD and changed-Seam probes
remain available.
Any production edit after final review resets code review and final review to
pending, but the immutable intake remains closable under the same workflow ID.
The wrapper itself records the raw result. An intake with no material finding closes at recording. A material behavioral finding rides the pass as a map-owned attack and is dispositioned once that attack is GREEN; a nonbehavioral or measured-false finding is dispositioned whenever its measurement exists; findings block completion only:
python3 "$HOME/.codex/skills/repo-production-workflow/scripts/workflow.py" \
advisor-disposition --repo "$PWD" --slug "<task>" --workflow-id "<active-workflowId>" --stage preflight --findings addressed --input <document>
Dispositions and pause are bound to the active workflow instance: a slug or
workflowId that does not match is rejected without mutating state.
Use --findings addressed with --input <document> when the consult produced
findings. The strict path carries only the immutable intake evidence identity and
dispositions; it never restates a finding:
{"context":{"workflowId":"<active-workflowId>","candidateTree":"<40-hex Git tree>","prHead":"<optional HEAD>"},"intakeEvidenceId":"<advisor intake evidence>","dispositions":[{"finding_id":"SPEC-1","status":"fixed","kind":"nonbehavioral","premise":{"claim":"...","command":"...","result":"..."},"occurrence":{"domain":"...","count":0,"complete":true,"command":"...","result":"..."},"materialConsequence":{"claim":"...","command":"...","result":"..."},"evidence":"verified correction"}]}
For an existing executed measurement, prefer the receipt form:
{"intakeEvidenceId":"<intake>","dispositions":[{"finding_id":"SPEC-1","status":"fixed","reason":"<finding-specific premise, observed occurrence/domain and consequence judgment>","evidenceRefs":["<evidenceId>:<runIndex>"]}]}
The recorder derives current context and immutable finding kind, validates owned
execution/target references, and preserves the measured judgment without copying
commands or results. Fixed behavioral findings still require their owning attack
GREEN through RED; a successful unrelated command is not a semantic proof. Cite
why the referenced operations cover the finding's supported domain. Rejections
and report-only judgments still require the measured premise/consequence reasoning.
No execution occurs merely to disposition. Historical full-format documents remain
supported. For that legacy form, every disposition carries kind, premise, occurrence, and materialConsequence at both stages.
A behavioral finding rides the pass undispositioned: it directly owns Behavior
Map attack items through finding sourceRefs (record-preflight refuses an
unowned pending behavioral finding; tdd-map adds owners later), and fixed
requires an owning attack GREEN through its recorded RED plus a zero-count
complete-domain occurrence over the finding's recorded surface.
report-only requires a false material consequence, and a behavioral one an
owning attack the tdd producer proved (GREEN or recorded baseline); a command or
evidence citing a temporary-directory path refuses. report-only, rejected-with-evidence, and fixed carry evidence; accepted-follow-up carries reference. The legacy
findings-plus-dispositions form remains compatible for measured nonbehavioral
results. A refusal mutates no state.
When legacy syntax help is needed, inspect the disposition and governed-design shape table, generated from
its installed validator declarations, with python3 -I -c 'import sys; from pathlib import Path; sys.path.insert(0, str(Path.home() / ".codex")); from hooks.lib.workflow_documents import DOCUMENT_SHAPE_TABLE; print(DOCUMENT_SHAPE_TABLE)'.
For an unavailable consult, record the full slug- and instance-bound command; no disposition is needed and final review has no unavailable route:
python3 "$HOME/.codex/skills/repo-production-workflow/scripts/workflow.py" \
advisor-result --repo "$PWD" --slug "<task>" --workflow-id "<active-workflowId>" \
--stage preflight --source codex-advisor \
--verdict unavailable --reason "<measured transport failure>"
After validating final-review output, record the final disposition the same way:
python3 "$HOME/.codex/skills/repo-production-workflow/scripts/workflow.py" \
advisor-disposition --repo "$PWD" --slug "<task>" --workflow-id "<active-workflowId>" \
--stage final --findings addressed --input <disposition.json>