✅ Readback: prove it in a fresh session
You built the portable core and ported the skill. Now comes the only question that matters: can an agent that has never seen the project pick it up? In this module you run the readback on both runtimes, read the answer critically, and learn to mark each check as passed, failed or not run.
❓ The 5 readback questions
Readback is a continuity test: you open a fresh session, with no history, and ask the agent to read the project and answer five questions. If it answers by citing the right files, the portable core works. If it makes things up, or answers from its own generic knowledge, the core exists but isn't being used.
Read from left to right: the five questions go into a session with no history and come out as one of three verdicts. There's no "sort of passed": either it cites the file, or it doesn't.
The prompt is short and generic on purpose. It doesn't say where the files are: if the agent needs you to point the way, the reading order in AGENTS.md isn't working. This is the exact text, taken from the prompt library and stored in the kit at prompts/03-readback-handoff.md:
Goal: paste into a fresh session of any runtime, inside the project folder.
Read this project's active instructions, current context, task, and latest handoff. Do not edit.
Report: (1) the current objective and acceptance criteria; (2) one important project rule,
with its exact source file; (3) the latest accepted decision; (4) the next concrete action; (5)
conflicts, stale facts, or missing access. Separate what the files establish from what you
infer. Do not rely on a previous conversation.
How to check: the answer has 5 numbered items and each one names a project file. "Separate what the files establish from what you infer" is the most important part: it forces the agent to admit what it made up.
New here? "Fresh session" means an agent process that starts from scratch, with no memory of the previous conversation. In Claude Code it's claude -p "..."; in Codex it's codex exec "...". Everything the agent knows about the project has to come from the files it reads at that moment.
Key concepts
Continuity test: a fresh session answers 5 questions citing files.
What the files say, kept apart from what the agent deduced.
The prompt doesn't say where the files are; the reading order has to work on its own.
Readback only reads. An agent that "fixes" things during the test contaminates the evidence.
🧪 readback-test.sh: claude -p and codex exec
Pasting the prompt by hand works, but it gets tiring and leaves no trail. The kit has a script that runs both executions in sequence, inside the project folder, and saves each runtime's raw answer in relatorios/. The verdict is still yours: the script marks "not run" only when the runtime doesn't exist on the machine.
Goal: run the readback on both runtimes against one of your projects and keep the evidence.
cd ~/projetos/agente-claude-codex
scripts/readback-test.sh ~/projetos/<seu-projeto> both
# → claude (fresh session in /home/.../<seu-projeto>)
# saved: relatorios/readback-claude-2026-09-14.md (25 lines)
# → codex exec (fresh session in /home/.../<seu-projeto>)
# saved: relatorios/readback-codex-2026-09-14.md (386 lines)
How to check: both files exist in relatorios/ and have more than a dozen lines. If one of them only holds a harness warning, that runtime counts as not run, even if the file exists. Replace <seu-projeto> with the real folder; both can become claude or codex to run just one.
Under the hood, the script is simple: it extracts the prompt from the prompts file, enters the project folder, calls claude -p and then codex exec --skip-git-repo-check, and redirects the output. The part that matters is what it does not do: it doesn't force a sandbox on Codex. The first version forced -s read-only and the test failed before reading a single file. You'll see that case in topic 5.
✓ The script does
- ✓Runs each runtime in a fresh session, inside the project folder.
- ✓Saves the raw answer with the date in the name, so it becomes versioned evidence.
- ✓Marks "not run" when the binary doesn't exist, instead of failing.
- ✓Prints the pass criteria at the end, so you can read them next to the answer.
✗ The script doesn't
- ✗Give the verdict. A file with 386 lines can be a failure.
- ✗Edit anything in the project, not even when the agent suggests fixes.
- ✗Force a sandbox: it respects the
sandbox_modein~/.codex/config.toml. - ✗Run in a loop. Each
codex execuses up OpenAI account quota.
💡 Practical tip
Run the readback right after finishing the core (module 2.3) and again after porting the skill (module 2.4). The first measures the context; the second measures whether the installed skill changed anything in the answer. If the answer is identical, the runtime isn't discovering the skill.
Key concepts
Claude Code's non-interactive mode: takes the prompt, answers, exits.
The Codex CLI equivalent; --skip-git-repo-check avoids refusal outside a repo.
Dated, versioned evidence; without it the test "didn't happen".
Every run costs; run it per project, not out of curiosity.
🔎 Reading the answer: does it cite the right files?
The answer arrives as a long block of text. Don't read it as prose: read it as a checklist. For each of the five questions, you look for three things: the item exists, it names a project file, and its content matches what's in the file. The fourth question has one extra criterion: the next action it cites has to be the same one that's in tasks/current.md.
Three steps that many people mix up: the file existing and the agent having read it are necessary, but only the third, the answer using the content and matching it, counts as evidence.
Goal and definition of done
It has to come from tasks/current.md. If the agent describes the goal from the README, the current task is not being read.
Rule with source file
It must name AGENTS.md (or the CLAUDE.md that imports it). A rule without a source is a guess.
Last accepted decision
Comes from context/decisions/. A good answer distinguishes "proposed" from "accepted", as both runtimes did in the real case.
Next action
It must match tasks/current.md and handoffs/latest.md. If the two diverge, the agent should say so in question 5.
Conflicts and missing access
The most valuable part. An agent that finds real inconsistencies is actually reading. One that says "no conflicts" in a freshly created project probably didn't read.
📋 Pass criterion, in one line
All five answers cite AGENTS.md, tasks/current.md and handoffs/latest.md, and the next action in the answer is the same as in the task. Anything less is a fail, even if the prose is nice.
Key concepts
The minimum unit of evidence: file name + matching content.
Exists → read → used. Only the last rung is proof.
Answer = tasks/current.md = handoffs/latest.md.
Whoever finds a real inconsistency is reading.
🧾 The real case: Codex found three holes in its own kit
On September 13, 2026, the readback was run against the kit's own repository, minutes after it was created. The result is the best argument for the test: both runtimes passed, and each one pointed out real problems that whoever wrote the repo had not seen. Below are verbatim excerpts from the files saved in relatorios/.
Real excerpt: relatorios/readback-codex-2026-09-13.md, question 5.
5. Problems found:
- Failed: reading handoffs/latest.md; file missing. Only the
template exists at template/handoffs/latest.md.
- Documentation conflict: PLANO.md says no readback was run;
context/current-state.md says the first run took place.
- Ambiguity: the skill groups in the plan add up to 94, although the
declared gap is 89; the overlap is not explained.
- Not run: runtime validation, drift and the isolated-copy test.
No files were edited by me.
What this proves: Codex read PLANO.md, context/current-state.md and the skills matrix, cross-checked all three and found a wrong sum (73+17+4 = 94, not 89), a handoff that only existed as a template, and a contradictory sentence. All three were fixed in that session.
Real excerpt: relatorios/readback-claude-2026-09-13.md, question 5 (the answer came in English; the content is what matters).
5. Conflicts, stale facts, missing access.
- The working tree has six modified files and an untracked handoffs folder,
all uncommitted. The handoff's "estado aceito" says "repo criado, commit
inicial", which does not reflect these later edits.
- There is no git remote configured, so the open question about publishing
to inematds/agente-claude-codex is unresolved and a push is currently
impossible. The local git email is already the correct inematds address.
- Branch is master, while the environment lists main as the main branch.
What this proves: Claude went beyond the Markdown files and looked at the git state. The uncommitted edits and the master branch were fixed in the next commit; the remote was created when the owner authorized publishing.
1st round on Codex: failed before reading
The script forced -s read-only; the bwrap sandbox doesn't start on this host because of AppArmor. The whole answer said "I couldn't read the files".
Minimal fix and 2nd round: passed
The flag was removed; the script now respects the config's sandbox_mode. Codex cited AGENTS.md, PLANO.md and tasks/current.md and pointed out the three holes.
Claude: passed and found git debt
It cited AGENTS.md, context/decisions, tasks/current.md and handoffs/latest.md, and listed what was out of place in the repository.
Handoff updated with the evidence
Each check went into handoffs/latest.md as passed, failed or not run, with the round number. The next agent reads that, not the conversation.
Notice: both runtimes agreed on questions 1 to 4 and differed only in what each one chose to investigate further. That is exactly what you expect from a good portable core: the context is the same, the executor changes.
Key concepts
An excerpt from the saved answer, not a summary from memory.
Wrong sum, missing file, contradictory sentence: things the author didn't see.
Each run has a number; "passed on the 2nd round" carries the history.
Agreement on the first 4 questions is the signal of portability.
🧯 FALHAS.md: one line per failure
Every failure the readback exposes becomes a line in a file at the project root: date, what broke, the smallest possible fix, and whether the cause was prompt (you asked in a way that induced the error) or infra (machine, network, service, permission). After about ten lines the pattern shows up on its own, and you stop rebuilding things that only needed a safeguard.
Real file: FALHAS.md from the kit, the two lines that came out of this readback session.
# Failures (most recent on top)
| date | what broke | smallest fix | prompt \| infra |
|---|---|---|---|
| 2026-09-13 | readback-test.sh forced `-s read-only` on codex exec; bwrap fails due to AppArmor on this host | remove the flag, respect sandbox_mode from config.toml | prompt \| infra |
| 2026-09-13 | audit.sh summary counted lines from section 3 (73+17+4=94 ≠ 89) | restrict grep to section 2.1 | prompt |
How to use: copy the header into your project. Write the line when you finish fixing, before moving on to the next task. If the fix was "rewrite everything", it was probably just a missing guard, retry or validation; record that.
✓ Good line
- ✓One line, no narrative. Long details go in a separate, linked file.
- ✓Fix named as a minimal action: "remove the flag", "restrict grep".
- ✓Marks both causes when it is both, as in the sandbox case.
- ✓Most recent on top, so you can glance and see the pattern.
✗ Bad line
- ✗"Codex threw an error, I redid the script." No what, no minimal fix.
- ✗Written at the end of the session, from memory, three failures at once.
- ✗No prompt or infra classification: loses the most instructive information.
- ✗Kept only in the conversation, which the next agent can't see.
New here? A "sandbox" is a playpen Codex creates with a tool called bwrap so the agent doesn't touch anything outside the folder. "AppArmor" is a Linux security module that, on this machine, forbids the technique bwrap uses. Result: the playpen doesn't come up and the agent can't read anything. The fix wasn't "repair Linux"; it was to stop forcing the playpen on a host where it doesn't work.
Key concepts
A cap, a retry, a guard, a validation. Rarely a rewrite.
You induced the error, or the machine/service failed. Sometimes both.
When you finish fixing, before the next task. Never at the end of the session.
After ~10 lines, you see what always breaks and protect it ahead of time.
🚦 When to mark passed, failed or not run
The three states are the grammar of every report in this course, and the third is the most important. Not run is not shameful: it is honesty. The serious mistake is the opposite: marking "passed" on a check nobody executed because the file "looked right". The prompt library is explicit: a readable file, a successful import or valid syntax are not proof of equivalent behavior.
✓ Passed
The check was executed, the result was observed and it meets the criterion. There is an evidence file or command output to show.
✗ Failed
Executed, observed, doesn't meet it. It gets recorded with the reason and becomes a line in FALHAS.md. A preserved failure is worth more than an invented pass.
— Not run
Not executed, for lack of runtime, time, an owner decision or quota. Write down the exact step to reproduce it later.
Real example: the "Checks run and result" block from the kit's handoffs/latest.md, after the readback.
## Checks run and result
- scripts/audit.sh — passed (89 skills only in Claude: 71 reusable, 15 adapter, 2 native, 1 without SKILL.md).
- scripts/adapt-instructions.sh ~/.claude --dry-run — passed (71 portable lines, 7 Claude residue).
- template/scripts/check.sh — passed.
- scripts/readback-test.sh . codex — passed on the 2nd run (1st failed due to bwrap sandbox; fixed).
- scripts/readback-test.sh . claude — passed: cited AGENTS.md, context/decisions, tasks/current.md and handoffs/latest.md.
- scripts/sync-skills.sh — not run (awaiting pilot choice).
- Isolated copy + check.sh — not run.
Notice: both "not run" entries are there, with the reason. Whoever opens the next session knows exactly what is left, and doesn't find out at the worst moment that "sync-skills" was never tested.
⚠️ The mistake to avoid
Declaring "migration complete" while a required flow is "not run". The prompt library says the opposite: recommend the smallest remaining step, never a speculative rewrite of the whole system.
Key concepts
Passed, failed, not run. There is no fourth state.
A "passed" with no file or command output is a "not run" in disguise.
Every "not run" comes with the exact command to run it later.
The report ends with an action, not with a rewrite plan.
Self-check (optional): the readback in Codex returned 380 well-written lines, but none of them cites tasks/current.md. How do you mark it?
🎯 Module summary
Next module:
2.6 — Handoff and prime: the daily cycle