farol farol
Free and open source · CLI and GitHub Action

Know the risk of merging, and where it lives.

Agents write the code and agents review it. The last call is still a person's. farol tells that person how risky the merge is, which files carry the risk and what they reach, so the riskiest changes get the most attention instead of the same skim as everything else.

$npx @winninjs/farol routes

or on every pull request: uses: winnin/farol/action@main

Free, MIT licenseNo account, no serviceNever executes your codeNever blocks a merge
farol report · single HTML file, works offline
A farol report of an example pull request: careful review at 74/100, the two files to start with, and three breaking contract changes

Every claim in the report comes with the chain of calls behind it. Explore a real one →

Why farol

Review effort should follow risk.

Agents now write much of the code and review it too, so the human approval is the scarce part. Spread evenly over every pull request it turns into a skim, and a skim is how a one-line change to a shared hook breaks forty pages.

farol makes the risk explicit before anyone approves: a verdict that says how much review the merge needs, and the files that carry the risk, ranked. Low-risk pull requests can go fast; risky ones get read line by line, starting where it matters. The Claude Code team describes the same principle in how they do code review: “The change sets the tier, not the author.”

The riskiest files, first

A forty-file pull request usually has two or three files that can hurt. farol ranks them by reach, diff coverage and findings, so they get the closest read.

Reach, not file names

A declaration graph built with the real compilers: a change to formatPrice lists the pages that render it.

Contracts before clients

Removed response fields, new required parameters and changed types, per endpoint, in GraphQL, FastAPI, Go handlers and gRPC.

Fails closed

When part of a change cannot be read, farol says unknown and asks for a careful review. It never calls something safe by default.

Where it fits

After the AI review, before the human approval.

farol does not replace your review agent. Let the agent comment on the lines; when it is done, farol gives the person who approves what the agent cannot reliably give: the risk of accepting the change, and where it lives.

An agent writes the change

Fast, and often larger than a person would write it.

An agent reviews the lines

Bugs, style and local mistakes, comment by comment.

farol measures the risk

What the change reaches, broken contracts, untested lines and findings, turned into a verdict and a ranked list of files.

A person decides

A quick look when the risk is low; a careful, file-by-file read of the risky parts when it is high.

What each one is good at:

Your AI reviewer

  • Read the diff, and whatever context fits in the prompt
  • Tell you what may be wrong in these lines
  • Answer differently on every run
  • May sound confident when unsure

farol

  • Reads the whole program at the base and the head, with the compilers
  • Tells you how risky the merge is, which files carry the risk and what they reach
  • Same pull request, same report, with the call chain behind each claim
  • Says unknown and asks for a careful review
The report

A review plan, not a wall of warnings.

One comment on the pull request and a single-file HTML report, built for the person reviewing it.

⚠
Verdict and merge risk scoreFast track, quick review or careful review, with the reasons and what adds to the score.
1
Start hereThe riskiest files first, with inline diffs: untested lines marked ○, findings ⚠. Tick them as you go and watch the score drop.
↳
Pages and endpoints reachedEvery entry point the change runs, drawn as the chain of files that reaches it.
≠
Contract changesBreaking, dangerous and safe changes to what each endpoint receives and returns.
✓
Test planWhat to try by hand. It follows your review: items whose files you reviewed are marked.
±
Since your last lookAfter a push, a second report with only the new commits, so a second round starts where the first ended.
The contract section of a farol report: GET /brands no longer returns response[].name

Also in the report: suggested reviewers from git history, findings from your linters and audits, production traffic and errors from Datadog (optional), pages behind a feature flag, and a copyable record of the review.

Free and open source

A CLI and a GitHub Action. Nothing to sign up for.

farol is MIT-licensed and free to use, on any repository. There is no account, no hosted service and no telemetry: it runs on your machine or in your CI runner.

On your machine

Run it with npx on any branch; it writes a JSON result and a single-file HTML report.

npx @winninjs/farol analyze --base origin/main --head HEAD --out farol.json
npx @winninjs/farol html --in farol.json --out farol.html

On every pull request

Use the GitHub Action after your tests: a comment on each push, with a link that opens the report in the browser.

# .github/workflows/farol.yml (excerpt)
- uses: winnin/farol/action@main
  with:
    command: analyze
    base: ${{ github.event.pull_request.base.sha }}
    head: ${{ github.event.pull_request.head.sha }}
    out: farol.json

Complete workflows for TypeScript, Go and Python →

Stacks

Reads the frameworks you already use.

Entry points come from your routes, operations and jobs. Diff coverage, lint and vulnerabilities come from the reports your CI already produces.

TypeScript & React

Pages and layouts, read with the TypeScript type checker, declaration by declaration.

React RouterNext.jsTanStack RouterGraphQLFastify / Express
Vitest or Jest coverage · ESLint · npm/pnpm audit

Go

Routes, RPC methods and binaries, read with go/types, offline. Interface calls reach their implementations.

chiginechonet/httpgRPC
go test -coverprofile · golangci-lint + gosec · govulncheck

Python

Routes, tools, tasks and workflows, read with Python's own parser. Nothing is imported.

FastAPIFlaskDjangoCeleryTemporalPrefectMCP
pytest-cov · ruff (with bandit rules) · pip-audit
How it works

Static analysis, end to end.

No model in the loop and nothing executed: the same pull request always gives the same report.

Diff

The merge-base against the head, with renames; whitespace-only lines are ignored.

Read both trees

The TypeScript compiler, go/types or Python's ast build a graph of which declaration uses which.

Reach

From each changed declaration to every entry point that runs it, keeping the shortest chain.

Plan

Class, risk score, verdict, files to start with and a test plan, in the PR comment and the HTML report.

Get started

One config line, then run it.

You need Node.js 22+ and git (plus Go or Python 3.11+ for those projects). Describe the project once, check what farol sees, then analyze a branch.

  • Add your coverage, lint and audit reports to sharpen the score
  • Copy a ready workflow to get a comment on every pull request
  • Optional: production traffic and errors from Datadog

Recipes per stack →  ·  Every option →

# 1. describe the project
echo '{ "routes": { "file": "src/routes.tsx" } }' > farol.config.json

# 2. check the pages and endpoints farol sees
npx @winninjs/farol routes

# 3. analyze your branch and open the report
npx @winninjs/farol analyze --base origin/main --head HEAD --out farol.json
npx @winninjs/farol html --in farol.json --out farol.html
Built to be trusted

Your code stays yours.

Never runs your code

Go and Python are read by small helpers that only parse, from the standard library. Your tests run in your own CI job.

Never sends it anywhere

Analysis is local or in your runner. Only the PR comment (GitHub) and the optional Datadog read use the network.

Shadow mode

farol informs. It never approves, requests changes or fails a check: reviewers decide.

Built in the open.

farol is free and MIT-licensed. If it helps your reviews, a star helps other teams find it. Issues, ideas and pull requests are welcome, especially new frameworks and languages.