An AI agent telling you "done" is not evidence.
When I started delegating work to Codex, I took those reports at face value — until I checked the code and found the change missing, the wrong file edited, or no commit at all.
So I stopped trusting language and started making the shell write the facts to disk.
Why this design works When you hand a task to Codex, it comes back with "Completed." At first that satisfied me.
But when I actually checked the code, the critical change wasn't there, or a different file had been touched, or had never run.
The output "I did it" and the fact "it was actually done" are two different things.
This is true of Claude Code too.
Whether tool results were read correctly, whether errors were swallowed — even with code I wrote myself, running a self-audit right after declaring completion turns up something every single time.
Delegating implementation to an AI amplifies that problem by one more notch.
The fix is simple: make it write state to a file, not to language.
Even if the AI says "completed," it isn't complete unless exists in the status file.
If the handoff file doesn't contain the real output of , you don't know what changed.
If the four sections you specified in the task file (Summary, Files Changed, Validation, Remaining Risks) aren't there, you can't verify it.
Files don't lie.
An AI under pressure will insist "I did it," but the output of can't be forged.
Pushing state management down into the filesystem is what makes it possible for a human to cross-check it in a shell.
That's the essence of this design.
The other important piece is separation of concerns. orchestrate-codex-worker.sh takes three arguments up front.
Each of these three files has a clear role. task-file: The work order for Codex.
It contains only "what to do." handoff-file: The handoff note after Codex finishes.
Written on success or failure alike, on the assumption that the next person in line (the next Claude Code session, or me) will read it. status-file: Machine-readable progress state.
It takes only three values: → / .
What happens without this separation?
When instructions and execution results live in the same place, "is this an instruction or post-execution output?" becomes ambiguous.
When you run large numbers of tasks in parallel, that ambiguity is fatal.
Multiple Codex workers can run in the same directory without interfering as long as each has its own independent task/handoff/status files.
On top of that, the script starts with .
That's a declaration that "the entire script stops the moment any command fails." Without it, Bash ignores errors and moves to the next line.
With , the behavior becomes: if git rev-parse fails, stop; if mkdir fails, stop.
A design that doesn't swallow errors matters especially in a script built on the premise of AI delegation.
The overall flow Following the script's behavior in order looks like this.
Looking at the function — the core of the actual code — shows what's being recorded. returns the branch name at that moment. is the absolute path of the worktree.
The timestamp comes out as UTC ISO 8601 via .
In other words, the status file tells you line by line when, on which branch, in which worktree, and in what state.
When running in parallel across multiple worktrees, just looking at the Worktree field in the status file identifies which is which.
The prompt handed to Codex is also assembled directly inside the script.
Two things stand out. "Do not write handoff or status files yourself" — an explicit prohibition.
Who writes the handoff/status files is a key design fork.
If you let Codex write them, Codex may output something that merely looks right.
Writing them from the script side means you get the actual output of , the actual branch name from , and the actual time from .
Those can't be falsified.
Forcing four sections.
Requiring "exactly these sections" in Codex's output fixes the positions that downstream processing and review will reference.
Open the handoff file, read the