/jeffy is a slash command, but Claude Code can take one from the shell: claude -p "/jeffy 10" runs a full round headless and exits when the round ends. Every receipt from ryu onward was produced that way, unattended, with a shell loop supplying the rounds. Nothing in the engine changes; the loop cannot tell whether a person typed the command.
Setup, once.
- Install Jeffy as in the Quick Install and sign in to Claude Code once interactively (
claudethen/login); the headless form reuses that session. - Clone the target and make sure the tree is clean and on a branch you are willing to see commits on. The loop checkpoints every iteration as a commit, and its pre-flight asks what to do about uncommitted work - a question a headless session never answers, so the round ends with nothing done.
- Decide the budget before the first round and write it down: rounds and iterations per round. Below 10 iterations a round rarely reaches its own gate; narrow single-purpose libraries in the receipts converged in 10 to 20 iterations, wide surfaces (30+ inventory rows) took 40 or more.
- Pass
--permission-mode bypassPermissions. A headless session has nobody to answer a permission prompt, so without it the round stalls silently at the first tool call. Run the session in a container that mounts the target and nothing else, read the clone's .claude/ before the first round, and see SECURITY.md: under -p, hooks committed in a repository's .claude/settings.json run without a trust dialog.
Two targets from the receipts, at their current heads rather than the pins they were run at:
git clone https://github.com/dtolnay/itoa.git ~/targets/itoa # Rust, converged in 2 rounds of 10
git clone https://github.com/ljharb/qs.git ~/targets/qs # JavaScript, 3 rounds of 10 declaredLinux / macOS / WSL
#!/usr/bin/env bash
# Run ROUNDS rounds of ITERS iterations against TARGET; stop early at convergence.
set -euo pipefail
TARGET=~/targets/itoa
ROUNDS=3
ITERS=10
# Outside the tree: an untracked log would stop pre-flight, and git add -A would commit it.
LOG="${TMPDIR:-/tmp}/jeffy-$(basename "$TARGET").log"
# A Converged line can sit in BACKLOG.md after the hook refused it, so only a new accepted record counts.
accepted() { cat .jeffy/metrics/*.jsonl 2>/dev/null | grep -c '"verdict":"accepted"' || true; }
cd "$TARGET"
for r in $(seq 1 "$ROUNDS"); do
before=$(git rev-parse HEAD); a0=$(accepted)
claude -p "/jeffy $ITERS" --permission-mode bypassPermissions >> "$LOG" 2>&1
# A round that made no checkpoint commit almost always hit a pre-flight
# question nobody answered. Stop rather than burn the remaining rounds.
[ "$before" != "$(git rev-parse HEAD)" ] || { echo "round $r: no progress, stopping"; exit 1; }
[ "$(accepted)" -gt "$a0" ] && { echo "converged in round $r"; exit 0; }
done
echo "budget spent: $ROUNDS rounds of $ITERS, not converged"Two rounds of 15 instead: ROUNDS=2 ITERS=15. A single /jeffy 10 is ROUNDS=1. To leave it running after you log out, put the script under nohup, setsid -f, or a systemd-run --user unit; the receipts used the last, with a memory ceiling so a runaway test binary cannot take the host with it.
Windows PowerShell
# Run $Rounds rounds of $Iters iterations against $Target; stop early at convergence.
$Target = "$HOME\targets\itoa"
$Rounds = 3
$Iters = 10
# Outside the tree: an untracked log would stop pre-flight, and git add -A would commit it.
$Log = Join-Path $env:TEMP "jeffy-$(Split-Path $Target -Leaf).log"
# A Converged line can sit in BACKLOG.md after the hook refused it, so only a new accepted record counts.
function Get-Accepted { @(Select-String -Path .jeffy\metrics\*.jsonl -Pattern '"verdict":"accepted"' -ErrorAction SilentlyContinue).Count }
Set-Location $Target
for ($r = 1; $r -le $Rounds; $r++) {
$before = git rev-parse HEAD; $a0 = Get-Accepted
claude -p "/jeffy $Iters" --permission-mode bypassPermissions 2>&1 | Add-Content $Log
if ($before -eq (git rev-parse HEAD)) { Write-Host "round $r: no progress, stopping"; exit 1 }
if ((Get-Accepted) -gt $a0) { Write-Host "converged in round $r"; exit 0 }
}
Write-Host "budget spent: $Rounds rounds of $Iters, not converged"What to read afterwards. JOURNAL.md has one entry per iteration; BACKLOG.md ends with a Converged: line naming the commit if the run declared, and holds the open findings if it did not; .jeffy/evaluator/ holds every gate verdict with the commands it ran. The log file is the raw session transcript and is only interesting when a round made no progress.
Note
Rounds are separate sessions on purpose. Each new session re-reads the tree cold, which is what makes the second round's audit independent of the first round's beliefs. Why that matters.