winnin/farol: Know the chance of merging a pull request, and the place it lives. Free, open-source CLI and GitHub Action: after your AI evaluate, farol reveals the riskiest information, what they attain, diff protection and contract breaks. TypeScript/React, Go, Python. · GitHub


Know the chance of merging a pull request, and the place it lives.

A free, open-source CLI and GitHub Action. After your AI evaluate, farol tells the one who approves how dangerous the
merge is and which information carry the chance, so the riskiest modifications get essentially the most consideration.

Website ·
Live demo ·
Get started ·
Reference

License: MIT
Node.js 22+
TypeScript · Go · Python
Shadow mode


Agents write the code and brokers evaluate it. The final name remains to be an individual’s: approve the merge or not. That
approval is the scarce half, and unfold evenly over each pull request it turns right into a skim, which is how a one-line
change to a shared hook takes down forty pages.

farol comes after the AI evaluate, not as a substitute of it. Your evaluate agent feedback on the traces within the diff. farol
offers the one who approves what the agent can’t reliably give: the chance of accepting the change, and the place it
lives
. The purpose is just not solely a quicker evaluate: low-risk pull requests can go quick, and the dangerous ones get learn line by
line, beginning with the information that carry the chance. It works from static evaluation (the compilers’ personal view of your
code, not a mannequin’s guess), so the identical pull request all the time will get the identical reply.

The Claude Code workforce describes the identical precept in
How the Claude Code team does code review: evaluate effort
follows the chance of the change. As they put it, “The change units the tier, not the creator.”

farol (Portuguese for lighthouse) does the triage earlier than the reviewer opens the diff:

  • What does this variation attain? Every present web page, API operation, RPC technique, job and script that runs the modified code, with the decision chain to every.
  • How dangerous is the merge? A verdict (quick monitor, fast evaluate, cautious evaluate) and a 0–100 threat rating from attain, diff protection, safety findings, contract breaks and dependency modifications.
  • Where do I begin? The riskiest information first, with inline diffs, untested traces marked, and a guidelines of what to attempt by hand.

Free and open supply (MIT). Run it as a CLI with npx @winninjs/farol, or on each pull request with the GitHub
Action winnin/farol/motion. No account, no hosted service: it runs in your machine or in your CI runner, feedback on
each PR and by no means blocks a merge. It by no means executes your code and by no means sends it anyplace.

The farol report of a pull request: a careful review at 74/100, the two files to start with, and three breaking contract changes

See farol on a real pull request →

The demo holds the studies farol produced in CI for a pull request on the
FastAPI full-stack template: a FastAPI backend and a React
frontend with TanStack Router. The pull request provides a standing to objects and an Insights web page, with the sort of issues
a reviewer ought to catch: a breaking API change, SQL constructed with an f-string, a shared element with out assessments.

  • Backend report: ⚠ cautious evaluate, a breaking contract change and a high-severity safety discovering.
  • Frontend report: ⚠ cautious evaluate, a brand new web page and the present pages a shared element reaches.

The studies are interactive: mark information as reviewed, mark a web page as behind a function flag, open the inline diffs,
observe the take a look at plan and duplicate the evaluate report from the Result tab. They are the identical information the pull request’s
feedback hyperlink to (the pull request); the
copies dwell in docs/demo/.

farol after your AI evaluate

AI evaluate brokers farol
Reads the diff, and no matter context suits within the immediate the entire program on the base and the pinnacle, with the compilers (TypeScript sort checker, go/varieties, Python ast)
Tells you what could also be flawed in these traces what these traces attain, how dangerous the merge is, and the place to look first
Answers are probabilistic: worded otherwise on each run deterministic: the identical PR offers the identical report, and each declare comes with its name chain
When uncertain might sound assured anyway says unknown and asks for a cautious evaluate
Runs a mannequin, normally a hosted service domestically or in your CI: it by no means executes your code and by no means sends it anyplace

