Turn any request into small, verified steps. A bounded 20-pass loop with durable state for GitHub Copilot and any AI agent that supports Agent Skills.
curl -fsSL https://github.com/DUBSOpenHub/looper/releases/download/v1.1.0/quickstart.sh | bashThe installer downloads the pinned v1.1.0 release and checks it against the release's
SHA256SUMSbefore installing anything. See Verify the Download.Then open the GitHub Copilot CLI in any project and say:
looperUsing another AI agent? Install with the GitHub CLI instead:
gh skill install DUBSOpenHub/looper looper@v1.1.0 --agent claude-code --scope userSwap
claude-codefor the agent you use;gh skill install --helplists the supported--agentvalues. See Works With.Requires Bash, a writable project folder, and an AI agent that supports Agent Skills. macOS, Linux, or WSL. GitHub Copilot also needs an active GitHub Copilot subscription.
Looper is a skill in the open Agent Skills format, built for GitHub Copilot, that carries a request all the way to verified completion instead of stopping at a plan or a green subset of tests. It breaks the request into numbered acceptance criteria and small steps, then repeats:
read state β reserve β implement β validate β repair β revalidate β checkpoint
Task state and evidence live on disk. After a context reset, crash, or new session, the agent reconciles that state with the current files before continuing interrupted work.
Long agent runs fail in predictable ways: they lose context, claim success from a partial check, retry the same broken fix forever, or quietly redefine "done." Looper makes those failure modes mechanically hard.
- π’ A hard 20-pass budget. Passes are counted by creating directories, not by trusting memory. There is no reset and no way to configure the limit.
- πΎ Durable, project-local state. Goal, criteria, task graph, progress, and evidence are stored in
.ralph-loop/, or.ralph-loop-NAME/for an independent named loop. - β
Criteria that must not be weakened. Each
AChas a concrete verifier and an expected result. The helper prevents lowering the criteria count; the skill's policy forbids removing or redefining criteria to get green. - π§Ύ Passing needs recorded evidence. Checks run through the helper, which records each command, its output, and its exit code.
close passedandverdictrefuse success without passing run records. Choosing meaningful checks remains the agent's responsibility. - π§ One bounded repair per pass. A pass gets at most one repair batch and one revalidation, and each check runs at most three times per phase. The helper enforces both.
- π§ͺ A mandatory final gate. A separate, read-only final pass re-runs every verifier, covers every acceptance criterion, and must produce the same deliverable snapshot at its start and end before completion can be declared.
- ποΈ Named loops for independent goals. One project can hold several loops, each with its own budget and evidence.
- π Honest stopping. It stops on verified acceptance, a genuine blocker, or exhaustion of the 20 passes, and reports which one.
In GitHub Copilot, or any other agent that has Looper installed, from your project folder:
looper
looper add a --dry-run flag to the deploy script and prove it works
looper resume
looper as docs: refresh the README for the new CLI flags
looper resume docs
looper list
Looper inspects your project instructions and existing changes, writes acceptance criteria and a step plan to .ralph-loop/state.md, then works pass by pass until it is done, blocked, or out of passes.
Use a named loop (looper as NAME: β¦) only for a genuinely independent goal; its state lives in .ralph-loop-NAME/. Loops that edit the same files should not run at the same time, so give each concurrent loop its own git worktree or run them one after another. A named loop is never a way to get more passes for the same goal.
Looper is built for GitHub Copilot and follows the open Agent Skills format, so other agents that support the format can load it too. To run it, an agent needs to read and edit files and run shell commands.
- GitHub Copilot. The GitHub Copilot CLI, the GitHub Copilot app, the GitHub Copilot cloud agent, and agent mode in VS Code, Visual Studio, and JetBrains IDEs support Agent Skills. IDE support depends on your version, and each surface reads skills from its own locations. The one-line installer above targets the GitHub Copilot CLI.
- Other AI agents.
gh skillcan install skills for Claude Code, Cursor, Codex, Gemini CLI, and many more, using the--agentflag shown above.gh skillis in preview, so its flags may change. - Anything else. Point your agent at
skills/looper/SKILL.mdand ask it to follow the instructions.
What is verified. v1.1.0 has 37 helper tests and 8 installer/release-build tests, plus one successful end-to-end task through the GitHub Copilot CLI on macOS: 2 passes and 11 independent acceptance checks. Other agent surfaces have not had equivalent end-to-end testing. See the validation report and its limitations.
.ralph-loop/ # or .ralph-loop-NAME/ for a named loop
format # helper protocol marker
criteria # number of acceptance criteria; can only grow
state.md # goal, criteria, task graph, latest evidence, next action
progress.md # append-only decisions, failures, checkpoints
passes/01..20/
reservation # immutable mode, target, reservation time
runs/001.. # recorded command, cwd, output, exit code, phase, AC IDs
repair # present once the pass has used its one repair batch
result # immutable passed / failed / blocked / interrupted
The skill is called
looper, but the state directory keeps the name.ralph-loop/and theralph-loop-pass-ledger-v1marker so ledgers created before the rename stay resumable.
skills/looper/scripts/pass-ledger.sh enforces reservations, the budget, the repair and retry limits, command timeouts, and the evidence needed to pass. It cannot judge whether a verifier really tests its criterion; the policy in SKILL.md covers that.
Run this happy-path example from a project's real root directory with Looper installed and no existing loop. It assumes slug.py, test_slug.py, and README.md are the complete deliverable set, and the unittest suite verifies AC01. Adapt the files and criteria to your actual task.
LEDGER="$HOME/.copilot/skills/looper/scripts/pass-ledger.sh"
bash "$LEDGER" .ralph-loop init
bash "$LEDGER" .ralph-loop criteria 1 # AC01
bash "$LEDGER" .ralph-loop reserve work S01
bash "$LEDGER" .ralph-loop run 01 --baseline -- python3 -B -m unittest
# Implement the scoped change here.
bash "$LEDGER" .ralph-loop run 01 --ac AC01 --timeout 300 -- python3 -B -m unittest
bash "$LEDGER" .ralph-loop close 01 passed
bash "$LEDGER" .ralph-loop reserve final ALL
bash "$LEDGER" .ralph-loop run 02 --snapshot -- shasum -a 256 slug.py test_slug.py README.md
bash "$LEDGER" .ralph-loop run 02 --ac AC01 -- python3 -B -m unittest
bash "$LEDGER" .ralph-loop run 02 --snapshot -- shasum -a 256 slug.py test_slug.py README.md
bash "$LEDGER" .ralph-loop close 02 passed
bash "$LEDGER" .ralph-loop verdict # complete=yes final=02 criteria=1
bash "$LEDGER" . loops # every loop in this projectA failed baseline is recorded with exit code 7; assess it before editing rather than treating it as a passing check. If initial validation fails, call bash "$LEDGER" .ralph-loop repair 01 once before the repair edits, then rerun the same failing check and the affected regression checks before closing the pass. Do not call repair after a passing check. If revalidation fails, close the pass failed, not passed.
The final snapshots must hash the actual contents of every deliverable, including untracked files and uncommitted changes, and capture relevant inputs and environment versions. git ls-files -s alone only fingerprints the index, not current working-tree contents.
| Exit code | Meaning |
|---|---|
0 |
Success |
2 |
Budget exhausted (20 passes reserved) |
3 |
A pass is already open, or already closed |
4 |
Ledger locked by another writer |
5 |
Invalid or unsafe state (symlinks, corruption, missing ledger) |
6 |
Refused by an evidence gate or rule (for example close passed without passing runs, a second repair, or a fourth run of the same check) |
7 |
run recorded a failing command |
64 |
Invalid usage |
The self-tests use only the Python standard library and create their fixtures inside the skill directory.
cd skills/looper
/bin/bash -n scripts/pass-ledger.sh
shellcheck scripts/pass-ledger.sh
python3 -B scripts/test_pass_ledger.py
cd ../..
python3 -B tests/test_quickstart.py # installer and release-build testsTo exercise the skill itself, install your checkout with ./quickstart.sh and run e2e/run-copilot-e2e.sh. It drives the GitHub Copilot CLI through a small task and then checks the result independently. See VALIDATION.md for the latest recorded run.
Starting with v1.1.0, releases are built by the Release workflow from a protected vX.Y.Z tag and published as immutable GitHub releases with three assets: looper-vX.Y.Z.tar.gz, quickstart.sh, and SHA256SUMS. Both the tarball and the installer carry a GitHub build provenance attestation.
- Checksum (always on). The installer refuses to install unless the tarball matches
SHA256SUMS, and it installs only the four skill files. - Pin a checksum. Set
LOOPER_SHA256to a tarball hash obtained through an independently trusted channel, so a changed file is refused even ifSHA256SUMSchanges with it. - Check provenance. Set
LOOPER_VERIFY_ATTESTATION=1to have the installer rungh attestation verifyagainst this repository's release workflow and tag. - Pick a version.
LOOPER_VERSION=vX.Y.Zinstalls another release. Branch names such asmainare refused.
The one-line installer executes the downloaded installer before it checks the tarball. To verify the installer itself first, use an up-to-date, authenticated GitHub CLI and run this from a separate download directory, not a Looper checkout:
curl -fsSLO https://github.com/DUBSOpenHub/looper/releases/download/v1.1.0/quickstart.sh &&
gh attestation verify quickstart.sh --repo DUBSOpenHub/looper \
--signer-workflow DUBSOpenHub/looper/.github/workflows/release.yml \
--source-ref refs/tags/v1.1.0 &&
LOOPER_VERIFY_ATTESTATION=1 bash quickstart.shSHA256SUMS alone cannot establish trust if both the archive and checksum are compromised. Attestations establish build provenance, not that the code is safe. A compromised trusted source or release workflow can still produce an attested artifact.
Running ./quickstart.sh inside a clone deliberately installs the local checkout instead; release checksum and attestation checks do not apply in that mode.
| Path | Purpose |
|---|---|
skills/looper/SKILL.md |
The skill: execution policy and the final verification gate |
skills/looper/scripts/pass-ledger.sh |
Pass counter, immutable reservations, and evidence gates |
skills/looper/scripts/test_pass_ledger.py |
Behavioral self-tests for the helper |
skills/looper/templates/state.md |
Durable checkpoint and evidence template |
quickstart.sh |
Installs a pinned, checksum-verified release into ~/.copilot/skills/looper/ |
tools/build-release.sh |
Builds the release tarball, installer copy, and SHA256SUMS |
tests/test_quickstart.py |
Installer and release-build tests |
e2e/run-copilot-e2e.sh |
End-to-end run through the GitHub Copilot CLI with hidden acceptance checks |
AGENTS.md |
Contributor instructions, invariants, and validation commands |
SECURITY.md |
Supported versions, private vulnerability reporting, and trust boundaries |
CONTRIBUTING.md |
Development and release workflow |
CHANGELOG.md |
Release history and unreleased changes |
docs/PRD.md |
Original v1.0 requirements with a v1.1 contract update |
docs/ARCH.md |
Original design with v1.1 evidence-gate and release additions |
docs/VALIDATION.md |
Test and gap-score results for the current release |
Do I need GitHub Copilot to use Looper? No. It is built for GitHub Copilot, but any agent that supports Agent Skills can load it. See Works With.
Does Looper run on its own in the background? No. It only runs while an agent session, such as GitHub Copilot, is active. The on-disk state lets the next session resume it.
Can I raise the 20-pass limit? No. The helper has no reset or configurable-limit operation, by design.
Can I run more than one loop in a project?
Yes, for independent goals. Say looper as NAME: <request>; state goes to .ralph-loop-NAME/ with its own 20-pass budget, and looper list shows every loop. Use separate git worktrees if the loops would run at the same time.
Can an agent just mark a pass as passed?
Not through the helper without evidence: close passed exits 6 unless its run records satisfy the gate, and verdict re-checks the final pass. The helper cannot tell whether a test is meaningful, and its local files are not tamper-proof against an agent with write access. See the security trust boundary.
What happens to a v1.0 loop after upgrading?
Its history and spent passes stay intact. Close an open legacy pass failed or interrupted, then reserve new passes for evidence-backed validation within the remaining budget. An old passed result without run records does not satisfy the v1.1 completion gate. Never delete state or reset the budget to upgrade.
Can I rename the skill without losing a running loop? Yes. Renaming the skill never migrates state, resets the budget, or discards history.
Why does the helper say state path must not contain symlinks?
Looper refuses to read or write loop state through a symlink, including a symlinked parent folder, so a link cannot redirect the ledger. On macOS, /tmp is a symlink to /private/tmp, so a project under /tmp is rejected. Start your agent from the project's real path (cd "$(pwd -P)" switches to it) and try again.
See CONTRIBUTING.md. Please report vulnerabilities privately as described in SECURITY.md.