looply

for people who already have a coding agent

Leave it running.
Keep only what
holds up.

Your agent writes the code — it is good at that. looply decides what it works on, refuses the paths you named, runs your checks, and has a second agent prove the change before a line of it is kept.

$npx looply-cli init Read the docs

works with the agent you already use · your code never leaves your machine

$ looply run --hours 4
syncstreaming to your phone · prj_8xhRgkVhqbD
round1 · serve() turns every readFile failure into a bare 404
gatetypecheck pass · jest 31 tests pass
proveproven (0.86) by a second agent
commitkept · 4f1c2ab
round2 · block() has no default case
gatetypecheck pass · jest 32 tests pass
proverejected — the new branch is never reachable
discarded · requeued with the reason

001 run.started

looply does not write your code

Claude Code, or whichever agent you already use, does that — and it is good at it. What it is not good at is deciding what to work on next, stopping at the edge of your schema, or telling you honestly whether the change it just made does what was asked.

looply is the harness around it. It holds the queue, the rails, the checks, the second opinion and the record. The agent reports its progress back through the same CLI you use, so what you read on your phone is what actually happened, not a summary of it.

the agent

  • reads the codebase
  • writes the change
  • writes the test
  • reports what it did

looply

  • picks the task, and proves the premise still holds
  • holds the rails and refuses the paths you named
  • runs your checks, then a second agent over the diff
  • keeps or discards, and records why

you

  • set the rails once
  • answer the few real questions
  • approve what ships

002 round.picked

What one round is

The unit of work, and the only thing that produces a commit. Step through it.

who does this · looply

The top item whose premise still holds. If the code moved since the item was written, it goes back through verification before anything is spent on it — an item describing a bug somebody already fixed is worse than no item at all.

$ looply run --hours 4
syncstreaming to looply-api · prj_8xhRgkVhqbD
round1 · picked itm_4a91 (attempt 1 of 3)
serve() turns every fs.readFile failure into a bare 404
evidence · scripts/serve.js:41
verifyconfirmed — the premise still holds at 8a3b9e9

who does this · the agent

Your coding agent does this part, and looply does not help. It starts at the file and line the item already located, which is most of what the verification pass pays for. One concern, a test with it, and no git — the runner owns branching and discarding.

phaseimplementing · claude -p (prompt on stdin)
scope · ** · never: package-lock.json, .looply/
2 files touched, 1 test added
agentimplemented — readFile errors now split 404 from 500 and log

who does this · looply

Your own checks, in the order you wrote them, cheapest first and stopping at the first failure. This is the first of the two keys. On its own it proves the change compiles and the suite still passes — which is not the same as proving the change did what was asked.

gatetypecheck · 4.1s · pass
gatejest · 31 tests · 6.8s · pass
gategreen — 2 of 2 steps ran
green is not a reason to keep anything. key two follows.

who does this · the agent

A second agent reads the diff against the item. It did not write the code and it is never shown the first agent’s account of what it did — that exclusion is enforced in the code, because a prover shown the story grades the story. It answers proven, rejected or partial.

provesecond agent · diff 61 lines · sees the item, not the note
checka readFile ENOENT still answers 404 · held
checkany other errno answers 500 and is logged · held
proveproven (0.86) — both behaviours are visible in the diff

who does this · looply

Both keys turned, so the work is committed to the run branch with a trailer recording which checks actually ran. Had either failed, the tree would be thrown away and the item requeued carrying the reason — so the next attempt starts knowing what went wrong with the last one.

commitkept · 4f1c2ab on looply/run-20260816
Checks: typecheck pass 4.1s · jest pass 6.8s
Proof: proven (0.86) by a second agent
round2 · picked itm_7c03
askexemption requested · src/html.ts is railed
moved on to itm_92f1 rather than idling on your money

003 proof.result

the part that matters

A passing build is not proof

Anything can make the tests go green. Every change looply keeps has been read by a second agent that did not write it, shown the task and the diff but not the reasoning behind them, and asked one question: does this do what was asked?

Key one · your checks

Typecheck, tests, build — yours, in the order you wrote them, cheapest first. This proves the change compiles and the suite still passes.

Key two · a second agent

A different agent reads the diff against the task. It did not write the code and never sees the first agent’s account of it. It answers proven, rejected or partial.

both checks green, rejected anyway — that is the job

Both have to agree. The checks pass and the reader says yes, or the work is thrown away and the task goes back in the queue carrying the reason it failed. That is why the number of changes rejected is worth reading — a prover that never rejects anything is not checking.

004 run.ended

Where the design came from

An earlier version of this harness ran three unattended sessions against a production codebase — 166 rounds, about fourteen hours. Every round shipped a test, no dependencies were added, and no forbidden path was ever touched.

It also went 166 for 166. Nothing was ever rejected, because nothing could be: the checks it ran were the same checks the agent had already run before finishing. That is the hole the second reader exists to close, and it is why looply counts proven rounds rather than green ones.

166rounds, unattended
2,226tests written
0rejected — the problem

005 round.phase

What the harness actually does

Your code never leaves your machine

The agent runs where your code already is. The server carries task titles, file paths and events — not source, not diffs, not credentials, not even where the repository sits on disk. If it disappears, the loop keeps working and says it lost the connection rather than going quiet.

Rails you set, and a door only you open

Name the paths the agent must never touch: schema, migrations, auth, anything that moves money. looply reports what it finds there and refuses the edit. A task that genuinely needs one becomes a question, for that one file, once.

It asks instead of guessing

When the loop reaches something only you can settle, the question carries a default and a deadline — and it moves to another task while it waits rather than idling on your money.

The agent reports through the CLI

Progress, findings and blockers all go through the same commands you use, so the ledger is the agent’s own account of its work, timestamped and append-only, not something reconstructed afterwards.

Nothing ships without you

Work lands on a branch, grouped for review rather than as a hundred loose commits. Undoing a change files a new task describing what was wrong with it, so the objection is never lost.

The queue is the product

No task is picked until it has been confirmed against the code as it stands — an item describing a bug somebody already fixed is worse than no item at all. When the loop writes its own tasks it caps how many near-identical chores it may queue.

006 alert

What it is not

Four things worth knowing before you install it.

  • a coding agent. It drives the one you already use, and is worth nothing without it.
  • a replacement for review. It narrows what you review and shows its working; you still decide what ships.
  • free. Every round is agent time, and a check that rejects work has still been paid for.
  • a fit for a codebase with no tests. Without checks of your own there is nothing for the first key to turn.

007 question.asked

Get looply

The CLI is the product. The app is how you watch it from somewhere else.

the CLI

$ npx looply-cli init # read the repo, ask the few things it cannot infer
$ npx looply-cli doctor # run every check once — no agent calls, no cost
$ npx looply-cli scan # fill the queue with findings tied to a file and a line
$ npx looply-cli verify # confirm each finding against the code as it stands
$ npx looply-cli run --hours 4 # work the queue, and tell you what it did

the app

Download on theApp Store Get it onGoogle Play

Neither badge is live yet — the app is in review. looply runs without it: pairing a phone is optional, and everything the loop does happens on your machine either way.