Use each, in that order. The agent critiques the traces first; then farol tells the one who approves how a lot consideration
the merge wants, which information deserve it, which pages and endpoints to check by hand and which contract modifications want
their purchasers checked. The agent’s evaluate is just not sufficient precisely when a small change has a big attain, and that’s
what farol reveals.

  • Review consideration goes the place the chance is. A 40-file PR normally has two or three information that may truly harm. farol ranks them, so the reviewer reads these intently and skims the remainder with a transparent conscience.
  • It follows the code, not the file names. farol builds a declaration graph with the true compilers (the TypeScript sort checker, go/varieties, Python’s ast). A change to formatPrice lists the twelve pages that render it, not “1 file modified”.
  • Contract breaks are caught earlier than purchasers are. Removed response fields, new required parameters, modified varieties in GraphQL, FastAPI, Go handlers and gRPC, with the providers that decision every endpoint.
  • Review the entire PR, or simply what modified since your final look. Every push will get two studies: the total pull request, and solely the commits for the reason that earlier push. After a spherical of fixes, the reviewer checks the brand new commits as a substitute of beginning over.
  • It makes use of what your CI already has. Coverage, lint, safety and audit studies turn into diff protection and findings on the modified traces. Nothing runs twice.
  • Fail closed. When farol can’t learn a part of a change, it says so (unknown) and asks for a cautious evaluate. It by no means calls one thing secure as a result of it didn’t perceive it.
  • Built for the human within the loop. Mark information as reviewed, mark pages as behind a function flag, verify off findings, and paste the outcome again within the PR as a report of what was reviewed.

You want Node.js 22+ and git (plus go for Go tasks, python3 3.11+ for Python ones). Nothing to
set up: run farol with npx @winninjs/farol.

1. Describe your venture in a farol.config.json at its root. One line is sufficient to begin; decide your stack:

Your venture farol.config.json Full recipe
React app with React Router { "routes": { "file": "src/routes.tsx" } } (the file that builds the route desk) React Router
Next.js app (Pages or App Router) { "routes": { "adapter": "subsequent" } } Next.js
React app with TanStack Router { "routes": { "adapter": "tanstack-router", "dir": "src/routes" } } TanStack Router
TypeScript API (GraphQL, REST) { "floor": "backend" } TypeScript API
Go service { "language": "go", "floor": "backend" } Go
Python service (FastAPI, Flask, Django, Celery…) { "language": "python", "floor": "backend" } Python

2. Check what farol sees: the pages, endpoints, jobs and scripts it discovered.

npx @winninjs/farol routes

3. Analyze a department in opposition to its goal and open the report.

npx @winninjs/farol analyze --base origin/principal --head HEAD --out farol.json
npx @winninjs/farol html --in farol.json --out farol.html && open farol.html     # xdg-open on Linux

Example: a React app with React Router

cd path/to/your/react-app
echo '{ "routes": { "file": "src/routes.tsx" } }' > farol.config.json

npx @winninjs/farol routes                                        # lists your pages: "https://github.com/", "/merchandise", "/settings"…
git checkout my-feature-branch
npx @winninjs/farol analyze --base origin/principal --head HEAD --out farol.json
npx @winninjs/farol html --in farol.json --out farol.html && open farol.html

The report already reveals the decision, the rating, the information to start out with, the pages the change reaches and what to
take a look at by hand. Next steps: add your protection, lint and audit studies and run farol on each PR with the
recipe for your stack. Every choice is within the reference and, per stack, in
examples/README.md.

Running it usually? npm set up --global @winninjs/farol offers you a plain farol command.

Each recipe has three elements: the farol.config.json to commit, the studies to provide, and the GitHub Actions
workflow. The workflows in examples/ are full and share one form:

  1. assessments runs your assessments, linter and audit and retains the studies. It runs the PR’s code, so it has no secrets and techniques and a read-only token. If you have already got a take a look at job, preserve it and add its add step.
  2. farol runs after it (go or fail), reads git and the studies, and posts a new touch upon each push with a hyperlink that opens the HTML report within the browser, plus a second report with solely the commits for the reason that earlier push. It by no means runs the PR’s code.
  3. Drafts are skipped, fork PRs get no remark (their token is read-only), and each farol step is continue-on-error.

