An autonomous AI dev team for your GitHub repos β plan, review, fix, and ship PRs, on a loop.
"LLMs are exceptionally good at looping until they meet specific goals... Don't tell it what to do, give it success criteria and watch it go." β Andrej Karpathy
Looper turns that idea into a local AI dev team. Register the repos you want it to watch; Looper picks up assigned, labeled issues and runs specialized agents β planner β reviewer β fixer β worker β each looping against its own success criteria until the PR is ready for human merge. GitHub stays the source of truth; Looper handles the spec, review cycle, and implementation in isolated worktrees.
Looper ships two binaries:
looperdβ the background daemon that polls GitHub, runs loops, and manages worktreeslooperβ the CLI for setup, control, inspection, and manual loop starts
Each role is an agent that keeps looping until its exit condition is met β no fixed step counts, just goals.
- π§ Planner β loops until the spec is reviewable. Reads the issue, explores the repo, drafts a spec, critiques it, and revises until the plan is concrete enough to open a spec PR. Done when the spec PR is open and labeled
looper:spec-reviewing. - π Reviewer β loops until the PR meets the bar. Re-reads the PR on every new commit, posts inline threads, and keeps re-reviewing as the fixer pushes changes. Done when no actionable threads remain and the review comes back clean.
- π§ Fixer β loops until reviewer threads are handled. Pulls open review comments, addresses them in the worktree, pushes, and waits for the reviewer's next pass. Ping-pongs with the reviewer until the PR converges. Done when every actionable thread is resolved, or replied to when human input is needed.
- π’ Worker β loops until the PR is ready for merge. Takes the
looper:spec-readyspec PR, implements the spec on top of it, runs checks, and iterates on its own output. Done when checks pass and the PR is ready for human review and merge.
The loops compose: planner hands off to reviewerβfixer, reviewerβfixer hands off to worker, and looperd gates each transition on GitHub labels β so you can pause, intervene, or take over at any boundary.
- π’ Start from an issue, not a prompt. Label an issue
looper:plan, assign it to yourself, and a spec PR shows up. Once it reacheslooper:spec-ready, implementation begins. - π GitHub is the only source of truth. Issues, PRs, labels, reviews, and assignees are the workflow β no external task tracker, no YAML pipeline, no project-specific config. If you can use GitHub, you can drive Looper.
- π°οΈ Many repos, one daemon. Register your projects once β Looper watches them together and runs loops across repos in parallel.
- π³ Parallel-safe by design. Every loop runs in its own git worktree, so agents work across issues and repos without stepping on each other.
- π€ Bring your own agent. Pluggable vendor layer (
opencode,claude-code,codex,cursor-cli) so you're not locked into one model or CLI. - π§° Local, inspectable, stoppable. Daemon on your machine, thin CLI to drive it.
looper ps,looper logs,looper stopβ no hosted control plane.
If you're an AI coding agent (Claude Code, OpenCode, Codex, Cursor, etc.) helping a user set up Looper, fetch and follow the install + configure tutorial in the bundled skill:
https://github.com/nexu-io/looper/blob/main/skills/looper/SKILL.md
It contains a one-shot, step-by-step flow (preflight β install β bootstrap β vendor credentials β verify β first loop) plus a troubleshooting matrix. Confirm destructive steps with the user before running them.
Fast path (macOS darwin-arm64 or Linux linux-amd64):
curl -fsSL https://raw.githubusercontent.com/nexu-io/looper/main/scripts/install.sh | sh
looper bootstrap
looper project add /path/to/your/local/repobootstrap interactively writes your config, installs the managed daemon, and starts looperd. Use --yes only for scripts or other non-interactive installs.
/path/to/your/local/repo means the local git checkout you want Looper to watch β the directory that contains that repo's .git folder, not a GitHub URL. For example:
looper project add ~/src/my-app
# or, from inside the repo:
looper project add .Add each repo you want Looper to watch after bootstrap. Full install, upgrade, uninstall, and from-source instructions: docs/installation.md.
Once looper status succeeds and gh auth status shows an authenticated account, drive loops manually:
# plan a spec from an issue
looper plan --project <id> --issue <num>
# review a PR β one-shot, or keep looping as new commits land
looper review <owner>/<repo>#<pr>
looper review <owner>/<repo>#<pr> --loop
# implement from an issue (reuses planner's spec PR if one exists)
looper work --project <id> --issue <num>Inside a registered repo, --project is usually optional for review and work, and you can drop the <owner>/<repo> prefix on PR refs. Pass them explicitly from outside the repo or when multiple projects could match.
The full workflow β label conventions, assignment rules, how planner / reviewer / fixer / worker hand off β is in docs/users-guide.md.
Want to babysit one pull request β review it, fix review threads, dismiss unreasonable change requests, and keep going until it merges?
The simplest path is one prompt. Paste this into whatever coding agent you already run (Claude Code, Codex, opencode, Gemini, β¦):
Take over this PR until it merges β read https://raw.githubusercontent.com/nexu-io/looper/main/skills/pr-takeover/SKILL.md and follow it.
That points the agent at the pr-takeover skill, which decides β confirming with you when unclear β between two modes:
- Live (default, zero install) β your own session drives the PR with
gh+git. Uses your already-authenticated agent; runs while your session is alive. - Background (unattended) β hands the PR to the
looper takeovercommand below, so thelooperddaemon runs the reviewer + fixer loops on their own and it survives you closing your terminal.
The rest of this section covers the looper takeover command that powers the background mode. Run it from inside the checkout:
# detect the current branch's PR automatically
looper takeover
# or target an explicit PR
looper takeover acme/repo#42takeover is the one-command path that, behind the scenes:
- installs/starts the managed
looperddaemon if it isn't already running; - registers the repository scoped to that single PR β every autonomous discovery loop is disabled, so Looper only touches the PR you named, never the rest of the repo;
- starts a continuous reviewer loop and fixer loop on the PR, which ping-pong until the review comes back clean;
- with
--merge, lets the reviewer enable GitHub auto-merge so the PR merges itself once it's approved and green.
It picks your coding agent automatically when exactly one of claude / codex / opencode is on PATH, prompts when it's ambiguous, and accepts --agent-vendor / --yes for non-interactive (agent-driven) runs:
looper takeover acme/repo#42 --merge --agent-vendor claude-code
looper takeover --yes --agent-vendor codex # fully non-interactiveList and stop takeovers:
looper takeover list # active takeovers + live loop status
looper takeover stop acme/repo#42 # stop this takeover's reviewer + fixer loops
looper takeover stop --allRequirements: git, an authenticated gh, and one supported agent CLI installed locally (the agent runs on your machine with your own credentials).
For someone who doesn't have Looper yet, a single piped command installs the CLI and hands off to takeover. This is what an automation/bot can drop into a PR comment so the author can adopt the PR in one step (run it from inside the repo checkout):
curl -fsSL https://raw.githubusercontent.com/nexu-io/looper/main/scripts/takeover.sh | sh -s -- acme/repo#42Everything after -- is forwarded to looper takeover, so --merge and --agent-vendor work there too.
Looper ships installable agent skills:
looperβ setup, status, config, daemon lifecycle, and troubleshooting guidance.pr-takeoverβ drive a single PR to merge (read review feedback β fix β resolve threads β dismiss unreasonable change requests β merge when approved and green). One skill, two modes: it runs live in your own agent session (gh+git, zero install) or hands off to the backgroundlooper takeoverdaemon, confirming with you when unclear. Works in any agent via one universal prompt β seeskills/pr-takeover/SKILL.md.
npx skills add ./skills/looper
npx skills add ./skills/pr-takeoverOr install directly from GitHub:
npx skills add https://github.com/nexu-io/looper/tree/main/skills/looper
npx skills add https://github.com/nexu-io/looper/tree/main/skills/pr-takeoverSee skills/looper/SKILL.md and skills/pr-takeover/SKILL.md for details.
The four loops above are the conceptual model. Here's the GitHub label state machine looperd actually drives:
issue (looper:plan, assigned)
β
βΌ
planner βββΊ spec PR (looper:spec-reviewing)
β
βΌ
reviewer β fixer
β clean
βΌ
PR labeled looper:spec-ready
β
βΌ
worker
β
βΌ
PR ready for human merge π
Each role runs in its own worktree, coordinated by looperd and gated by labels. The planner opens the spec PR, the reviewer and fixer loop on it until it's clean, and looper:spec-ready is the signal that hands work to the worker β which implements on the same PR rather than opening a new one.
Looper is poll-driven, not webhook-driven: keep looperd running and gh authenticated for the loop to fire. Everything runs locally β no hosted control plane required.
Looper supports two project modes:
network.mode=offβ local-only behavior. Worker still claimslooper:worker-readyIssues assigned to the local GitHub user, Reviewer still claims review requests for the local GitHub user, and anylooper:target:*labels are ignored.network.mode=routedβ multi-Node behavior.loopernetcentralizes webhook ingress and event fan-out, but GitHub remains the authority for work intent.
In Routed mode:
- Coordinator, not
loopernet, mutates GitHub for Issue admission and PR review assignment. looper:worker-readyand GitHub review requests express work intent.- exactly one
looper:target:<node_name>label is the exact-Node authority, and Coordinator writes it last. - the
loopernetCoordinator lease is only a fencing gate for mutation rights; if the lease is stale, Coordinator must stop mutating GitHub. - polling stays enabled as drift recovery if webhook ingress or SSE wakeups are missed; it is not the primary wakeup path.
For setup, identity strategy, recovery steps, and loopernet deployment, see docs/users-guide.md, docs/configuration.md, and docs/loopernet-deployment.md. The formal authority rules live in ADRs 0007 through 0011.
Setup & health
looper bootstrap # first-run setup
looper status # daemon + config health
looper version
looper project list
looper project add /path/to/repoStart loops manually
looper takeover [<owner>/<repo>#<pr>] [--merge] # adopt one PR until it merges
looper plan --project <id> --issue <num>
looper review <owner>/<repo>#<pr> [--loop]
looper work --project <id> --issue <num>
looper loop start --type fixer --pr <owner>/<repo>#<pr>--project can be omitted for plan / work when run from inside a uniquely registered repo; review can also omit the <owner>/<repo> prefix in that case, but loop start --pr always requires <owner>/<repo>#<pr>.
Inspect PRs
looper pr list
looper pr show <owner>/<repo>#<pr>
looper pr status <owner>/<repo>#<pr>Manage running loops
looper ps # list active loops
looper logs <id> --follow # stream logs
looper jump <id> # jump into a loop's worktree
looper stop <id>
looper run reconcile-stale # recover stale running loops after sleep/wakeDaemon control
looper daemon install|start|stop|restart|statusIf looper ps shows stale running work with no live agent after sleep/wake, run looper run reconcile-stale first. looper daemon restart remains a reasonable fallback when you want a full daemon restart.
- Canonical default path:
~/.looper/config.toml - Supported formats:
.toml,.yaml,.yml,.json - Config source selection precedence:
--configβLOOPER_CONFIGβ default-path discovery - All role-specific config lives under
roles.<role>; canonical reviewer behavior lives underroles.reviewer.behavior.* - Loading legacy
~/.looper/config.jsonemits one informational note per process telling users that~/.looper/config.tomlis now the preferred default path agent.vendoris required to run loops (no default)- If
server.authMode=local-token, setserver.localTokenand exportLOOPER_TOKENfor the CLI
Every field, env var, CLI flag, validation rule, and troubleshooting note lives in docs/configuration.md.
From the repo root:
go run ./cmd/looperd
go run ./cmd/looper <args>
go build ./...
go vet ./...
go test ./...Build artifacts go to dist/ and are gitignored β don't edit generated files.
looperdfails fast on invalid config; runtime paths must be writable- The managed daemon binary lives at
~/.looper/bin/looperd - Daemon-managed worktrees live under
~/.looper/worktrees/, grouped by repo and project looper worktree cleanupdry-runs Looper-managed worktree cleanup;--confirmremoves eligible clean terminal worktrees without deleting branches- When
notifications.osascript.enabled=true,osascriptmust resolve on startup - Automation is poll-driven, not webhook-driven β keep
looperdrunning andghinstalled and authenticated for the loop to fire
