Open source · Self-hosted · Beta

AI wrote the PR.
You still have to review it.

ReviewStage drafts your review from the real diff, on your own Claude plan, and stages every finding privately. You pick what reaches GitHub, edit it, and post it under your own name. Nothing posts until you click.

git clone https://github.com/Wimukti/reviewstage && cd reviewstage && cp .env.example .env && docker compose up -d

Docker Compose, then http://localhost:8899. Needs a Claude Pro, Max, Team or Enterprise plan for the reviewer who runs it.

reviewstage · acme/payments #482 · live 1 / 6
ReviewStage APP 9:41

@you was requested to review #482

Refund flow: retry on gateway timeout
acme/payments · +412 −38 · 9 files
Open in ReviewStage
Effort
Quick Standard auto-suggested Deep
Model
Default Opus Sonnet Haiku
Focus optional
check idempotency on retries
billed to your plan · ~12 min Start review
Drafting · standard · sonnet worktree rs-482
  1. 00:02 checked out worktree
  2. 00:05 reading 9 files
  3. 00:41 walking critical path: payments/refunds/**
  4. 03:12 6 findings
6 findings staged private draft
  1. high Retry can refund twice on a timed-out capture critical path
    A gateway timeout is not a failure; the first attempt may have succeeded.payments/refunds/retry.ts:88
  2. high Idempotency key is regenerated on every retry
    Each attempt looks new to the gateway, so its dedupe never fires.payments/refunds/client.ts:41
  3. medium Backoff has no jitter
    Synchronised retries after an outage spike the gateway at once.payments/refunds/retry.ts:112
  4. medium Timeout error is swallowed into a generic 500
    Ops cannot tell a slow gateway from a bug.payments/api/refund.ts:57
  5. medium Test covers the happy path only
    No case for timed out, then succeeded.payments/refunds/retry.test.ts:19
  6. low RETRY_LIMIT is a magic number
    Three lives in two files; name it once.payments/refunds/retry.ts:9
6 of 6 selected · COMMENT review Post 6 as you
you commented · 4 comments COMMENT
  • retry.ts:88 Retry can refund twice on a timed-out charge
  • client.ts:41 Idempotency key is regenerated on every retry
  • refund.ts:57 Timeout error is swallowed into a generic 500
  • retry.ts:9 RETRY_LIMIT is a magic number
Approval is a separate click. Approve
Posted as @you — COMMENT review

Someone asks for your review. Nothing has run yet.

  • Open source (MIT)
  • Self-hosted
  • Human-gated
  • Runs on your Claude subscription
  • Never posts as a bot

The gate

Nothing posts until you click

The review step has no GitHub write path at all. It reads the diff and produces a file the dashboard renders. Every write to GitHub is a separate, deliberate click by a signed-in person, using that person's own token.

Comment-only, by construction.

A wrong nit costs a reply. A wrong approval ships a bug under a real person's name. So the two are different buttons, and the agent can press neither.

  • Comment-only. Posting is always a plain COMMENT review. ReviewStage never requests changes and never blocks a merge; the agent's verdict is shown to you as an assessment, nothing more.
  • Approval is its own click, pre-filled with LGTM plus a checklist of the blocker and should-fix findings, editable before it goes.
  • Every finding's file and line is validated against the actual diff before posting, so GitHub can never reject the whole review because one anchor pointed outside it.
  • A failed GitHub read never degrades into a bad post: the fetch checks the response shape, retries once, and refuses on anything odd.
reviewstage · #482 · post 6 findings
  • blockerRefund can be issued twice on a timed-out capture
    payments/refunds/retry.ts:88
  • should-fixIdempotency key is regenerated on every retry
    payments/refunds/client.ts:41
  • should-fixBackoff has no jitter
    payments/refunds/retry.ts:112
  • should-fixTimeout error is swallowed into a generic 500
    payments/api/refund.ts:57
  • nitTest covers the happy path only
    payments/refunds/retry.test.ts:19
  • nitRETRY_LIMIT is a magic number
    payments/refunds/retry.ts:9
4 of 6 selected · comment review · anchors validated against the diff Post 4 as you
Approveseparate click

LGTM — checked the blocker and should-fix items below before approving.
☐ Refund can be issued twice on a timed-out capture
☐ Idempotency key is regenerated on every retry

Available once your comments are posted. Approve

The staging area

A review is a staging area

Findings arrive as cards, not as comments. You decide which ones deserve your name on them, reword the ones that are almost right, and drop the rest without anyone seeing.

Your name, your call.

The agent writes for a person deciding from its text alone, so the prose has to be readable, and the findings have to be few and confident. What you drop is recorded, and it stops coming back.

  • Tick or untick each finding. Edit the body inline with a markdown preview; the original is kept so the learnings loop knows what you changed.
  • Each card leads with a plain title and why it matters; the technical detail is collapsed underneath.
  • Explain simply: one click rewrites a finding in plain words and adds how to verify it, on your own Claude account.
  • Findings can carry a GitHub suggestion block, so the author gets a one-click Apply on the exact replacement.
  • The review is flagged stale when the author pushes new commits. It is never re-run for you; you choose when.
  • Re-run at any effort or focus. Every earlier run stays in history and can be opened read-only.
finding · should-fix · src/orders/cutoff.ts:142 stale · 1 new commit
should-fix Cut-off uses the server's clock, not the customer's confirmed ×2

A customer in Perth can miss the 5 pm cut-off at 2 pm because the comparison runs in UTC.

Technical detail

isBeforeCutoff() compares Date.now() against a wall-clock hour with no zone. Every call site passes the customer's timezone already.

- const now = new Date();
+ const now = zonedNow(customer.timezone);
  return now.getHours() < CUTOFF_HOUR;
Explain simply & how to verifyyour claude

The order deadline is checked on the server's clock. For a shop in another timezone the deadline lands at the wrong hour.

  1. Set a customer's timezone to Australia/Perth.
  2. Place an order at 14:30 Perth time.
  3. Expected: accepted. Current: rejected as past cut-off.
Original kept for the learnings loop. EditDrop

Billing

Runs on your own Claude plan

ReviewStage runs the genuine Claude Code CLI. Each reviewer connects their own Claude account in the browser, and the reviews they start are billed to their plan and bound by their plan's limits.

Honest about the cost.

There is no shared API key and no metered SaaS. Whoever clicks Start pays for that run on their own subscription, and everyone requested on the PR reads the result.

  • Click-to-run, not on every push. A full agent run against a 25-file PR takes 10 to 15 minutes and real tokens; you decide which PRs earn one.
  • Quick, Standard or Deep effort, auto-suggested from the diff size. Deep tells the agent to search the whole repository for impact before judging.
  • A focus note ("pay attention to the cut-off maths") is folded into the prompt on top of the skill.
  • Choose the model per run: your plan's default, Opus, Sonnet or Haiku. The PR page shows which model ran and how many tokens it used.
  • Runs serialise one at a time per server, and refuse to start below a free-memory floor, so two agents never fight over a small box.
  • A re-run of the exact same commit, effort, focus and model is served from cache: zero new tokens.
run · #482 · you claude · connected
Effort
Quick Standard auto-suggested Deep
Suggested from the diff: 9 files, +412 −38.
Model
Plan default Opus Sonnet Haiku
Focus optional
pay attention to the cut-off maths
Billed to your plan. Nothing runs on push. Start review
Last run sonnet · 118,240 tokens standard · 11 min re-run of same commit · cached · 0 tokens

Team mode

One server, every reviewer, their own name

One instance serves the whole team. Each person signs in once; from then on their queue, their runs, their posts and their approvals are theirs, under their own GitHub identity.

Shared server. Personal accountability.

The design refuses to have a bot identity. If a comment carries your name, you chose it, and the audit trail on GitHub is the audit trail.

  • Independent reviews per reviewer, each in its own git worktree, so two people on one PR never collide and can compare what they each found.
  • A poller notices review requests within three minutes and sends each requested person their own Slack card. Discord is planned.
  • Posts and approvals go out under each person's own GitHub account. GitHub's own self-approval check runs against that user.
  • The service token in the server's .env does reads and the base clone only. It cannot post or approve as anyone.
  • Stacked PRs (Graphite or ghstack style) can be reviewed from one page, top to bottom, at one effort.
queue · acme · 2 repositories you · mira
To review4 Reviewed2 Posted7 Approved3
acme/payments acme/web + add repository
  • #482
    Refund flow: retry on gateway timeout highmedium
    acme/payments · by mira +412 −38 requested 09/12/26
    YM
  • #479
    Cut-off check in the customer's timezone medium
    acme/web · by dev-bot +96 −12 requested 09/12/26
    Y
  • #477
    Stacked: extract RefundGateway (2 of 3)
    acme/payments · by jon +220 −140 requested 09/12/26
    M
  • #475
    Bump pnpm and lockfile low
    acme/web · by renovate +8 −8 requested 09/12/26
    no run yet
Each reviewer's run, post and approval carries their own GitHub identity.

The loop

It learns what your team drops

Every post records which findings were kept, reworded or dropped. Recent decisions are fed into the next review of the same repository, so the agent stops raising what your team has already rejected. Not machine learning: in-context steering with your own recent choices.

A flywheel with a human at every turn.

Usage produces accept and reject signal. Signal shows which skills work. That informs a better team default, edited and approved by people.

  • Per-skill keep rate: each review records which skill ran it, so the Skills page shows how often each skill's findings survive a human.
  • Bring your own Claude Code skill. Paste your review skill and ReviewStage runs its logic, appending only the output contract the dashboard needs.
  • Quick-add a rule in plain words ("don't ask for a ticket link in code comments"); it is tidied into the skill's Team rules section.
  • The team default is versioned. Every edit is committed with the editor's name, and the revision history is on the page. It cannot be blanked, and restoring the built-in takes a typed confirm.
  • Independence-weighted agreement: when reviewers using a different skill, model or effort raise the same finding, it is marked confirmed. Same configuration twice does not count.
skills · team default · v3 kept 71.4%
  • Team defaultruns by default 71.4% kept · 38 reviews
  • Your skill 64.0% kept · 11 reviews
  • Built-in 58.3% kept · 20 reviews
Quick-add a rule
don't ask for a ticket link in code comments
Add rule
Tidied into the skill's Team rules section, committed under your name.
  1. v3mira · 09/11/26Team rules: no ticket links in code comments
  2. v2you · 09/03/26Drop nits on test file naming
  3. v1jon · 08/22/26Forked from built-in

Beyond the review

From PR to QA guide

The same server can turn a PR into a tester-ready QA guide: what to set up, what to test first, where the change must not appear, and what not to file as a bug.

Hand testers something grounded.

The guide is markdown you can paste anywhere. It is generated on demand, one job at a time, and can be stopped like a review.

  • Risk-tiered P0 / P1 / P2 cases derived from the real diff, the review threads and the branch's commit history, not from the PR description.
  • Written for a tester who has never seen the code: numbered steps, explicit pass and fail, no identifiers except the ones a tester has to type.
  • Includes a surface matrix with the deliberate "must not appear" rows and a list of known non-defects, so QA does not file them.
  • Runs on the requesting user's own Claude account, in its own worktree, never writing to GitHub.
qa guide · #482 · 11 cases P0 3 · P1 5 · P2 3
  • p0
    01Refund after a gateway timeout is issued exactly once
    Pass: one refund row, one gateway call
  • p0
    02Retry reuses the original idempotency key
    Pass: same key on every attempt in the gateway log
  • p0
    03Timed out, then succeeded: no duplicate
    Pass: second attempt returns the first result
  • p1
    04Backoff spreads retries after an outage
    Pass: attempts do not land in the same second
  • p1
    05Slow gateway is reported as a timeout, not a 500
    Pass: error code GATEWAY_TIMEOUT in the response
  • p2
    09Refund UI unchanged for card payments
    Pass: no new controls or copy
  • + 3 P1 and 2 P2 cases
Must not appearsurface matrix
Card refundsno retry banner·Admin exportno new column
Known non-defects1 · the retry counter resets per deploy

Who it's for

One developer, one team, or the whole company

The same container at every size. Start on a laptop, move it to a server when a second reviewer wants in, and add repositories when the organisation does.

  • Solo

    One developer, one laptop

    Docker on your own machine. Paste a PR URL, get the findings, post the ones you stand behind.

    • docker compose up -d and you are in
    • No notifications to configure; you open it when you review
    • Runs on your own Claude plan, no shared key
    • Add to Home Screen and it opens like an app
  • Team

    One server, one repository

    A shared instance every reviewer signs in to. Within three minutes of a review request, the requested person gets a card.

    • Review-request alerts to Slack, Discord or any webhook
    • Everyone signs in as themselves and posts as themselves
    • Independent runs per reviewer; agreement across them is marked
    • Skills, learnings and Insights shared by the team
  • Company

    Many repositories, one install

    One server for the organisation: an allowlist of repositories, per-repo skills and risk paths, and Insights across all of them.

    • Multiple repositories per server
    • Org membership allowlist for who may sign in
    • Per-repo skills and risk paths
    • Insights across repositories
    • GitHub App sign-in with central revocation roadmap

Same install, same gate at every size: nothing reaches GitHub without a signed-in person clicking, under their own name. Team and Company are configuration, not a different edition.

Ready when you are

Three steps to a staged review

  1. 1

    Bring it up

    docker compose up -d and open http://localhost:8899. bin/doctor.sh checks Docker, the .env, and that Claude Code can sign in.

  2. 2

    Sign in as yourself

    A fine-grained GitHub token scoped to the repo, then Connect Claude in the browser. Both are stored encrypted and only used for actions you click.

  3. 3

    Paste a PR URL

    Pick Quick, Standard or Deep, optionally a focus note and a model, and run. Read the findings, tick, edit, post. Approve is its own click.

Add --profile team for the review-request poller and Slack cards, so teammates are pinged when a PR is waiting on them. Run docker compose up -d demo to see the dashboard with sample runs before wiring anything up. Details in Team mode.

Stage it. Then post it as yourself.

One command to a staged review.

git clone https://github.com/Wimukti/reviewstage && cd reviewstage && cp .env.example .env && docker compose up -d