Pin the motion to a commit as soon as it really works for you: winnin/farol/motion@ # principal as of .

examples/README.md goes deeper for every stack: each configuration key, CLI parameter and
motion enter, and the way to verify a setup.

React frontend (React Router)

React Router route tables (object and JSX kinds, lazy routes, cut up route modules), attain per declaration.

{
  "routes": { "file": "src/routes.tsx" },
  "roles": { "world": ["src/main.tsx", "src/App.tsx", "src/styles/global.css", "package.json", "vite.config.ts"] }
}
npx vitest run --coverage.enabled --coverage.reporter=json --coverage.reportsDirectory=studies/protection
npx eslint -f json -o studies/eslint.json <modified information>
npm audit --json > studies/audit.json                     # or pnpm audit --json

npx @winninjs/farol analyze --base origin/principal --head HEAD 
  --coverage studies/protection/coverage-final.json --eslint studies/eslint.json --audit studies/audit.json --out farol.json

CI: copy examples/workflow.yml to .github/workflows/farol.yml.

Set protection.embrace: ['src/**/*.{ts,tsx}'] within the Vitest config so information no take a look at masses are reported as untested.
Split route timber go in routes.additionalFiles; a fuller config is in examples/farol.config.json.

Pages Router and App Router: each web page, API route, format, _app/_document and middleware, learn from the file
names. Dynamic segments ([id]), catch-alls, route teams and parallel slots are understood.

{
  "routes": { "adapter": "subsequent" },
  "roles": { "world": ["next.config.*", "package.json"] }
}

pages/ and app/ are discovered within the venture or in its src/; set "dir" after they dwell elsewhere. Reports and CI
are the identical as for React Router (Jest or Vitest protection, ESLint, audit). In a
monorepo whose tsconfig extends a workspace bundle ("extends": "tsconfig/nextjs.json"), set up dependencies
earlier than analyzing, so the bundle is in node_modules.

File-based routing: each module calling createFileRoute('') below the routes listing, with the foundation route,
pathless layouts (_app) and dad or mum routes as layouts of their kids.

{ "routes": { "adapter": "tanstack-router", "dir": "src/routes" } }

Reports and CI are the identical as for React Router.

TypeScript API (GraphQL or REST)

GraphQL root operations (schema information and gql templates, per resolver) and Fastify/Express-style REST endpoints.

{
  "floor": "backend",
  "backend": { "graphql": true, "relaxation": true },
  "roles": { "world": ["package.json", "src/app.ts"] }
}

Reports and CI are the identical as for React Router: examples/workflow.yml. If
resolvers attain information by an injected context (ctx.loaders.Brand.byId()), inform farol the place the suppliers dwell:
"backend": { "context": { "loaders": ["src/modules/*/loaders/index.ts"] } }.

chi, gin, echo and internet/http routes, gRPC service strategies and principal binaries, attain per declaration with interface
calls resolved to their implementations.

{ "language": "go", "floor": "backend" }
go take a look at -coverpkg=./... -coverprofile=studies/cowl.out ./...
golangci-lint run --output.json.path=studies/golangci.json --issues-exit-code=0 ./...   # allow gosec
govulncheck -json ./... > studies/govulncheck.json

npx @winninjs/farol analyze --base origin/principal --head HEAD 
  --coverage studies/cowl.out --eslint studies/golangci.json --audit studies/govulncheck.json --out farol.json

CI: copy examples/workflow-go.yml. farol reads modules offline, so the workflow runs
go mod obtain for the bottom and the pinnacle first.

FastAPI and Flask routes (routers, blueprints, prefixes), Django URLs, MCP instruments/assets/prompts, Celery duties,
Temporal workflows and actions, Prefect flows and __main__ scripts. farol parses your code; it by no means imports it.

