| name | codex-build |
| description | Orchestrator drives, Codex codes. Execute an approved plan one task at a time: your agent (Claude Code, etc.) sequences the work, briefs OpenAI Codex to write ALL product code, reviews every diff, runs the test gate BEFORE each commit, commits one task per commit, and opens exactly ONE PR at the end. Use when the user says 'codex-build', 'have codex code it', 'you orchestrate, codex codes', or hands over a plan for step-by-step implementation. |
| license | MIT |
| metadata | {"version":"2.1"} |
codex-build — orchestrator drives, Codex codes
You (the agent running this skill) are the orchestrator. A separate model,
OpenAI Codex (codex exec), is the coder. You never write product code;
Codex does. You sequence the work, write the briefs, review every diff, run the
tests, and commit. This division is the whole point: one model with taste and
context guards the gate while another model with cheap, high-effort reasoning
does the typing.
Roles (non-negotiable)
- Orchestrator = you. Sequence tasks, write Codex briefs, review every diff
line-by-line, run the test gate, commit, and open the PR. You do not write
product code. The only exception is a trivial fix-up (≤5 lines, e.g. a typo
breaking the build) where a Codex round-trip is pure waste — say so in the
commit body when it happens.
- Codex = coder. All feature code, tests, and refactors are written by
codex exec. Model and effort are pinned per invocation (see Config) — never
rely on config defaults silently, or a codex upgrade will change your
builds out from under you.
Config (resolve once, at the top of the run)
| Variable | How to resolve | Default |
|---|
MODEL | --model arg, else $CODEX_BUILD_MODEL, else your Codex config default | pin one you have access to (see below) |
EFFORT | second positional arg, else $CODEX_BUILD_EFFORT | high (opt into xhigh for hard/architectural work) |
TRACKER | detect: bd on PATH → beads, else markdown | markdown |
Pin a model. Run codex exec --help / check ~/.codex/config.toml for what
your account exposes (e.g. gpt-5-codex, gpt-5.6-codex). Announce the resolved
MODEL/EFFORT to the user before starting so the run is reproducible. If the
CLI rejects xhigh, fall back to high and tell the user.
Arguments
codex-build <plan-file> [effort] [--model <name>]
<plan-file> — a Markdown plan with an ordered task list (T1..Tn), each
task naming its files, constraints, and test commands. See
references/plan-example.md for the shape. If the
plan has prose but no task list, extract one and show it to the user before
coding.
[effort] — high (default) | xhigh.
Step 0 — Preflight (once)
codex --version. If Codex isn't authed, codex exec "reply OK" -s read-only
fails — stop and tell the user to run codex login.
- Confirm the pinned model + effort are accepted (cheap, no side effects):
codex exec "Reply with the single word READY" \
-m "$MODEL" -c model_reasoning_effort="$EFFORT" -s read-only --ephemeral < /dev/null
If xhigh is rejected, fall back to high and tell the user.
Always redirect < /dev/null on every codex exec (see Rails) — without
it, a non-interactive run hangs forever on "Reading additional input from
stdin…" instead of doing the work.
- Read the plan end-to-end. Extract: task list, dependency order, per-task test
commands, guardrails (things the plan bans), branch/PR target.
- Resolve the current checkout and look for durable run state before applying
a clean-worktree rule:
REPO_ROOT = git rev-parse --show-toplevel.
GIT_DIR = git rev-parse --absolute-git-dir (this is worktree-specific).
SKILL_DIR = the directory containing this SKILL.md.
- State root =
$GIT_DIR/codex-build/. This keeps orchestration state off the
product diff while making it survive context compaction and process restarts.
- If
current points to an active run for this branch, read its run.md,
tasks.md, interfaces.md, and active allowlist before doing anything else.
Confirm its last recorded commit still matches HEAD; stop on a mismatch
instead of guessing. An in-flight task may legitimately have a dirty
worktree: immediately run its saved scope check before any new Codex call.
If current describes another branch or an inconsistent run, stop rather
than overwriting it.
- For a new run only, inspect
git status --porcelain. The task loop starts
clean so its scope check can attribute every changed path to the active task.
If the checkout is dirty, preserve it and create an isolated worktree from
the intended base (or stop and ask); never discard or absorb pre-existing
work.
The durable layout is:
$GIT_DIR/codex-build/
current
runs/<run-id>/
run.md
tasks.md
interfaces.md
allowlists/T1.txt
Tracker (unit of work = one task)
The loop is identical regardless of tracker; only the bookkeeping commands differ.
markdown (default, zero install): keep the - [ ] / - [x] checklist in
the run's durable tasks.md. "Claim" = note the task in-flight; "close" =
check the box with the commit hash and test evidence.
beads (optional, if bd is on PATH): richer dependency tracking.
bd prime for context; one bead per task (bd create, title = task title,
description = plan excerpt + file paths, dependencies per the plan); claim with
bd update <id> --claim; close with bd close <id>. Mirror task status and
commit/test evidence to durable tasks.md so a resumed run has one local
recovery record. Install:
https://github.com/steveyegge/beads.
Step 1 — Materialize tasks
Turn the plan's task list into tracker units in dependency order. Each unit
records: goal, the plan excerpt (verbatim constraints, file paths, schema/copy
blocks), and its declared file scope (the files it is allowed to touch). The
file scope is enforced by an executable check — everything else is out of bounds.
For every task, write its scope to allowlists/<task-id>.txt: one exact,
repo-relative file path per non-empty line. Use / separators; no absolute
paths, directories, ./.., comments, or globs. A rename declares both old and
new paths. If the plan genuinely needs another file, amend the allowlist before
Codex touches it and record the reason in tasks.md; never expand scope merely
because an unexpected path appeared in the diff.
Initialize interfaces.md as the canonical cross-task contract. It starts with
"greenfield — no prior interfaces" and is updated only from committed source in
step 6 below.
Step 2 — Per-task loop (the heart; repeat until the queue is empty)
For each task, in dependency order:
-
Claim it in the tracker.
For a newly claimed task, confirm the product worktree is clean before
invoking Codex. Durable state is under the Git directory, so it does not make
the worktree dirty. When resuming an already in-flight task, the worktree may
contain its changes; run the saved allowlist check immediately instead.
-
Brief Codex. Compose a self-contained prompt — Codex sees only what you
give it. Use references/codex-brief.md as the
skeleton. It must carry:
- the task's goal and the verbatim plan excerpt (constraints, file paths,
schema/copy);
- the interfaces ledger (see step 6) — the signatures, types, endpoints,
and file paths that earlier tasks created and this one builds on. Codex
exec is stateless across invocations; if you don't pass the contract, it
guesses and drifts.
- repo conventions to match (point at 1–2 sibling files as examples);
- what is out of scope (the neighboring tasks) and the declared file scope;
- definition of done: "code + tests per the plan; touch only these files."
codex exec "<brief>" -C "$(git rev-parse --show-toplevel)" -s workspace-write \
-m "$MODEL" -c model_reasoning_effort="$EFFORT" < /dev/null
Never use --dangerously-bypass-approvals-and-sandbox. The < /dev/null is
mandatory (see Rails).
-
Enforce scope, then review the diff yourself. This is your job, not
Codex's.
Step 3 — Finish (after the last task)
- Full-suite gate one final time: all packages + build + any lint/screenshot
scripts the plan names. Green or you don't ship.
git pull --rebase then git push. git status must show up-to-date with
origin. On rebase conflicts, resolve minimally and re-run the gate — never
force-push over shared history.
- Exactly ONE PR for the whole feature, targeting the branch the plan
specifies. Body = plan summary: context, what shipped, test evidence,
out-of-scope/follow-ups. No AI attribution anywhere.
- GitHub:
gh pr create. GitLab: glab mr create. No forge CLI: push the
branch and give the user the compare URL to open the PR themselves.
- Close out the tracker (file follow-ups, close finished units).
- Mark
run.md complete and record the final commit, gate evidence, and PR URL.
- Report: tasks completed/blocked, commit list, PR URL, anything deferred.
Rails
- One task per commit; one PR per plan. No batching, no splitting.
- Disk state is canonical. Chat progress is a rendering of
run.md, tasks.md,
task allowlists, and interfaces.md, never the only copy of run state.
- Every
codex exec gets < /dev/null. With a prompt passed as an argument
and an open stdin, codex exec blocks indefinitely on "Reading additional
input from stdin…" and never runs. Redirecting stdin from /dev/null gives it
immediate EOF so it proceeds. This is the single most common way to make the
whole run silently hang.
- Tests before every commit — non-negotiable.
- Effort stays
high/xhigh. A trivial-mechanical task may drop to high
(never lower); note it.
- If the plan and the user's live instructions conflict, the user wins —
note the deviation in the PR body.
- Secrets never go into briefs, commits, or PR bodies.
- A commit that later tasks built on turned out wrong? Fix forward with a new
task/commit. Don't rewrite pushed history.
See also