Pay for an ultrareview only when the diff earns it: a 45-line gate for claude ultrareview
Each ultrareview costs a free run, then roughly $5 to $25, and takes up to 25 minutes. A short wrapper checks the diff size, refuses repeats and keeps the findings. Ten minutes to set up.

A branch has been open for a week, the diff is 3,000 lines across a dozen files, and it’s Friday afternoon. claude ultrareview is the obvious tool: a fleet of reviewer agents in a cloud sandbox, every finding reproduced before it’s reported. So the command goes in, and 20 minutes later there’s a list of bugs.
Then Monday comes. A one-line fix goes onto the same branch, someone runs it again out of habit, and a second review gets charged for a diff that’s 99.9 percent identical. Or the branch is 11,000 lines and the service refuses it after the confirmation. Or a laptop lid closes at minute 12 and the findings never reach the terminal.
Per the ultrareview docs
, Pro and Max accounts get 3 free runs, once, and they don’t refresh. After that a review typically costs $5 to $25 in usage credits. A run that fails or is stopped early still counts. That’s not much per review, but it’s enough that a habit of running it casually adds up, and it’s a bad deal for a 60-line diff that /code-review handles in seconds.
This Playbook builds a small wrapper, ultra-gate.sh, that sits between the developer and the command. It skips diffs too small to justify a paid review, refuses diffs the service will reject, remembers which exact diff has been reviewed, keeps the findings in a file, and maps the three exit codes to something readable. It’s a 45-line bash script plus a git alias, and it takes about ten minutes.
What the subcommand does, and where it bites
claude ultrareview is the non-interactive form of /code-review ultra. It launches the review, waits for the cloud session to finish and prints the findings to stdout. Progress messages go to stderr, so stdout stays clean for redirection. With no argument it reviews the current branch against the default branch, including uncommitted and staged changes. A PR number or a base branch can be passed instead.
The details that matter for a wrapper:
- Exit code 0 means the review completed, with or without findings. Exit 1 covers a failed launch, a stopped or errored cloud session, a timeout, and an untrusted folder. Exit 130 is Ctrl-C.
- Default timeout is 45 minutes, set with
--timeout <minutes>. - A branch review can include up to 500 changed files and 8,000 changed lines by default. The docs say those values can change, and the refusal message names the ones in effect.
- If the command exits before the findings arrive, they never reach the terminal. Running it again starts a new review, it doesn’t resume the old one, and the new one uses a free run or bills credits.
- In a CI job or any other place where it can’t ask, an untrusted folder exits with
Error: Workspace not trusted.--trust-workspacefixes that for one run, but the flag takes no value, so a PR number or base branch has to come before it. It arrived in Claude Code 2.1.309.
Two of those bullets are the whole case for a wrapper. Exit code 0 doesn’t tell a script whether anything was found, and a retry costs a new review. A script that records what it got, keyed to the exact diff, avoids paying twice for the same answer.
The script
Save this as scripts/ultra-gate.sh in the repository and make it executable.
#!/usr/bin/env bash
# Run `claude ultrareview` only when the diff is big enough to justify the cost,
# small enough for the service to accept, and not already reviewed.
set -uo pipefail
BASE="${1:-origin/main}"
MIN_LINES="${ULTRA_MIN_LINES:-400}"
MAX_FILES="${ULTRA_MAX_FILES:-500}"
MAX_LINES="${ULTRA_MAX_LINES:-8000}"
TIMEOUT_MIN="${ULTRA_TIMEOUT_MIN:-45}"
OUT_DIR="$(git rev-parse --git-dir)/ultrareview"
mkdir -p "$OUT_DIR"
mb="$(git merge-base "$BASE" HEAD)" || { echo "ultra-gate: no merge base with $BASE" >&2; exit 1; }
files=0; lines=0
while read -r add del _; do
[[ "$add" == "-" ]] && continue # binary file
files=$((files + 1)); lines=$((lines + add + del))
done < <(git diff --numstat "$mb")
if (( files == 0 )); then echo "ultra-gate: nothing to review against $BASE"; exit 0; fi
if (( lines < MIN_LINES )); then
echo "ultra-gate: $lines changed lines across $files file(s), under $MIN_LINES. Use /code-review instead."; exit 0
fi
if (( files > MAX_FILES || lines > MAX_LINES )); then
echo "ultra-gate: $files file(s) / $lines lines, over the limits of $MAX_FILES / $MAX_LINES. Split the branch first." >&2; exit 2
fi
key="$(git rev-parse HEAD)-$(git diff "$mb" | sha1sum | cut -c1-12)"
if [[ -s "$OUT_DIR/$key.txt" ]]; then
echo "ultra-gate: this exact diff was already reviewed. Findings in $OUT_DIR/$key.txt"; exit 0
fi
echo "ultra-gate: reviewing $files file(s) / $lines lines against $BASE (15 to 25 minutes, billed after free runs)" >&2
claude ultrareview "$BASE" --timeout "$TIMEOUT_MIN" >"$OUT_DIR/$key.tmp" 2>"$OUT_DIR/$key.log"
rc=$?
case $rc in
0) mv "$OUT_DIR/$key.tmp" "$OUT_DIR/$key.txt"; cat "$OUT_DIR/$key.txt"
echo "ultra-gate: saved to $OUT_DIR/$key.txt" >&2 ;;
130) echo "ultra-gate: interrupted" >&2; rm -f "$OUT_DIR/$key.tmp"; exit 130 ;;
*) echo "ultra-gate: review did not finish (exit $rc). Last log lines:" >&2
tail -n 5 "$OUT_DIR/$key.log" >&2; rm -f "$OUT_DIR/$key.tmp"; exit 1 ;;
esac
Each block does one job. The numstat loop counts changed files and lines from the merge base to the working tree, so uncommitted edits count, as they do for the real command. Binary files show a dash instead of line counts and get skipped in the line total. The three early exits are the cost guard: nothing to review, too small, too big. Too small exits 0 because it isn’t an error, just advice. Too big exits 2 so a caller can tell it apart from a failed review.
The cache key is the HEAD commit plus a short hash of the full diff against the merge base. That means a new commit, or a new uncommitted edit, produces a new key and a new review, while a rerun on an untouched branch finds the saved findings and stops. The files live under the git directory (.git/ultrareview), so nothing needs adding to .gitignore and nothing can be committed by accident.
The --json flag is deliberately not used. It prints the raw bugs.json payload, and the docs don’t publish its schema. A wrapper that parses fields it can’t verify would fail quietly the day they change. The formatted text is written for people, and the script’s job is to get it in front of one.
The 400-line floor is an opinion, not a documented number. A local /code-review finishes in seconds to a few minutes and counts towards normal usage, which is the right tool for small diffs. Raise or lower the floor with ULTRA_MIN_LINES to match the team’s appetite.
Wire it up
chmod +x scripts/ultra-gate.sh
git config alias.ultra '!scripts/ultra-gate.sh'
git fetch origin main
git ultra
The leading ! makes the alias run a shell command, and git runs those from the top of the working tree, so the relative path works from any subdirectory. The fetch matters because the script computes the merge base against origin/main locally. The service itself fetches the base from origin if it isn’t in the clone, but the size check happens before that.
To review against a different base, pass it: git ultra origin/develop. Set the alias in the repository’s local config as above, or use --global if the path is the same everywhere.
Changes that exist only as untracked files are invisible to git diff, so they aren’t counted. Run git add -N path/to/new-file (intent to add) to make a new file show up in the diff without staging its contents.
Show it working
The gate logic can be tested without paying for a single review. Put a stand-in claude first on PATH: a script that records its arguments to a log and exits with whatever code the test asks for.
#!/usr/bin/env bash
echo "$*" >> "$FAKE_CLAUDE_LOG"
echo "progress: launching" >&2
if [[ "${FAKE_CLAUDE_EXIT:-0}" == 0 ]]; then echo "Found 2 verified bugs"; else echo "Error: session errored" >&2; fi
exit "${FAKE_CLAUDE_EXIT:-0}"
Then drive the gate through a throwaway git repository with origin/main set to the base commit: an empty diff, a 120-line diff, a 900-line diff that succeeds, the same diff again, a tweak followed by a failing review, and a limit lowered to force the “too big” path. Run it and it prints:
--- empty diff
ultra-gate: nothing to review against origin/main
exit=0
--- small diff
ultra-gate: 120 changed lines across 1 file(s), under 400. Use /code-review instead.
exit=0
--- big diff, review succeeds
ultra-gate: reviewing 2 file(s) / 1020 lines against origin/main (15 to 25 minutes, billed after free runs)
Found 2 verified bugs
ultra-gate: saved to .git/ultrareview/719bbc8bf8536abae4aafeffefee6ca17f6eee28-d2302201faea.txt
exit=0
--- same diff again
ultra-gate: this exact diff was already reviewed. Findings in .git/ultrareview/719bbc8bf8536abae4aafeffefee6ca17f6eee28-d2302201faea.txt
exit=0
--- review fails
ultra-gate: reviewing 2 file(s) / 1021 lines against origin/main (15 to 25 minutes, billed after free runs)
ultra-gate: review did not finish (exit 1). Last log lines:
progress: launching
Error: session errored
exit=1
--- too large
ultra-gate: 2 file(s) / 1021 lines, over the limits of 500 / 500. Split the branch first.
exit=2
--- claude was called with:
ultrareview origin/main --timeout 45
ultrareview origin/main --timeout 45
The log at the bottom is the useful part: two calls to claude across six scenarios. The empty, small, repeated and oversized cases never reached the paid command. The failed run left no saved findings, so a retry after fixing whatever broke will try again instead of reporting a stale result.
That test uses a stand-in, so it proves the gate and not the real service. Against the installed CLI (Claude Code 2.1.310) in a folder that hasn’t been trusted, the same script exits 1 and the log it keeps reads:
Error: Workspace not trusted. Please run `claude` in <repo> first to review and accept the workspace trust dialog.
No review was launched, so nothing was billed. It shows the failure path with the real binary: the wrapper reported the log’s last lines and exited 1. Run claude once in the repository and accept the trust dialog, and the next git ultra goes through.
What the real review prints for findings is not shown here, because producing it would spend a paid run. The script saves whatever arrives on stdout without interpreting it.
Make it yours
Pull request mode. claude ultrareview 1234 reviews a pull request on github.com and, per the docs, uploads nothing from the machine: the cloud sandbox clones the PR using the GitHub account connected to the Claude account. Branch mode instead bundles the repository and uploads it, with extra handling for files named like credentials, such as .env and *.tfvars. If the repository is sensitive, PR mode is the one to script. The size check can read gh pr view 1234 --json additions,deletions,changedFiles in place of the numstat loop, and the rest of the script stays the same.
Posting to the PR. The --post flag, on Claude Code 2.1.227 or later, posts the finished findings as one plain comment from the developer’s own GitHub account, and it only works on github.com PR targets. It isn’t the default, and it’s worth keeping that way: a wrapper that posts without asking is a wrapper that someone eventually regrets. Add it as an explicit second argument rather than a baked-in default.
CI. A CI job needs --trust-workspace, placed after the target, as in claude ultrareview 1234 --trust-workspace. The bigger obstacle is authentication: the docs say ultrareview needs a claude.ai sign-in, and an API key alone isn’t enough. Sort out how the runner signs in before building anything on top. For automatic reviews on GitHub pull requests with no CLI step, the docs point to the separate Code Review
integration, which has its own spend dials (covered in Claude Code Review bills every push by default
).
Tuning the numbers. The size limits are the service’s, and the docs say they can change, so keep ULTRA_MAX_FILES and ULTRA_MAX_LINES as variables. The refusal message names the values in effect, so if the script’s defaults drift out of date the real command still tells the truth.
What goes wrong
The script can’t tell the developer whether the review found anything. Exit 0 means finished, and the saved file is the only record. Anyone wanting a hard block on findings has to parse the output, and that means either depending on an undocumented format or reading it by eye. The honest position for now is advisory: the gate controls when money is spent, and a person reads the result.
The cache lives in the git directory that `git rev-parse –git-dir` reports. A linked worktree reports its own per-worktree directory, and a separate clone has its own `.git`, so each of those pays once for a diff that another checkout has already reviewed. That’s slightly wasteful and harmless.
A review that is interrupted or times out doesn’t deliver findings, and the docs say a stopped or failed review still uses a free run. The gate can’t prevent that. It can only keep the retry from being automatic, which is why exit 1 prints the log and stops.
Availability is the last limit. Ultrareview isn’t available on Bedrock, Vertex or Foundry, or to organisations with Zero Data Retention or the HIPAA configuration, and CMEK organisations can’t run it. On those setups /code-review ultra falls back to a local review, and it’s worth checking what claude ultrareview does on the same setup before committing the team to the script.
Skip all of this if reviews are rare. A team that runs one ultrareview a month on a risky merge doesn’t need a wrapper. The gate pays for itself when several people can launch reviews on long-lived branches and nobody is watching the credit total.
The first ten minutes
Copy the script into scripts/ultra-gate.sh, run chmod +x on it and add the alias. Run claude once in the repository to accept the trust dialog. Then run git ultra on the branch that’s about to be merged, and check that the byte-for-byte same diff reports “already reviewed” on the second call. For the next change, set ULTRA_MIN_LINES to whatever size the team agrees is worth $5 to $25.