{ "language": "python", "floor": "backend", "python": { "roots": ["src", "."] } }
pytest --cov=src --cov-report=json:studies/protection.json
ruff verify --output-format json --extend-select S --exit-zero . > studies/ruff.json    # S = flake8-bandit
pip-audit --format json -o studies/pip-audit.json

npx @winninjs/farol analyze --base origin/principal --head HEAD 
  --coverage studies/protection.json --eslint studies/ruff.json --audit studies/pip-audit.json --out farol.json

CI: copy examples/workflow-python.yml (makes use of uv; swap in your installer).

Add Datadog site visitors and errors

Optional, and data solely: it by no means modifications the rating. With it the report reveals how a lot site visitors every affected
web page or operation will get, its distinct manufacturing errors (linked to Datadog), the modified information that already throw
errors, and the providers that decision every modified endpoint.

{
  "datadog": {
    "env": "prod",
    "rum": { "applicationId": "" },
    "apm": { "service": "orders-api", "operations": ["fastapi.request"] }
  }
}
DD_API_KEY=… DD_APP_KEY=… npx @winninjs/farol utilization --out utilization.json      # final 14 days
npx @winninjs/farol analyze … --usage utilization.json

CI: the instance workflows have a farol-usage job: set the DD_API_KEY and DD_APP_KEY secrets and techniques and the
repository variable FAROL_DATADOG=true. It reads Datadog as soon as a day and by no means sees the PR’s code. Keys, scopes and
matching guidelines are within the reference.

TypeScript / React frontends TypeScript / JavaScript backends Go Python
Entry factors React Router route tables (object and JSX kinds, lazy routes, cut up route modules); Next.js Pages and App Router (pages, API routes, layouts, middleware); TanStack Router file-based routes GraphQL root operations (schema information and gql templates) and REST endpoints (Fastify/Express type) chi, gin, echo and internet/http routes; gRPC service strategies; principal binaries FastAPI and Flask routes (routers, blueprints, prefixes); Django URLs; MCP instruments, assets and prompts; Celery duties; Temporal workflows and actions; Prefect flows; __main__ scripts
Reach precision per declaration (TypeScript sort checker) per module, per resolver for GraphQL per declaration (go/varieties, interface calls resolved to implementations) per declaration (Python ast with native sort inference)
Contract modifications — GraphQL schema (breaking / harmful / secure) Handler request and response varieties (internet/http, chi, gin, echo); gRPC messages FastAPI parameters, physique, response and Pydantic fashions
Dependencies bundle.json + npm/pnpm/yarn/bun lockfiles identical go.mod + go.sum pyproject.toml (PEP 621, extras, teams, uv, Poetry), necessities.txt + uv.lock/poetry.lock/Pipfile.lock
Diff protection Istanbul coverage-final.json (Vitest, Jest) identical go take a look at -coverprofile protection.py JSON (pytest --cov)
Lint eslint -f json identical golangci-lint JSON ruff JSON
Security built-in guidelines (XSS sinks, eval, hard-coded secrets and techniques, javascript: URLs…) identical gosec (by golangci-lint) flake8-bandit (ruff S guidelines)
Vulnerabilities npm audit --json, pnpm audit --json identical govulncheck -json pip-audit --format json
Suppressions eslint-disable, @ts-ignore, @ts-expect-error, as any… identical //nolint, //lint:ignore, #nosec # noqa, # sort: ignore, # nosec, # pragma: no cowl…
Traffic and errors (non-obligatory) Datadog RUM web page views and errors Datadog APM requests, error spans and callers identical identical

In each language: setting, utilities and CI information (.env*, Dockerfiles, compose, CI pipelines, helm, k8s,
terraform…) in a bit of their very own; incremental evaluation since any commit (--since); urged reviewers from
git blame and CODEOWNERS; studies as a GitHub remark, Markdown or a single-file HTML web page.

farol produces two issues: a PR remark with the decision, the highest information and a take a look at guidelines, and a
single-file HTML report (linked from the remark) the place the evaluate occurs. Here is what every half is for and the way
to make use of it.

Verdict and merge threat rating

What it tells you is how a lot of your time the PR deserves.

