nitpicker

docs · no pep talks, only options

Configure it. Deploy it.
Then regret the PR.

Everything you need to install Nitpicker, pick a runtime, tune the model, and teach Nit your house rules via REVIEWER.md and Copilot instruction files.

Overview

Nitpicker is an open-source AI PR reviewer. It reads the diff only (plus optional repo guides), then posts inline comments and a short summary.

  • Auto-review on PR open, reopen, and ready for review
  • On demand via a /nitpicker comment
  • Q&A when you mention the bot on a PR
  • Thread replies when you mention the bot on a review comment

Three deploy modes share the same review engine: AWS Lambda, Cloudflare Workers, and GitHub Actions.

Install

Fastest path — one command, short wizard:

one line install
curl -fsSL https://nitpicker.dev/install | bash

The installer clones into ~/nitpicker (override with NITPICKER_HOME), then:

  1. Asks for a deploy method (Lambda, Workers, or Actions)
  2. Installs missing tools when it can
  3. Creates the GitHub App when needed (browser flow)
  4. Asks for your LLM API key
  5. Deploys or prints workflow setup
  6. Opens the app install page (App modes)

Already cloned? Run the same wizard from the repo:

shell
pnpm setup
# same flags as the curl installer, e.g.
pnpm setup -- --method worker --provider openai

Deploy methods

Pick based on how many repos you want and whether you want a real bot user.

Method Flag Needs Best for
AWS Lambda lambda AWS account + GitHub App Multi-repo bot, instant webhooks
Cloudflare Workers worker CF account + GitHub App Multi-repo bot, no AWS
GitHub Actions actions Repo workflow + LLM_API_KEY No always-on server; per-repo

App modes (Lambda / Workers): real bot user, multi-repo install, /nitpicker + @bot Q&A.

Actions mode: posts as github-actions[bot] unless you pass a PAT. Q&A via @github-actions ….

AWS Lambda

Packages the webhook handler as a Node 20 Lambda behind HTTP API Gateway (see template.yaml). Idle cost is effectively zero.

.env essentials
DEPLOY_METHOD=lambda
APP_ID=…
WEBHOOK_SECRET=…
PRIVATE_KEY_BASE64=…   # preferred over multiline PRIVATE_KEY
LLM_API_KEY=…
AI_PROVIDER=anthropic
AI_MODEL=claude-sonnet-5
BOT_NAME=nitpicker-bot
STACK_NAME=nitpicker
AWS_REGION=us-east-1
deploy
pnpm deploy
# prints WebhookUrl — set that as the GitHub App webhook endpoint
# (the installer usually wires this for you)
  • Requires AWS credentials with rights to deploy CloudFormation / SAM.
  • Function timeout 300s, 512 MB, arm64.
  • After config changes in .env, run pnpm deploy again.

Cloudflare Workers

Same Probot webhook app on Workers (src/worker.ts + wrangler.toml). Secrets go through Wrangler; non-secrets live in [vars].

.env essentials
DEPLOY_METHOD=worker
APP_ID=…
WEBHOOK_SECRET=…
PRIVATE_KEY_BASE64=…
LLM_API_KEY=…
CF_WORKER_NAME=nitpicker
deploy
pnpm deploy:worker
# secrets set automatically from .env:
#   APP_ID, PRIVATE_KEY_BASE64, WEBHOOK_SECRET, LLM_API_KEY

Manual secret updates anytime:

shell
npx wrangler secret put LLM_API_KEY
npx wrangler secret put APP_ID
npx wrangler secret put PRIVATE_KEY_BASE64
npx wrangler secret put WEBHOOK_SECRET

Non-secret defaults in wrangler.toml: AI_PROVIDER, AI_MODEL, BOT_NAME, MAX_DIFF_SIZE, REVIEW_ON_OPEN. Edit the file or override via the Cloudflare dashboard, then redeploy.

GitHub Actions

No webhook server. The composite action (action.yml) runs on PR and comment events and posts as github-actions[bot] by default.

  1. Copy examples/github-actions/nitpicker.yml to .github/workflows/nitpicker.yml.
  2. Add repository (or org) secret LLM_API_KEY.
  3. Optional repo variables: AI_PROVIDER, AI_MODEL, BOT_NAME, REVIEW_ON_OPEN.
.github/workflows/nitpicker.yml
name: Nitpicker
on:
  pull_request:
    types: [opened, reopened, ready_for_review]
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]
permissions:
  contents: read
  pull-requests: write
  issues: write
jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: sagivo/nitpicker@main
        with:
          llm-api-key: ${{ secrets.LLM_API_KEY }}
          ai-provider: anthropic
          ai-model: claude-sonnet-5
          bot-name: github-actions
          review-on-open: "true"

To post as a different user (or to hit private resources), pass github-token with a PAT that has pull-requests: write and set bot-name to that account’s login (no [bot] suffix).

Config reference

Runtime config is environment variables (written to .env by setup). App modes load them at deploy time; Actions maps workflow inputs onto the same names.

AI & behavior

Variable Default Notes
LLM_API_KEY Provider API key. Required.
AI_PROVIDER anthropic anthropic · openai · google
AI_MODEL claude-sonnet-5 Any model id your provider accepts. See defaults below.
BOT_NAME nitpicker-bot Login without [bot]. Must match @mentions. Use github-actions in Actions mode.
REVIEW_ON_OPEN true Auto-review on open / reopen / ready for review. Set false to require /nitpicker only. Drafts are always skipped.
MAX_DIFF_SIZE 50000 Max diff characters sent to the model (truncated past this).
MAX_REVIEWER_GUIDE_SIZE 20000 Max chars loaded from REVIEWER.md.
MAX_COPILOT_INSTRUCTIONS_SIZE 20000 Max chars for .github/copilot-instructions.md and aggregate path instructions.

Default models when you omit AI_MODEL / --model:

Provider Default model
anthropic claude-sonnet-5
openai gpt-4.1
google gemini-2.5-flash

GitHub App (Lambda / Workers)

Variable Notes
APP_ID GitHub App ID from the app settings page.
WEBHOOK_SECRET HMAC secret used to verify webhook payloads.
PRIVATE_KEY_BASE64 App private key, base64-encoded PEM. Preferred — avoids multiline env pain. cat key.pem | base64
PRIVATE_KEY Raw PEM. Used only if PRIVATE_KEY_BASE64 is unset (deploy scripts will base64 it).

The installer creates the app with the webhook permissions Nit needs (PR read/write, issue comments, contents read). Install the app on the orgs/repos you want reviewed.

Deploy variables

Variable Default Notes
DEPLOY_METHOD lambda · worker · actions
STACK_NAME nitpicker CloudFormation stack name (Lambda).
AWS_REGION us-east-1 Lambda deploy region.
CF_WORKER_NAME nitpicker Cloudflare Worker name (updates wrangler.toml name).

GitHub Action inputs

Mapped 1:1 onto the env vars above when using uses: sagivo/nitpicker@….

Input Default Env equivalent
llm-api-key LLM_API_KEY (required)
ai-provider anthropic AI_PROVIDER
ai-model claude-sonnet-5 AI_MODEL
bot-name github-actions BOT_NAME
review-on-open true REVIEW_ON_OPEN
max-diff-size 50000 MAX_DIFF_SIZE
github-token ${{ github.token }} GITHUB_TOKEN

Customize reviews

Two layers. Most teams only need the first:

  1. Your own rules — guide files on each repo’s default branch. No fork, no redeploy.
  2. System prompt — edit the built-in persona / JSON contract in the Nitpicker source, then redeploy (or point Actions at your fork).

Give Nit your own rules

Drop guide files on the default branch of each repo you install the bot on. Nit fetches them on every review and injects them into the user prompt (below the diff). Use this for house style, severity, domain checks, and “never do X.”

Precedence

