Looper - Extensible Improvement Loop for Claude Code
Claude Code stops when it thinks it's done. Looper keeps it going until it's
actually done. It's a native plugin that runs your quality checks - build, lint,
tests - every time Claude says "finished," and pushes it back with the failures
if anything is red. The code you get compiles, passes lint, and has green tests,
because Claude kept iterating until those things were true. No external
wrappers, no log scraping - it runs inside Claude Code's own hook system.
A minimal kernel dispatches hook events to packages that define every step of
the loop: what to check, how to score, when to stop. The bundled quality-gates
package reproduces the classic behavior (typecheck, lint, test, coverage gates),
but you can create packages for TDD cycles, security audits, documentation
verification, or anything else.
Install
Quick start
curl -fsSL https://raw.githubusercontent.com/srdjan/looper/main/install.sh | bash
This clones the repo to ~/.claude/plugins/looper, checks that jq and
claude are available, and prints the command to start Claude Code with the
plugin. Or clone manually with
git clone https://github.com/srdjan/looper.git ~/.claude/plugins/looper.
Marketplace (coming soon)
claude plugin install looper@claude-plugins-official
Requirements: jq (brew install jq on macOS, apt install jq on
Debian/Ubuntu). Bundled shell packages only need jq. SDK-authored packages
declare their own runtime in package.json; the current supported value is
deno. If a configured package requires a missing runtime, Looper fails closed
and blocks edit tools until the runtime is installed or the package is removed
from .claude/looper.json.
What Happens on First Run
- Start
claude in any project.
- Looper inspects repo truth - stack markers,
package.json scripts, lockfiles,
tool configs - and writes .claude/looper.json with matching gates.
- A bootstrap confidence summary shows what was verified versus inferred.
- Ask Claude for a code change.
- After Claude finishes, the Stop hook runs your quality gates.
- If any required gate fails, Claude gets the failure output and tries again.
- The loop ends when all gates pass or the iteration budget is reached.
Run /looper:bootstrap to verify your setup. Run /looper:doctor to compare
your config against the repo's actual tooling. Run /looper:looper-config for
guided fine-tuning.
Disable / Uninstall
claude plugin disable looper@claude-plugins-official # stop hooks from firing
claude plugin uninstall looper@claude-plugins-official # remove the plugin entirely
For source installs, remove the plugin directory:
bash ~/.claude/plugins/looper/uninstall.sh
Project config (.claude/looper.json) and state (.claude/state/) are
preserved unless explicitly cleaned up during uninstall.
Usage
claude
> implement a user avatar upload endpoint with validation
# Claude works. After each response, the kernel dispatches to package stop
# handlers. If any package is unsatisfied, Claude gets another turn with
# feedback. When all packages are satisfied (or budget is reached), Claude stops.
Configuration
Edit .claude/looper.json:
{
"max_iterations": 10,
"packages": ["quality-gates"],
"quality-gates": {
"gates": [
{
"name": "typecheck",
"command": "npx tsc --noEmit --pretty false",
"weight": 30,
"skip_if_missing": "tsconfig.json"
},
{
"name": "lint",
"command": "npx eslint .",
"weight": 20,
"skip_if_missing": "node_modules/.bin/eslint"
},
{ "name": "test", "command": "npm test", "weight": 30 },
{
"name": "coverage",
"command": "$LOOPER_PKG_DIR/lib/check-coverage.sh",
"weight": 20,
"required": false
}
],
"checks": [
{
"name": "format",
"command": "npx prettier --check {file}",
"fix": "npx prettier --write {file}",
"pattern": "*.ts,*.tsx",
"skip_if_missing": "node_modules/.bin/prettier"
}
]
}
}
Top-level keys max_iterations and packages are kernel config. Everything
under a package name key is that package's config.
Gate Options