Verdict Means What to do
✓ Fast monitor Only new code, assessments or low-risk modifications. Skim the diff and approve.
◐ Quick evaluate Existing code modified in a contained approach, or a weaker sign (low protection, lint errors, a config file). Check the Start right here information, then approve.
⚠ Careful evaluate Wide or silent breakage is feasible: a rating of 60+, a breaking contract change, a high-severity discovering, an untested central file, or code farol couldn’t learn. Read the Start right here information line by line and take a look at what they attain.

The rating (0–100) is the prospect that at the least one dangerous merchandise breaks one thing. Expand What provides to it to see
every merchandise and its factors: the information by attain × untested share, findings, contract modifications, dependencies. The verdict
all the time comes with its causes; learn them earlier than the diff.

The modified code information, riskiest first. Each row reveals what number of present pages or operations run the file, its diff
protection, its findings and its personal threat factors; with Datadog, additionally its site visitors and manufacturing errors. Open the inline
diff: added traces no take a look at runs are marked ○, traces with findings ⚠.

How to make use of it: evaluate top-down and tick Mark as reviewed on every file. The rating drops as you go, so that you
all the time know the way a lot threat is left. Below it come the low-risk information to skim, setting/utilities/CI information
(verify their values per setting), and information that want no evaluate (docs, lockfiles, assessments).

On each web page or operation row, and in a panel on the high: mark an entry level that’s totally behind a flag. Files
that solely flagged entry factors use go away the evaluate, labeled behind a flag fairly than reviewed. Use it for
work-in-progress options shipped darkish, so the remaining rating displays what customers will truly hit.

Every new and affected entry level, as an inventory or a tree by module. Opening one attracts how the change reaches it,
file by file. With Datadog each reveals its site visitors share and its distinct errors, busiest first. Use it to
decide blast radius: a change reaching 3 not often used admin pages is just not the identical as one reaching the checkout.

Each endpoint whose request or response form modified, as breaking (purchasers constructed for the bottom can fail),
harmful (they might misbehave) or secure (appropriate additions), with the precise subject and the calling providers
from Datadog. Use it to substantiate each breaking change is meant and its purchasers are up to date, then tick
checked with purchasers.

A breaking contract change: GET /brands no longer returns response[].name

Security, Dependencies, Coverage

The proof behind the rating: safety findings on the modified traces (with a checked field every), added or bumped
dependencies with identified vulnerabilities, and diff protection per file. A report that was not given reveals as
not verified, by no means as passing.

The new and affected pages or operations to attempt by hand, new ones first, then by the chance of the file that reaches
them. The PR remark has it as a activity record. Use it if you run the department domestically or on a preview setting.
It follows your evaluate: as soon as each modified file behind an merchandise is marked as reviewed, the merchandise is marked too
(✓ information reviewed), or 🚩 behind a flag. Its personal checkbox, for the guide take a look at, stays yours to tick.

Who ought to evaluate: the individuals who wrote the code this PR modifications (git blame, weighted by every file’s threat), plus
CODEOWNERS. The PR’s personal authors and bots are not noted, and inactive individuals are labeled. Use it to request the
one that is aware of the riskiest file, not simply whoever is free.

A Markdown report of the evaluate: the preliminary verdict and rating, the rating left now, the flagged entry factors, the
reviewed information, and the checked findings and contract modifications. Copy as Markdown and paste it within the PR as your
evaluate remark, so the following particular person is aware of what was checked out.

After a push to an open PR, the remark carries a second report with solely the commits for the reason that earlier push
(analyze --since ; after a force-push, from its merge-base). Its verdict, rating and Start right here cowl simply
these modifications. Use it for the second spherical of a evaluate: verify that the fixes do what was requested and nothing
else, then return to the total report provided that the brand new commits attain someplace new.