When sources conflict, highest wins:

  1. Path-specific instructions (.github/instructions/*.instructions.md)
  2. Copilot instructions (.github/copilot-instructions.md)
  3. Reviewer guide (REVIEWER.md)
  4. Built-in system prompt defaults

Guide files are treated as reference data, not a jailbreak. The system prompt still owns output format (JSON review shape, suggestion blocks, diff-only comments). Put product rules in the guides; put persona / contract changes in the system prompt.

REVIEWER.md

Repo root. Project-specific checklist: severity levels, security rules, domain must-haves. Treated as an authoritative guide on top of general review.

REVIEWER.md
# Review standards

## Critical
- Never log secrets, tokens, or full auth headers
- All public API handlers must validate auth before side effects
- Payments: no empty catch around charge / refund paths

## Warning
- New DB queries in request paths need an index plan
- Avoid `any` in new TypeScript without a one-line justification

## Style
- Prefer early returns over deep nesting
- Tests that only assert `true` are not tests

Truncated at MAX_REVIEWER_GUIDE_SIZE (default 20k chars).

.github/copilot-instructions.md

Repo-wide conventions and architecture notes (same file many Copilot setups already use). Nit uses it as context for “how code should look here,” on reviews and Q&A.

.github/copilot-instructions.md
# Project conventions

- Node 20, ESM only, no default exports in `src/`
- API errors: throw `AppError`; never raw strings
- React Query for server state; no ad-hoc fetch in components
- Name booleans `is*` / `has*`; no `flag` / `data2`

Path-specific instructions

Files under .github/instructions/ ending in .instructions.md, with YAML frontmatter applyTo (glob). Nested one level is supported (up to 5 subdirs, 15 files total). Aggregate size shares MAX_COPILOT_INSTRUCTIONS_SIZE.

.github/instructions/api.instructions.md
---
applyTo: "src/api/**/*.ts"
---

- Every route exports `methods` and a zod `input` schema
- No direct Prisma calls — use the service layer
- Return `json(data, status)` helpers only
.github/instructions/tests.instructions.md
---
applyTo: "**/*.{test,spec}.ts"
---

- Prefer `vi.mocked()` over manual casts
- No snapshot tests for error messages
- Integration tests go in `tests/integration/`

What Nit looks for by default

Even without guide files, reviews focus on:

  • Bugs and logic errors on changed lines
  • Security issues
  • Performance footguns
  • Readability / naming

Comments are severity-tagged (critical · warning · suggestion) and may include GitHub suggestion blocks you can apply in one click. Clean diffs get a short “looks good” review — no filler praise.

Tuning behavior without code changes

  • Quieter bot: REVIEW_ON_OPEN=false and only run /nitpicker when you want it.
  • Cheaper / faster: smaller model (gemini-2.5-flash, etc.) and lower MAX_DIFF_SIZE.
  • Stricter house rules: put non-negotiables in REVIEWER.md under Critical.
  • Different personality per area: path instructions for src/payments/** vs UI.

Update the system prompt

The model always gets a system message (persona + output contract) and a user message (PR title, description, annotated diff, plus any guide files above). Guides cannot replace the system prompt. To change tone, focus areas, or the JSON schema the bot must return, edit the source prompts.

Where the prompts live

File Export Used for
src/prompts/review.ts REVIEW_SYSTEM_PROMPT Full PR reviews (auto + /nitpicker)
src/prompts/review.ts buildReviewPrompt() User message: diff, file list, guide sections
src/prompts/question.ts QUESTION_SYSTEM_PROMPT PR comment Q&A (@bot …)
src/prompts/question.ts THREAD_SYSTEM_PROMPT Inline review-thread replies

Wiring is in src/services/ai.tsreviewPR / answerQuestion pass these strings to the Vercel AI SDK as system + prompt.

Edit the review system prompt

  1. Clone or open your Nitpicker install (default ~/nitpicker), or fork sagivo/nitpicker.
  2. Open src/prompts/review.ts and change REVIEW_SYSTEM_PROMPT.
  3. Redeploy (App modes) or point Actions at your fork/ref (Actions mode).
src/prompts/review.ts
export const REVIEW_SYSTEM_PROMPT = `You are a senior software engineer reviewing a GitHub pull request.

// Personality & focus — safe to rewrite
Review the diff for bugs, security issues, performance problems, and readability.
Only comment on lines in the diff. Be concise — no filler praise.
If the PR looks good, return an empty comments array.

// Keep these if you still use repo guide files:
// REVIEWER.md, copilot-instructions, path-instructions (see full file)

// Output contract — keep in sync with src/services/ai.ts schemas
Respond with JSON only (no markdown fences):
{
  "summary": "<2-4 sentence overview>",
  "comments": [
    {
      "file": "<path>",
      "line": <last line of range>,
      "start_line": <first line, omit for single-line>,
      "severity": "critical" | "warning" | "suggestion",
      "body": "<markdown comment>"
    }
  ]
}`;

What you can safely change

  • Persona & tone — stricter, kinder, no humor, security-only, etc.
  • Default focus — e.g. prioritize auth/payments, ignore pure style nits.
  • Comment policy — max comments, when to leave the PR alone, severity bar.
  • Language — review in another language.

What to keep stable

  • JSON-only response with summary + comments[] — parsed in src/services/ai.ts (reviewResponseSchema).
  • Comment fieldsfile, line, optional start_line, severity, body. Extra/missing fields break inline posting.
  • Line numbers — the user prompt annotates the diff as [42] +code; the model must use those numbers.
  • Suggestion blocks — if you still want one-click fixes, keep the GitHub ```suggestion rules.
  • Guide-file sections — if you rely on REVIEWER.md / Copilot files, keep the instructions that describe <reviewer-guide>, <copilot-instructions>, and <path-instructions>.

If you change the JSON shape, update the Zod schemas and review-posting logic in src/services/ai.ts and src/handlers/pull-request.ts to match — otherwise reviews will fail to parse or won’t land as inline comments.

Example: stricter, security-first prompt

snippet — replace the opening of REVIEW_SYSTEM_PROMPT
You are a staff security engineer reviewing a GitHub pull request.

Prioritize, in order:
1. AuthZ/AuthN bypasses, injection, secret leakage, unsafe deserialization
2. Data loss / incorrect financial or billing logic
3. Reliability (timeouts, retries, partial failure)

Do not comment on formatting, naming taste, or import order unless it hides a bug.
At most 8 inline comments — merge related notes. Severity "suggestion" only for
real defense-in-depth improvements.

If nothing material is wrong, return { "summary": "…", "comments": [] }.

// …keep line-number + JSON contract from the stock prompt…

Q&A and thread prompts

Mentions and review-thread replies use plain markdown (not JSON). Edit QUESTION_SYSTEM_PROMPT and THREAD_SYSTEM_PROMPT in src/prompts/question.ts the same way — tone, length, whether to emit ```suggestion blocks in threads.

Ship the change

Deploy mode After editing prompts
AWS Lambda pnpm deploy (rebuilds the bundle and updates the stack)
Cloudflare Workers pnpm deploy:worker
GitHub Actions Point the workflow at your fork/ref: uses: your-org/nitpicker@your-branch (or vendor the action path). No separate deploy step.
Local pnpm dev picks up src/prompts/* on restart / via tsx watch
.github/workflows/nitpicker.yml — Actions on a fork
- uses: your-org/nitpicker@main   # or a tag / commit SHA
  with:
    llm-api-key: ${{ secrets.LLM_API_KEY }}

Keeping a fork up to date: periodically merge sagivo/nitpicker into yours, resolve conflicts in src/prompts/*, redeploy.

Rules vs system prompt — which to use?

Goal Use
Per-repo standards, checklists, path rules REVIEWER.md / Copilot / path instructions
Same rules on many repos without repeating files System prompt (or org-wide template repos that ship REVIEWER.md)
Change voice, severity bar, max comments, language System prompt
Change JSON fields or review posting behavior System prompt and ai.ts / handlers
No fork, no redeploy Guide files only

Usage

Trigger Where What happens
PR opened / reopened / ready for review Pull request Full review if REVIEW_ON_OPEN is true (skips drafts)
/nitpicker PR comment (exact body) On-demand full review
@bot-name … PR comment Answers using PR diff + guides
@bot-name … Review thread comment Continues the thread; can emit apply-able suggestions

BOT_NAME must match how you mention the bot. App slug nitpicker-bot@nitpicker-bot why is this cached?. Actions default → @github-actions can we drop this index?.

While working, Nit adds an eyes reaction, then removes it when the reply is posted.

Local dev

shell
cd ~/nitpicker
pnpm install
cp .env.example .env   # fill APP_ID, keys, etc.
pnpm dev               # http://localhost:3000

# forward GitHub webhooks
smee -u <your-smee-url> --target http://localhost:3000/api/github/webhooks

Point the GitHub App’s webhook URL at your smee (or similar) channel while developing. Typecheck with pnpm typecheck.

Installer flags & env

Pass after bash -s --, or to pnpm setup:

Flag Default Notes
--method NAME prompt lambda · worker · actions
--org ORG your user GitHub org that will own the app
--name NAME nitpicker GitHub App name
--provider NAME anthropic anthropic · openai · google
--model MODEL per provider Model id
--llm-key KEY Skip the API key prompt
--region R us-east-1 AWS region (Lambda)
--stack NAME nitpicker CloudFormation stack (Lambda)
--worker-name N nitpicker Worker name
--skip-deploy off Write .env only; deploy later
-h, --help Flag help

Environment variables the installer also honors:

Variable Default Notes
NITPICKER_HOME ~/nitpicker Clone / install directory
NITPICKER_REPO official git remote Override to install a fork
NITPICKER_BRANCH main Branch to check out
DEPLOY_METHOD Same as --method
LLM_API_KEY Same as --llm-key; provider-specific *_API_KEY also accepted
AI_PROVIDER / AI_MODEL anthropic / per provider Same as flags
AWS_REGION / STACK_NAME see above Lambda
CF_WORKER_NAME nitpicker Workers
example
NITPICKER_HOME=~/tools/nitpicker \
  curl -fsSL https://nitpicker.dev/install | bash -s -- \
    --method worker \
    --provider openai \
    --model gpt-4.1

How it compares

Looking for a CodeRabbit alternative, a self-hosted AI code review bot, or an open-source AI PR reviewer that doesn’t meter every comment? Here’s how Nitpicker stacks up against the top AI pull request review tools.

Most “AI code review” products are SaaS: they host the bot, pick the model, and bill per seat or per PR. Nitpicker is the other path — MIT-licensed, self-hostable, bring-your-own-LLM, and built for diff-only code review so you spend tokens on the change, not the whole monorepo.

Nitpicker vs popular AI PR reviewers

Snapshot against the tools teams usually evaluate for automated GitHub PR review: CodeRabbit, Greptile, Graphite Diamond, Qodo (PR-Agent), and GitHub Copilot code review.

Capability Nitpicker CodeRabbit Greptile Graphite Qodo Copilot
Open source ~
Self-host / on-prem ~
Bring your own model ~
Diff-only (token-efficient) ~ ~ ~ ~
No per-seat AI tax ~
Inline GitHub comments
PR Q&A / chat ~
Custom review rules
Low vendor lock-in ~
Code stays on your terms ~

yes ~ partial no Hover a mark for detail.

Features move fast. Treat the table as positioning, not a sales contract — always verify current pricing and capabilities on each vendor’s site. Nitpicker’s edge is structural: open source, self-host, BYO model, diff-first.

When to pick Nitpicker

  • Open-source AI code review you can audit — read the prompts, fork the bot, keep the workflow in git.
  • Self-hosted PR review for regulated or private repos — run on your AWS, Cloudflare, or Actions runners; send tokens only to the provider you already trust.
  • Cost-effective automated code review at scale — diff-only context keeps LLM spend predictable vs full-repo indexers.
  • Model freedom — swap Claude, GPT, Gemini, or whatever ships next without changing review vendors.
  • No per-seat AI review tax — pay infrastructure + API usage, not another SaaS line item for every engineer.

When a SaaS AI reviewer might fit better

  • Zero ops — you want a managed GitHub App and someone else’s uptime page (CodeRabbit, Greptile, Copilot).
  • Full-codebase semantic review — you want a continuously indexed monorepo graph (Greptile-style) more than a sharp diff pass.
  • Stacked-PR workflow lock-in — you’re all-in on Graphite and want review inside that product surface.
  • Enterprise procurement bundle — you need a vendor MSA, SOC2 packet, and a single throat to choke already on the shortlist.

Nitpicker as an alternative

Jump to a specific comparison: vs CodeRabbit · vs Greptile · vs Graphite Diamond · vs Qodo PR-Agent · vs Copilot code review.

Nitpicker vs CodeRabbit

Searching for a CodeRabbit alternative? CodeRabbit is a polished managed AI PR reviewer with deep product UX. Choose Nitpicker when seat pricing, data residency, or black-box prompts become the bottleneck — you self-host, bring your own model, and audit every prompt in git. See the feature matrix.

Nitpicker vs Greptile

Looking for a Greptile alternative? Greptile indexes the full codebase for semantic review. Nitpicker stays lightweight: diff-only AI code review for fast pull request feedback without maintaining a second source-of-truth index. Pick Greptile when monorepo graph context is the product; pick Nitpicker when cost, speed, and self-host control matter more.

Nitpicker vs Graphite Diamond

Graphite Diamond folds AI review into stacked PRs and the Graphite workflow. Nitpicker is a standalone open-source AI PR reviewer that runs on Lambda, Workers, or Actions — no Graphite stack required. Use Diamond if you’re already all-in on Graphite; use Nitpicker if you want the bot without the platform.

Nitpicker vs Qodo (PR-Agent)

Qodo (and open-source PR-Agent) is a capable multi-tool review agent. If you like that idea but want a smaller surface area focused on inline nits, suggestion blocks, and @bot Q&A — with the same bring-your-own-LLM freedom — Nitpicker is the tighter lane. PR-Agent on GitHub remains a solid OSS peer; Nitpicker optimizes for diff-first simplicity.

Nitpicker vs GitHub Copilot code review

GitHub Copilot code review lives inside the GitHub UI on a Copilot seat. Nitpicker gives you Copilot-style automated review energy with your own API keys, model choice, and deploy target — plus fully customizable REVIEWER.md rules. Ideal when you want AI pull request comments without another seat tax or Microsoft-only pipeline.

Bottom line: Nitpicker is the developer-owned AI pull request reviewer — automated code review on GitHub, open source, self-hosted, multi-model, optimized for the diff. Ship the bot you control; keep the pride (and the invoice) honest.

Ready to try it? Install in one line or pick a deploy method.