Free playbooks in your inbox

How to Review a Coding Agent's PR in 60 Seconds

Approve or reject a coding agent's pull request in about a minute, from your phone, because the screen is built from an evidence file and not from the agent's summary. The same script refuses to show anything if the branch moved or the file was edited after the run.

From the youcanbuildthings catalog ▸ Build-tested

Hello builders,

Reviewing a coding agent’s work in about a minute, from your phone, is what lets one person keep up with three agents without rubber-stamping any of them. The summary the agent writes will not get you there; a Reddit post about a Claude Code plugin for “translating from Claudish to English” pulled 3,000 votes, which tells you how readable those summaries are. The way to review AI generated pull requests fast is to stop reading the story and read an evidence file the run wrote, rendered as five questions with the problems at the top.

Somebody in that thread said what we’ve all done: they asked Claude to summarize last week’s work and got phrases they didn’t understand about their own research. A recap full of strange words is not a review aid. It is one more document to decode, and at 11pm we give it a thumbs-up just to make it go away.

Five questions, one file

So what does a useful review screen look like? The picture is the whole idea. One file, evidence.json, is the single source, and two things read it. A person gets fast answers to five questions: what changed, did checks pass, what is the risk, how do I roll back, and what needs my decision. A machine checks the digest and the exact SHA.

One evidence.json file answers five review questions (what changed, did checks pass, what is the risk, how do I roll back, what needs my decision) and verifies the exact SHA. Human view: 5 of 5 found, 0 ambiguous, 00:54. Machine proof: digest plus exact SHA. Retrieval test, not review.

The timer in the corner is 00:54, with 5 of 5 answers found and 0 ambiguous. That number measures whether the packet is easy to read. It says nothing about whether the change is correct, and the picture says so itself: retrieval test, not review. After the minute, you still open the diff that the risk line points at.

Build the screen from facts

The agent’s last step writes body.json from things it can prove: the changed paths and line counts from git diff --numstat against the base commit, the state of each check it ran, and the one decision it needs from you. It looks like this.

{
  "job_id": "J-1042",
  "objective": "Repair retry documentation and focused test",
  "changes": [{"path": "docs/remote-setup.md", "additions": 1, "deletions": 0}],
  "commands": [
    {"name": "format-check", "state": "passed"},
    {"name": "type-check", "state": "skipped"},
    {"name": "focused-unit-test", "state": "passed"}
  ],
  "risks": [{"severity": "medium", "claim": "Retry wording could conflict with the public support policy"}],
  "decision": "Confirm retry wording matches the public support policy",
  "rollback": "Close the PR and delete branch remote/J-1042"
}
# seal.sh, the agent's last step: stamp the real head from git, then seal
jq --arg h "$(git rev-parse HEAD)" '.head_sha = $h' body.json > stamped.json
jq --arg d "$(jq -cS . stamped.json | shasum -a 256 | cut -d' ' -f1)" \
  '. + {bundle_digest: $d}' stamped.json > evidence.json

# handoff.sh, run by you: bash handoff.sh evidence.json <branch>
set -euo pipefail
ev=$1 branch=$2
want=$(jq -r .bundle_digest "$ev")
got=$(jq -cS 'del(.bundle_digest)' "$ev" | shasum -a 256 | cut -d' ' -f1)
[ "$want" = "$got" ] || { echo "REFUSED: BUNDLE_DIGEST_MISMATCH"; exit 2; }
now=$(git rev-parse "$branch")
[ "$(jq -r .head_sha "$ev")" = "$now" ] || { echo "REFUSED: BRANCH_MOVED to $now"; exit 2; }
jq -r '"\(.job_id): \(.objective)", "Head: \(.head_sha)",
  "1. What changed?", (.changes[] | "   \(.path) +\(.additions)/-\(.deletions)"),
  "2. Did checks pass?", (.commands | sort_by(.state == "passed") | .[] | "   \(.state | ascii_upcase) \(.name)"),
  "3. What is the risk?", (.risks[]? | "   [\(.severity)] \(.claim)"),
  "4. How do I roll back?", "   \(.rollback)",
  "5. What needs my decision?", "   \(.decision)"' "$ev"

What happens if the branch moves while you read? I ran it against a throwaway repo with that exact packet to find out. The screen came back with SKIPPED type-check sitting above both passes, which is the point: a skipped check gets the loudest line on the screen, right at the top of the list. Flipping that one state to “passed” in the file got REFUSED: BUNDLE_DIGEST_MISMATCH, and one more commit on the branch got REFUSED: BRANCH_MOVED. We don’t regenerate a packet automatically when the branch moves, either, because the new commit hasn’t been checked by anything yet.

The server has its own opinion, and you want it too. gh pr checks <branch> --required shows only the required checks, and with --json the GitHub CLI sorts each one into a bucket:

When the —json flag is used, it includes a bucket field, which categorizes the state field into pass, fail, pending, skipping, or cancel.

Skipping has its own bucket there as well. If your screen says passed and the server says skipping, believe the server and send it back.

My rule for big diffs is simple. If the change is too large to judge from the five answers, the packet should say deep review required and I read it at a desk. A fast yes on a diff nobody could read in a minute is exactly the rubber stamp we set out to kill.

Now go build something this weekend!

John Cook

Why trust this? Every youcanbuildthings guide is pulled from a build-tested book: code that ran in production before it was written down.