Kept in Details and a collapsed block of the remark, so reviewers type their very own opinion first:
remoted (solely provides), touches-existing (present code modified), world (a worldwide file, manifest or important
dependency) and unknown (a part of the change couldn’t be learn: by no means secure). Every cause code is in
docs/reasons.md.

  1. Diff the merge-base and the pinnacle, detecting renames and ignoring whitespace-only and trailing-comma traces.
  2. Read each timber with out operating something: the TypeScript compiler API, go record + go/varieties (offline), Python ast. From them, the entry factors and a graph of which declaration makes use of which.
  3. Compare declarations by a hash of their code, so feedback and formatting by no means rely. New declarations and entry factors are additive.
  4. Reach: from every modified declaration to each entry level that runs it, holding the shortest chain.
  5. Classify, weigh and plan: class, rating, verdict, information to start out with, take a look at guidelines.

On 662 previous commits of 4 repositories, quick monitor had 0 issues in 56 commits and the rating’s AUC was
0.72–0.83; run farol calibrate by yourself historical past.
The particulars per language are in docs/how-it-works.md, and the explanations behind each alternative in
docs/DECISIONS.md.

  • analyze by no means executes code of the analyzed repository and by no means makes use of the community. The Go and Python helpers use solely their normal libraries and solely parse.
  • Only remark (GitHub API) and utilization (Datadog API) discuss to the community. Error messages will not be copied from Datadog, solely error varieties.
  • In CI the job that runs your code has no secrets and techniques and no write token; the job that feedback by no means runs your code.
  • Shadow mode: farol informs, it by no means approves, requests modifications or fails a verify.
  • Static studying: values constructed at runtime are invisible (computed route paths, getattr, importlib, DI containers, registries stuffed in loops). When an entry level can’t be learn, the PR is unknown; when a name can’t be resolved, farol assumes it reaches extra, by no means much less.
  • TypeScript frontends: React Router, Next.js and TanStack Router (file-based) solely: no code-based TanStack route timber, Remix/React Router file conventions, Vue or Svelte. JavaScript information, renamed information and TypeScript backends use module-level attain.
  • Go: route prefixes from middleware stacks aside from chi/gin/echo teams will not be utilized, and venture varieties that wrap a router with their very own registration API (Gitea’s net.Router) will not be learn. Python: Django REST Framework routers will not be learn.
  • The rating and verdict thresholds are heuristics checked on a number of repositories. Calibrate them on yours.

We have already got an AI reviewer. Why add farol? They reply completely different questions. The agent feedback on the traces
within the diff; after it, farol tells the one who approves how dangerous the merge is and which information carry the chance, from
static evaluation of the entire program. Run each: farol’s remark and report sit subsequent to the agent’s, and neither blocks
the merge.

Is it free? Yes. farol is open supply below the MIT license, with no account, hosted service or paid tier: run it
with npx @winninjs/farol or the GitHub Action winnin/farol/motion.

Will it decelerate CI? No. farol runs after your assessments and reuses their studies. The evaluation takes about 3 s for
a 300-file Python service, 8–10 s for a big TypeScript monorepo or a Go service with a chilly cache, and below a
second for the bottom when its helper output is cached.

Can I exploit it exterior GitHub? Yes. analyze, html and report work anyplace; solely remark is
GitHub-specific. Post the output of npx @winninjs/farol report along with your platform’s API.

The report says “not verified”. That report was not given, or the trail is flawed. Paths given to analyze are
relative to the present listing; paths in farol.config.json are relative to the venture.

A web page I modified is just not listed. Run npx @winninjs/farol routes to see the entry factors farol reads, and
npx @winninjs/farol affect
to see what reaches a file. Unreadable route constructs are listed below diagnostics.

Go: “farol reads Go modules offline: run go mod obtain”. The module cache lacks a dependency of the bottom or the
head. Run go mod obtain for each earlier than analyzing.

Monorepo? Point --cwd on the app. Paths keep relative to the repository root, and modifications in apps the venture
doesn’t use are listed as exterior it.

Contributions are welcome: route adapters, frameworks, languages, report codecs and higher heuristics. See
CONTRIBUTING.md for the setup, the structure and the conventions, and
SECURITY.md to report a vulnerability.

MIT © 2026 Winnin



Source link