Loops
A loop holds one piece of work to a written brief: partyline runs your checks on it, has other models review it, and sends it back until the checks pass and no reviewer has an open P1.
$ ptln loop start --brief brief.md --checks "make test"A session runs that command, not you. Tell a Claude, Codex or Gemini session running in partyline
"use a partyline loop for this"; its session context points it to ptln loop guide, which prints
the workflow, the brief template and the report template.
ptln help lists ptln loop under Loops; ptln loop --help prints its usage. Start with ptln loop guide.
Loop or batch
| Built by | Started with | |
|---|---|---|
| Loop (a single run) | the session that started it | ptln loop start --brief <file> --checks "<cmd>" |
| Batch (two or more ordered steps) | builders partyline starts, one step after another on one branch | ptln loop batch start --brief <step1> --brief <step2> --checks "<cmd>" |
Repeat --checks for each command. A check containing a newline or other control character is
refused; give each command as its own --checks.
Single runs can be started from Claude and Codex sessions. Gemini sessions can start batches but not single runs, because partyline cannot recognise Gemini's idle input box.
The brief
A brief is Markdown, titled # <title>, with these sections. Each is required and must not be
empty.
| Section | Holds |
|---|---|
## Goal | what the user will be able to do, in their terms |
## Decisions | what was decided, each with its reason |
## Constraints | what must not change; interfaces others depend on |
## Out of scope | what this run will not do |
## Acceptance | one line each: run: <command> must exit 0, file: <path> must exist |
## Verification | for each acceptance item, the check that proves it |
## Unknowns | open questions, not assumptions; "None" if there are none |
A brief with a missing section, no run: or file: line under Acceptance, or control characters
other than newline and tab is refused. A brief can be revised three times before it is approved;
after that the loop fails.
Where a loop can run
| Rule | What happens otherwise |
|---|---|
| Start it inside the git repository | not in a git repository |
| One loop per repository, counting its worktrees | loop <id> is already running in this repository … one per repository, including its worktrees |
| Start it from a Claude, Codex or Gemini session running in partyline | refused: the process has no session identity |
Loops in different repositories run in parallel.
Rounds
- Approval. The brief and checks wait for approval (below). A batch first goes to the reviewers, who read its briefs as a set; a batch with open P1s goes back to its session to revise.
- Baseline. Partyline runs the checks before any work, so checks that already fail do not count against the loop.
- Build. The session (or, in a batch, a builder) does the work, writes a report and runs
ptln loop ready <id> --report <file>. - Checks. Partyline runs the checks and the brief's acceptance lines. A check that newly fails, or any acceptance line that fails, sends the work back without a review.
- Review. Each reviewer reads the brief, the report and the diff, read-only, and returns findings. A finding whose quoted code is not in the file it names is dropped.
- Result. Any P1 sends the work back to step 3. No new failure and no open P1 ends the loop.
The report needs these sections: Evidence, Hardest decision, Rejected alternatives, Least confident, What an excellent reviewer would criticise.
| Priority | Meaning | Blocks the loop |
|---|---|---|
| P1 | must be fixed before merge: wrong behaviour, data loss, a security hole, a broken build or test | yes |
| P2 | should be fixed: a real defect with limited impact, a missing test for real behaviour | no |
| P3 | worth doing: clarity, small simplifications | no |
P2 and P3 findings are passed on with the result, for the PR description.
A loop has six rounds; each ready uses one, whether the checks or the review sent it back. A loop
that uses all six, or submits work identical to the previous round's, fails, and you decide what
happens next.
A review that is missing a reviewer pauses instead of passing. A reviewer that hit a usage limit
resumes by itself after the limit resets; ptln loop resume <id> runs a paused review again. Checks
that cannot run (for example a blocked .envrc) also pause the loop rather than counting as a
failure.
Disputes
The session disputes a P1 it believes is wrong:
ptln loop dispute <id> <finding> --reason "<evidence>"A session never rules on its own dispute. Who rules depends on the Decisions setting:
| Decisions | Single run | Batch step |
|---|---|---|
| loops decide (default) | a model that did not build the work rules at once: the arbiter if one is set, else reviewer 1 | deferred to the end of the batch, then ruled the same way; the step carries on |
| ask me, disputes: ask me | you rule in the approval popup | deferred to your review at the end of the batch; the step carries on |
| ask me, disputes: let an AI decide | you rule in the approval popup | the arbiter rules; below 0.8 confidence, or with no valid answer, it is deferred to you |
When a loop decides for itself, the model reads the work read-only with the session's reason. Its ruling stands whatever its confidence. If it gives no valid answer, the finding stands and the work is fixed.
A P1 that was dismissed or deferred is not raised again in later rounds.
Jev
Jev (typesafe.ai) gives an outside estimate of whether a disputed finding is right. It is optional and advisory: it does not read the code, and the model ruling on the dispute is told to weigh its estimate and decide from the code.
With no key saved there is no Jev. With a key, when a loop decides a dispute, partyline sends Jev the brief (up to 6,000 characters), the finding and the session's reason, and passes the returned probability to the ruling model. Jev is skipped on any error: no credits, a revoked key, a rate limit, a 15-second timeout. The dispute goes on without it. Jev is used only when loops decide; with "ask me" it is not called.
Decisions
Loops decide by default: nothing waits for you. A brief or batch waiting for approval is approved, and disputes are ruled as above.
Switch Decisions to "ask me" in the loop settings to bring approvals back. Then ‼ on a tab
and "N to approve" on the status bar show when something waits; ctrl-\ a opens the approval
popup, where approving asks you to type the four-digit code it shows. A session must never approve
or operate that popup.
Loop settings
ctrl-\ , opens the loop settings; , in the Loops popup does the same. Every change is saved at
once to ~/.partyline/settings.json, or refused with the reason.
| Row | Choice |
|---|---|
| Builder | the engine, model and effort that build batch steps; b adds a backup, x removes one |
| Reviewer 1, 2, … | engine, model and effort for each reviewer; b adds a backup; + Add a reviewer adds a slot |
| Failover | on: switch to the next backup at a usage limit. Off: the review records the limit and fails |
| Quality | the standard every prompt carries: built in, or the full path of a plain-text file under 64 KB |
| Decisions | loops decide (default), or ask me |
| Disputes | with ask me only: ask me, or let an AI decide |
| Arbiter | engine, model and effort of the model that rules on disputes; with loops decide, reviewer 1 when unset |
| Jev key | optional; ⏎ pastes a key, x removes it |
Builders, reviewers and the arbiter are Claude or Codex. Claude offers Fable, Opus, Sonnet and Haiku
with efforts low to max; Codex offers the models in its own ~/.codex/models_cache.json.
No loop runs until you have chosen a builder and at least one reviewer (and the arbiter, when disputes go to it), each with a model and an effort: partyline does not choose them for you, because both affect token use. A loop started before then is saved, the settings open on your screen, and the loop carries on once they are chosen.
A new batch copies the settings, including the quality standard's text, so a later change does not
change a batch already approved. Decisions is the exception: it is read each time a decision is due,
so changing it applies to loops already running. --config <file> or --review claude,codex
overrides them for one loop or batch. A config file is JSON:
{"builder": ["claude:opus:high", "codex:gpt-5:medium"],
"reviewers": [["codex:gpt-5:high", "claude:sonnet:high"], ["claude:opus:max"]],
"failover": true}Each reviewer slot reviews once, trying its models in order when one hits a usage, rate or capacity
limit. A limited model is skipped until its reset, or for 12 hours when no reset is given; limits are
kept in ~/.partyline/limits.json.
The Jev key is kept in ~/.partyline/jev-key, readable only by you.
Batches
A batch runs on the branch checked out when it is approved; with no branch checked out (a detached
HEAD), approval is refused. Each step is built by a builder partyline starts (a contractor, listed on
the Loops popup's Contractors tab), then checked and reviewed like a single run. Partyline commits
each step that passes, authored as <engine> <model> via partyline and leaving memory/ as it was
at HEAD, and starts the next. When the last step passes, any deferred findings are put to you.
ptln loop batch status <id> summarises a batch: each step's state and rounds, its commit range,
its report, and which model reviewed each round.
What partyline does to your repository
Partyline commits batch steps that pass, in the batch's own checkout. It never pushes, merges or
opens a pull request. For a single run, the session is told to commit and open the PR itself, and
to record it with ptln loop pr <id> <url> so the Loops board shows it and its CI.
Builders
A builder runs with your own setup: your engine configuration, your CLAUDE.md or AGENTS.md
files, your tools, MCP servers and credentials. Two things are blocked:
| Guard | How |
|---|---|
| cannot push, merge or open a pull request | git push is rewritten to an address git cannot open; gh runs with no account; GitHub tokens are removed from its environment |
cannot change ~/.partyline, where approvals and rulings live | Claude builders: permission deny rules and the Bash sandbox block reading and writing it. Codex builders: the workspace-write sandbox limits writes to the checkout and temp |
Reviewers and the arbiter read a snapshot of the work read-only: Claude with only Read, Glob and Grep
and no MCP servers, Codex in its read-only sandbox without your config or the repository's
AGENTS.md.
The Loops board
ctrl-\ l opens the Loops popup; ptln loop tab shows the same board full-screen. The board has
five columns, in the order work moves:
| Column | Holds |
|---|---|
| Needs you | a brief waiting for approval, or a disputed finding waiting for a ruling. When loops decide, cards pass through here while the decision is made |
| Planned | batch steps not started yet |
| In progress | building, or revising the brief |
| In review | baseline checks, a round's checks and reviews, a batch's review, or paused |
| Done | finished, failed or stopped; listed for seven days |
| Key | Action |
|---|---|
← → · ↑ ↓ (or h l · j k) | move between columns · cards |
⏎ | open a card's details: who is working on it and their last action, its token use, its rounds and findings; on a building or reviewing card, select its contractor |
a | approve a card that needs you |
s | stop the selected run, after confirmation |
d | delete the card's loop, or its whole batch; press d again to confirm |
r | cycle the repository filter: all repositories, then each in turn |
, | loop settings |
tab | switch between Board and Contractors |
esc · q | close |
Delete a loop
$ ptln loop delete <id>Stops the loop if it is still running, stops its builder, reviewers and arbiter, and removes its
records for good: it leaves the board and cannot be resumed. A batch step, or a batch id, deletes
the whole batch. The command does not ask for confirmation; d on a card does.
Commands
| Command | Does what |
|---|---|
ptln loop guide | the workflow for the calling session's engine |
ptln loop start --brief <file> --checks "<cmd>" | start a single run (run by the session) |
ptln loop batch start --brief <file> --brief <file> ... --checks "<cmd>" | start a batch, with one approval for every step (run by the session) |
ptln loop ready <id> --report <file> | the work is done; partyline checks and reviews it |
ptln loop dispute <id> <finding> --reason "..." | dispute a P1 |
ptln loop brief <id> --file <file> | revise a single run's brief |
ptln loop batch revise <id> --brief <file> ... | revise a batch after its review or a rejection |
ptln loop batch next <id> · batch status <id> | start a batch's next step · summarise the batch |
ptln loop listen <id> · inbox <id> | wait for results (a Claude background task) · print the state and waiting messages |
ptln loop status [<id>] | every loop, or one |
ptln loop resume <id> | run a paused review again |
ptln loop pr <id> <url-or-number> | record the PR the session opened |
ptln loop delete <id> | stop and remove a loop or its batch |
ptln loop tab [--contractor <id>] | the Loops board full-screen |
ptln loop review [--by claude,codex] [--base <ref>] | a one-off review of the working tree against <ref>, with no loop |
A card's details total the tokens each model used, by role (builder, reviewer, brief reviewer, arbiter, decider): fresh tokens (input, cache writes and output) and cost, with cache reads listed apart. Codex reports no cost, so its rows show tokens only. A building card shows the builder's last command instead of the note set when it started.
Loop records live under ~/.partyline/loops/, outside the repository, so the session being reviewed
cannot edit them.