Skip to main content
PR Loop is an open-source agent loop that shepherds your open pull requests. Each time a commit is pushed to a PR, Claude Code — running headless inside a warm Superserve sandbox — reviews the new code against a calibrated rubric, runs your project’s own tests as a verifier, posts one concise review, and escalates risky changes to a human. It proposes; a human merges. It never merges, force-pushes, or edits CI. Everything is self-hosted and yours: your repo, your GitHub identity, your Claude subscription, your sandboxes, your review norms.

How it works

Three roles, and only one of them is a sandbox:
  1. Trigger — a GitHub Actions workflow fires on pull_request events (opened, synchronize, reopened). No idle cron.
  2. Orchestrator — a stateless script from the published @superserve/loops package runs on the CI runner: it finds the repo’s loop sandbox by metadata, runs one tick inside it, then pauses it.
  3. Worker sandbox — a Firecracker microVM booted from the superserve/claude-code template. The repo clone, the review state, and Claude Code all live here, warm between ticks.
The review runs in a sandbox rather than on the CI runner because:
  • Warm checkout. The repo and its dependencies are cloned once, on the first tick. Every later tick resumes the same box and skips setup entirely.
  • Isolation. A PR diff is untrusted code. It is reviewed — and your test suite runs against it — inside an isolated microVM, never on your runner or laptop.
  • ~$0 idle. The box is paused between ticks; you pay for seconds of compute per review, plus your LLM tokens.

Prerequisites

You needWhere to get it
Superserve API key (ss_live_…)console.superserve.ai
A Claude credentialclaude setup-token (Pro/Max/Team/Enterprise subscription, mints a ~1-year token) — or a metered ANTHROPIC_API_KEY
bunbun.sh — only to run the installer
GitHub accessNothing extra — reviews post as github-actions[bot] via the workflow’s built-in token. A PAT or App is opt-in (below).

Install

Run inside the repo you want reviewed:
bunx @superserve/loops add pr-loop
The installer does everything:
  1. Prompts for your Superserve API key (hidden input) and — when the claude CLI is installed — runs claude setup-token for you to mint the long-lived Claude token.
  2. Stores that token as a Superserve secret (claude-oauth) bound to api.anthropic.com — it is swapped in at egress and never enters the sandbox.
  3. Sets SUPERSERVE_API_KEY as a GitHub Actions secret on the repo.
  4. Writes .github/workflows/loop-pr-loop.yml — the only file added to your repo — then commits it (scoped to just that file; anything else you had staged stays staged) and pushes it after you confirm (--yes is the non-interactive consent).
Push a commit to any PR and it is reviewed within seconds.
The push only ever publishes the installer’s own commit. If your branch is already ahead of upstream with unpublished work, the installer refuses to auto-push — and whenever it can’t or won’t push (no upstream, no write access, confirmation declined), it prints the exact commands to run yourself.
The workflow runs the published package (bunx @superserve/loops@stable run pr-loop …) — no loop source is vendored into your repo. @stable is a gated release channel, so loop improvements roll out without you ever editing the file.
For CI or scripted installs, pass credentials via env or flags instead of prompts:
SUPERSERVE_API_KEY= CLAUDE_CODE_OAUTH_TOKEN= \
  bunx @superserve/loops add pr-loop --yes

# preview without changing anything
bunx @superserve/loops add pr-loop --dry-run

Try one tick locally

No install, no repo changes — good for seeing the resolved plan and one live review first:
# resolved plan only, needs no keys
bunx @superserve/loops run pr-loop --repo owner/name --dry-run

# one real review from your machine (the review still runs in a cloud sandbox)
SUPERSERVE_API_KEY=ss_live_… \
CLAUDE_CODE_OAUTH_TOKEN=… \
GITHUB_TOKEN=$(gh auth token) \
  bunx @superserve/loops run pr-loop --repo owner/name --pr 42
Omit --pr to sweep every open PR in one tick, or add --watch=15m to re-tick on an interval.

Where your credentials live

CredentialWhere it livesDoes it enter the sandbox?
Superserve API keyGitHub Actions secretNo — only the orchestrator on the CI runner uses it
Claude tokenSuperserve secret claude-oauthNo — the box sees a stand-in value; the real token is attached at egress, only toward api.anthropic.com
GitHub tokenMinted per run by GitHub ActionsYes, but it is repo-scoped, least-privilege, and expires when the run ends
See Secrets for how egress swapping works. A GitHub PAT (optional, below) gets the same treatment as the Claude token: stored as a Superserve secret, swapped at egress.

Bring your own bot identity

By default reviews post as github-actions[bot] — zero GitHub credentials to create. Two opt-in upgrades:

A custom name — machine-user PAT

Create a dedicated GitHub account (e.g. acme-review-bot) and mint a fine-grained PAT on the target repo with Contents: Read, Pull requests: Read & write, Issues: Read & write. Classic repo-scope tokens are refused — repo includes push and merge rights, which would void the loop’s propose-only guarantee. Then install with:
bunx @superserve/loops add pr-loop --github-token <PAT>
Reviews now post as that account. The PAT is stored as the Superserve secret loop-github-token and swapped at egress. This path is also how one repo’s workflow reviews a different repo.

A name and an avatar — your own GitHub App

A GitHub App gets you the [bot] badge, a profile picture, and short-lived per-repo tokens. The App — and its private key — stay yours, in your own repo’s (or org’s) secrets; nothing is shared.
  1. Create the App: GitHub → Settings → Developer settings → GitHub Apps → New GitHub App. The name becomes the handle (acme-pr-loopacme-pr-loop[bot]). Uncheck the webhook. Permissions: Contents: Read-only, Pull requests: Read & write, Issues: Read & write.
  2. Upload a logo under Display information (this is the avatar), generate a private key, and install the App on the repo you’re reviewing.
  3. Store the App credentials as Actions secrets — repo-level, or org secrets so every repo inherits them:
gh secret set LOOP_APP_ID --body "<your App ID>"
gh secret set LOOP_APP_PRIVATE_KEY < ~/Downloads/your-app.*.private-key.pem
  1. Install with --github-app — the installer writes the App-token workflow for you, no YAML editing:
bunx @superserve/loops add pr-loop --github-app
The generated workflow mints a fresh installation token each run via actions/create-github-app-token, scoped to that one repo and expiring within the hour, and posts reviews as your App. Because the credentials are referenced by secret name, setting LOOP_APP_ID / LOOP_APP_PRIVATE_KEY as org secrets once covers every future repo — install the loop into a new repo and it inherits the identity with no extra token setup.

Make it review your way

These work with the published loop as-is — nothing to fork:
  • Review norms and the merge bar. Each run the loop reads your repo’s CLAUDE.md / AGENTS.md / README.md for the review conventions and what “ready to merge” means in your project. Write your team’s rules there and reviews follow them.
  • The verifier’s checks. The loop runs your project’s own tests, lint, and build — discovered from CLAUDE.md, AGENTS.md, Makefile, or CI config on the default branch. Nothing loop-specific to define.
  • Your own skills. Commit them to your repo at .claude/skills/<name>/SKILL.md. Claude Code runs inside your cloned repo, so it discovers project skills automatically.
Deeper changes — your own rubric, MCP servers, models, tool policy — mean running the loop from source. The loop’s README covers that path.

Rotate, revoke, uninstall

  • Rotate a credential by re-running the installer. add is idempotent: it rotates the existing Superserve secrets in place and rewrites the same workflow file. The Claude token lasts about a year; when it expires, run claude setup-token again and re-run the installer.
  • Revoke independently. Revoke the Claude token in your Claude account, the PAT in GitHub settings, or the Superserve API key in the console — each kills its own half without touching the others.
  • Uninstall by deleting the workflow file, then kill the warm sandbox (console → Sandboxes → the box named pr-loop, or Sandbox.killById) and delete the claude-oauth secret.

Safety model

  • Never merges, force-pushes, or edits .github/workflows. The strongest action it takes is a review plus a ready-to-merge label — kept in bounds by the skill’s rules and, decisively, by the least-privilege token scope below: a contents: read token cannot merge or push, no matter what runs in the sandbox.
  • Prompt-injection firewall. PR content is treated as data, not instructions. The loop refuses instructions embedded in diffs or comments and only runs the project’s own checks, read from the default branch — never commands suggested by the PR.
  • Least privilege. The workflow grants contents: read and pull-requests: write, nothing else. Fork PRs are skipped by default (their token is read-only); review them via the PAT path if you want them covered.
  • Human gates. Security, auth, payments, or core-infra changes — and PRs stuck across several runs — get a needs-human label and an @-mention instead of silent action.
Two cost meters, don’t conflate them: pausing the sandbox makes sandbox compute roughly free between ticks, but LLM tokens are billed separately by Anthropic. A subscription token from claude setup-token keeps ticks off metered API billing.

See also

Source and full install guide

The loop’s code, review rubric, and the step-by-step README — from “just try it” to a branded bot with your own skills.

Secret binding

How credentials are swapped in at egress so they never enter the sandbox.

Claude Code sandboxes

Run Claude Code interactively in a Superserve sandbox.

Sandbox lifecycle

Pause, resume, and the warm-state model the loop is built on.