up-reviewer
v0.3.1
Published
Flue agent that reviews git diffs and reports structured, line-anchored findings
Maintainers
Readme
up-reviewer
A Flue agent that reviews local git diffs and GitHub PRs, reporting line-anchored findings (file, line, severity, title, body).
Install
npm install up-reviewerPublished at npmjs.com/package/up-reviewer.
Build from source
git clone https://github.com/senbinil/up-reviewer.git
cd up-reviewer
npm install
npm run buildRequires Node >= 24 (native TypeScript type-stripping).
Quick start
# Set your provider's API key
export DEEPSEEK_API_KEY=sk-xxx
# Review the working tree vs HEAD
npx review
# Review vs a specific commit
npx review 8592245
# Review a branch diff
npx review main feature/x
# API-ready JSON output
npx review --format json main feature/xNote: If you cloned the repo, use
npm run reviewinstead ofnpx review.
Configuration
Built-in Providers
Built-in providers need only the API key — no other env vars required. The agent auto-configures the base URL, protocol, and model defaults.
# DeepSeek (default — no AGENT_MODEL needed)
DEEPSEEK_API_KEY=sk-xxx npx review
# Anthropic (just the key + model override)
ANTHROPIC_API_KEY=sk-ant-xxx AGENT_MODEL=anthropic/claude-sonnet-4-6 npx review
# OpenAI (just the key + model override)
OPENAI_API_KEY=sk-xxx AGENT_MODEL=openai/gpt-5.5 npx reviewCustom Providers
For providers not in the built-in set (Mimo, Ollama, etc.), register dynamically:
AGENT_MODEL=mimo/mimo-model-id \
AGENT_PROVIDER_BASE_URL=https://api.mimo.example.com/v1 \
AGENT_API_KEY=sk-xxx \
AGENT_MODEL_MAX_TOKENS=16384 \
AGENT_MODEL_CONTEXT_WINDOW=256000 \
AGENT_MODEL_REASONING=true \
npx reviewSee .env.example for a template.
Environment Variables
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| AGENT_MODEL | No | deepseek/deepseek-v4-flash | Model specifier (provider/model-id) |
| AGENT_PROVIDER_ID | No | Extracted from AGENT_MODEL | Override provider ID for custom providers |
| AGENT_PROVIDER_BASE_URL | No* | — | Base URL for custom providers (*required for custom providers) |
| AGENT_PROVIDER_API | No | openai-completions | Wire protocol: openai-completions or anthropic-messages |
| AGENT_API_KEY | No | — | API key for custom providers |
| AGENT_MODEL_MAX_TOKENS | No | 8192 | Max output tokens |
| AGENT_MODEL_CONTEXT_WINDOW | No | 1000000 | Context window size (1M) |
| AGENT_MODEL_REASONING | No | false | Enable reasoning/thinking (true/false) |
GitHub Actions
The agent reviews every PR automatically via a GitHub Actions workflow.
Using the npm package
# .github/workflows/review-pr.yml
name: PR Review
on:
pull_request:
types: [opened, synchronize]
permissions:
contents: read
pull-requests: write
concurrency:
group: pr-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
review:
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/setup-node@v7
with:
node-version: '24'
- run: npm install up-reviewer
- run: npx review
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
AGENT_API_KEY: ${{ secrets.AGENT_API_KEY }}Using the source repo
Setup:
- Add
AGENT_API_KEY(or provider key likeXIAOMI_API_KEY) as a repository secret - Copy .github/workflows/pr-review.yml into your repo's
.github/workflows/ - Push to the default branch — it activates on the next PR
The workflow uses pull_request_target so only base-branch code runs with secrets.
Fork PRs are skipped. After each run, it verifies a review was actually posted
and fails loudly otherwise.
How it works
Local CLI:
npx review <base> [head]
│
▼
src/workflow/review.ts auto-detects mode, dispatches to:
│ ├── local.ts (LOCAL MODE: git diff)
│ └── github.ts (GITHUB ACTIONS MODE: gh pr diff)
▼
src/agents/reviewer.ts sandbox-less review, single validated tool
│ `submit_findings` ({findings: [...]})
▼
workflow validates the tool captures the tool call via toolCallId,
output + renders findings falls back to parsing a JSON replyGitHub Actions (same agent, different mode):
PR opened/synchronized
│
▼
npx review (GITHUB_ACTIONS=true) review.ts detects Actions mode,
│ dispatches to github.ts
▼
github.ts validates PR_NUMBER, GH_TOKEN,
│ AGENT_API_KEY; dispatches Reviewer
▼
src/agents/reviewer.ts `fetch_pr_diff` loads the PR diff
│ via `gh pr diff`; reviews it
▼
`post_review` tool validates findings, POSTs a PR review
(event COMMENT + inline comments) via `gh api`Design decisions (hard-won):
- No diff parsing anywhere. The raw unified diff goes straight to the
model; stats come free from
git diff --stat. The original hand-rolled parser was both inefficient and buggy (diffInParts[-1]), and was removed. - Structured output rides on a schema-validated tool call, not free text.
The model's most reliable behavior is calling tools;
submit_findingshas a valibotinputschema, so the runner can trust it. The same schema gatespost_reviewbefore anything is sent to GitHub. - No sandbox, no gh tools for LOCAL MODE. The
submit_findings-only configuration is what the CLI was designed with: a crafted inline diff cannot steer the model into GitHub writes, because the tools that could do so are simply not registered. Under GitHub Actions the gh-backedfetch_pr_diff/post_reviewtools are registered — narrow and schema-validated, never an open-ended model-directed shell, and the token never reaches the model. Mode is decided by theGITHUB_ACTIONSenv var, never by parsing the (untrusted) user message. - The CLI cannot hang.
Reviewer.durability = { timeoutMs: 240_000 }bounds every submission; the workflow'sgitcalls have their own timeouts; an empty diff short-circuits without a model call. - Untrusted diff text is marked as data in the prompt (injection surface).
CI
.github/workflows/ci.yml runs npm run check:types and npm test on
every push to any branch and on pull requests (opened/reopened only —
every PR update is a push, so synchronize would be a duplicate). It
runs on Node 24 (read from .nvmrc), carries no secrets — permissions are read-only contents.
Concurrency is grouped per branch with cancel-in-progress: a new push
cancels the in-flight run from the previous commit on the same branch, so
CI never backs up behind stale runs. Docs-only pushes (markdown) skip CI
to save runner minutes.
Fork PRs are un-gated (GitHub denies repository secrets to fork runs +
the read-only token is the real boundary, not an inline if: that a fork
can delete from its copy).
Learn more
- Flue docs — or
npx flue docsfrom the terminal.
