NeonDiff is a local-first AI PR reviewer for teams and agents that want the review loop without handing every diff to a hosted review SaaS.
Use it when you want a GitHub App to review pull requests from a local worker, with your GitHub installation, your provider keys, your repo policy, and public-safe evidence for every live posting decision.
From NeonDiff 1.1.0, review of repositories that GitHub reports as public is
free, with no license key, through the GitHub Action, neondiff review-pr --ci, and the self-hosted
worker (daemon, run-once, review-pr, providers verify).
The Mac app reviews public repositories without a key (choose "Public repositories only" in onboarding); private repositories need Solo or Team.
Private, internal, and unknown-visibility repositories need an active NeonDiff
license; unknown visibility fails closed.
The npm CLI 1.0.x requires API-backed activation for every repository.
Paid licenses are flat, with no per-seat pricing: Solo $9/mo or $90/yr for one developer, Team $290/yr per GitHub organization. Solo comes with a 7-day trial and Team with a 30-day trial. Existing subscribers keep their current price, and legacy lifetime licenses remain honored but are no longer sold. You bring your own model provider key or local model; NeonDiff does not include hosted model credits. NeonDiff is source-available commercial software, not open-source software.
Website · Setup · GitHub App Install · Contributing · Agent Instructions · Security · Code of Conduct · License · License Boundary · Pricing · Providers · Local checkout review · systemd · Docker · CI Runner · Known Limitations · Precision Badge · Roadmap · Repository
AI-built software has made PR volume and review fatigue worse. NeonDiff is built for the opposite posture: run locally, read only the pull request it is asked to review, post only current-head comments, and keep provider/model cost under the user's control.
The current implementation grew from the internal evaOS review bot. This repo is now the NeonDiff implementation surface; older internal naming is legacy operator history, not the public product name.
NeonDiff currently provides:
- a GitHub App based pull-request reviewer
- current-head duplicate suppression for
{repo, pr, head_sha} - dry-run review output before live posting
- inline finding placement only on current RIGHT-side diff lines
- secret-looking finding suppression
- stale-head checks before command-triggered review, planning, and posting
- local evidence logs with secret redaction
- repo profile and policy configuration
- JSON-first operator commands for status, queue, dashboard, cooldowns, and why
- offline eval packets for comparing seeded defects, CI, human review, and bot findings
It intentionally does not approve PRs, merge branches, push repairs, expand GitHub permissions by profile alone, or claim calibrated review accuracy before evals prove it.
Requirements:
- Node.js 26 or newer
- npm
- a GitHub App installed on the repos you want to review
- a model/provider path configured locally, such as GLM/Z.ai, Ollama, or a future OpenAI-compatible provider slot
v1.0.5 verification notice: Before relying on v1.0.5, verify
npm view neondiff@1.0.5and the matching non-prerelease GitHub Release plus its typed publication proof. If those identities do not agree, keep using the verified v1.0.4 package; v1.0.3 and earlier do not enforce this boundary.
Recommended package install after v1.0.5 is published and verified:
npm install -g neondiff@1.0.5If the required v1.0.5 registry and GitHub Release identities do not agree, use the immutable verified predecessor instead:
npm install -g neondiff@1.0.4Installer script path:
curl -fsSL https://www.neondiff.com/install | shThe installer script checks for Node.js 26 or newer and installs the same npm package. To preview without changing your machine:
curl -fsSL https://www.neondiff.com/install | sh -s -- --dry-runThe public paid B0 Mac beta uses a separate checksum-bound worker bundle from
the same immutable GitHub prerelease as the app rather than an unpublished npm
version or an unpinned source checkout. No invitation is required when the
versioned public GitHub prerelease is published and the neondiff.com
purchase/download path is live.
The worker installer requires Node.js 26 or newer resolving through the
approved stable path /opt/homebrew/bin/node or /usr/local/bin/node.
When the app reports Worker update required, choose Install / Update Local
Worker. Verify the outer worker bundle ZIP against the prerelease notes, then
verify the extracted release manifest and inner .tgz tarball against the
published SHA-256 values before following the dry-run-first update and rollback
commands in docs/SETUP.md.
Retain each verified worker bundle: rollback is available only after a second
checksum-managed candidate has been installed, and requires the prior
candidate's exact manifest, published manifest SHA-256, and tarball. The first
migration cannot roll back to an unbound original invocation.
This preserves the existing config, LaunchAgent identity/environment, provider
state, repository allowlist, and credential stores. It is not a public npm,
Sparkle, or automatic worker-update claim before that immutable prerelease is
published. The installer keeps a stable Homebrew Node command in the LaunchAgent
whenever that command resolves to the same binary as process.execPath, including
when migrating an existing versioned Cellar path. Routine Homebrew upgrades then
do not strand the worker on a removed runtime.
Operator/contributor source checkout fallback:
git clone https://github.com/electricsheephq/evaos-code-review-bot-neondiff.git neondiff
cd neondiff
npm install
npm run buildIf you intentionally use the source checkout without the global package,
substitute ./dist/src/cli.js anywhere this guide calls neondiff. A source
checkout is not a supported B0 worker update and cannot replace the
checksum-bound prerelease bundle.
For private review-pr --ci, follow the CI license key-file setup; local license activate does not supply the CI key file.
Follow docs/SETUP.md for the CLI-first setup path (the first-run path on non-Mac platforms and the operator/advanced path on Mac). The short version is:
neondiff init --config config.local.json
neondiff dashboard --config config.local.json
export NEONDIFF_GITHUB_APP_ID="<github-app-id>"
export NEONDIFF_GITHUB_APP_CLIENT_ID="<github-app-client-id>"
export NEONDIFF_GITHUB_APP_PRIVATE_KEY_PATH="/absolute/path/to/neondiff.private-key.pem"
neondiff doctor github --config config.local.json --json
neondiff providers list --config config.local.json --json
neondiff providers doctor --config config.local.json --json
neondiff doctor --config config.local.json --jsonFor the Mac customer journey, the native macOS app (apps/neondiff-desktop) is
the human first-run surface. The local HTML dashboard is an operator/diagnostic
surface for CLI-first and non-Mac setups, not the product UI. It shows license
status, GitHub App status, daemon status, and provider readiness, and its
provider card includes a Verify API Key control that reports redacted
pass/fail output.
The managed native path binds activation and private-repository token issuance
to the same Keychain-backed broker device identity and exact GitHub-selected
repository. The raw Activation Key remains Keychain-owned: it crosses bounded
stdin for activation and the fixed-origin broker HTTPS request body for private
token issuance only, and is never placed in argv, config, logs, or broker
storage. That production path remains behind its rollout kill switch until the
paid-beta canaries pass. The native source now composes the managed broker only
when a release bundle carries the exact paid-mac-beta-v1 Info.plist contract,
fixed production broker origin, and explicit broker-enable marker. Those public
build values are absent by default, so ordinary/debug bundles stay quarantined;
the server kill switch and every broker/entitlement decision still fail closed.
The public paid B0 BYO beta build uses a separate exact
paid-mac-beta-byo-v1 release contract with NeonDiffBYOGitHubEnabled=true and
no managed-broker fields. That contract enables the existing local direct/BYO
path and API-backed native activation without a hidden defaults mutation. It
supports keyless public-only review; private repositories need Solo or Team. The signed release app contains a sealed NeonDiff worker built from the
exact reviewed source and a pinned, SHA-256-verified official Node runtime. A
clean Mac therefore does not need a global CLI or separate worker install for
the native setup and review path. The separate checksum-bound bundle remains
available for the customer-owned local-agent path; its explicit first-install
command installs only its verified CLI in a private current-user version
directory, writes a credential-free installation marker, and creates or loads
no LaunchAgent. After repository, provider, App-access, and any required activation
verification, the signed app can install a secret-free LaunchAgent whose
executable is the signed NeonDiff app. Before releasing either Keychain secret,
the app validates its exact Developer ID signature and the running sealed
worker process, then pipes one bounded JSON envelope to that process's stdin.
The plist contains only the
public App ID, config path, launchd label, the non-secret broker device ID used
by the existing API-backed activation, and the signed app path—never a key
value or key-file path. The headless app re-derives that device ID from its
Keychain identity and rejects a mismatched plist before releasing credentials.
Review and daemon readiness remain separate gates.
The background worker reviews new pull requests on the repositories you
enrolled and posts its reviews; in dry-run mode it writes them to local
evidence instead.
The daemon may also run the independently admitted issue-enrichment lane. A
heartbeat proves service liveness only and never authorizes a PR post.
Issue-enrichment success requires lane-specific result evidence. One-off native live PR posting outside the background worker uses only the exact scoped review-pr dry review plus explicit same-head
confirmation; the matching approval is consumed
atomically.
The immutable published prerelease and clean-Mac artifact proof remain
distribution gates. Unsigned development builds still require an executable
global or checksum-managed worker before native first run
exposes Initialize Local Config (non-destructive; never force-overwrites),
Add Repository, Apply Repository, and Verify App Access without a
terminal or operator config edit. Apply Repository writes both the selected
pilotRepos allowlist and an enabled policy profile for each selected
repository, preserving any existing per-repository policy fields. When the
verified account has no bot yet,
the app allocates that isolated new-bot plan before it presents the
initialization action; it never initializes the _unselected placeholder. If
the customer quits during that setup, the next
launch restores the same pending bot and config path when its saved selection
is still current. If an older build or manual rollback selected a verified
existing bot under the same account, the app keeps that authoritative bot
selected and resumes the validated pending setup only after the customer
explicitly chooses NEW BOT. A new native config receives bot-isolated runtime,
state, evidence, and license paths beside that config instead of reusing the
packaged worker's placeholder /tmp/neondiff tree. If one exact
checksum-managed local worker already exists for the selected LaunchAgent
label, the app may reuse it for non-secret legacy commands. Credential-bearing
commands always use the sealed worker; the app never sends Keychain material to
a global, customer-writable, or checksum-marker-only executable. A verified
legacy LaunchAgent remains supported without migrating or exporting its
existing credential environment.
This
source path does not prove customer-safe private-key custody, a compatible
published CLI, signing, billing, canaries, or release readiness.
After Checkout displays a one-shot NeonDiff Activation Key, return to the
native License pane and paste it there. Buy an Activation Key opens the
public pricing page without hiding that secure existing-key field, so returning
from the browser does not require a second purchase or an operator-only state
change. The app stores the key through its existing Keychain-only activation
path and clears the plaintext field after the customer continues.
When the signed-in account already contains a verified bot and its App identity
matches a local launchd/config candidate on this Mac, the native app reuses that
authoritative account/bot intersection instead of asking the user to initialize
or re-enter the existing worker credentials. It may show GitHub, provider,
entitlement, and repository setup as configured while still requiring fresh,
repository-scoped GitHub and activation verification before new review work.
If that existing worker monitors more than one repository, the native app keeps
the full allowlist intact and asks the user to choose one Review Target.
Native activation and current-access verification bind to that exact target;
the app uses the bounded doctor github --repo owner/repo form rather than
rescanning the worker's complete allowlist. Selecting it does not remove,
disable, or rewrite the worker's other repositories. The app may reuse the
exact matched LaunchAgent's App ID and private-key file coordinate only inside
the child process for that config; it never copies the key into the app,
Keychain, arguments, logs, or UI. Overview can then run review-pr for one
selected repository and pull request through the configured provider. Live
posting remains disabled until that exact target and config revision return a
successful dry-run head and the user confirms the pinned head. A transport
failure revokes that approval instead of permitting a blind retry. For a
customer multi-repository worker, daemon-wide start remains blocked; a verified
internal-admin worker may start it and then reviews its whole allowlist, with
license admission checked for every pull request. The selection and
dry-run approval fail closed if the config, target, pull request, workspace, or
head changes.
The same Verify existing access action then runs credential-free
license status --refresh true through that exact matched worker and config.
It does not read, copy, migrate, or prompt for the worker's Activation Key.
Useful work unlocks only when GitHub reports the exact repository visibility
and the live API response returns an active entitlement covering that
visibility; missing, unknown, expired, revoked, malformed, or offline proof
fails closed.
During launch it shows a bounded restoring state while that authorized
account/bot/config intersection is checked; it does not flash empty first-run
setup or claim that the existing configuration is missing.
Local config alone can never invent account membership or unlock a review.
This source composition is not proof that the production broker is enabled,
that billing is live, or that a signed customer artifact exists. Update,
rollback, daemon admission, and live-review behavior still require exact signed
candidate validation before distribution.
The native Providers pane reads the active review runtime from the inspected
config. When codexRuntime.enabled is true, it shows the exact Codex CLI path,
model, and reasoning effort and treats that existing authenticated CLI session
as the review execution backend; NeonDiff never reads or stores its OAuth
material. Otherwise the pane reads and edits the saved providers registry,
not the legacy desktop.openAICompatibleEndpoint field. Load config, Preview,
and Apply the exact selected provider before Verify is enabled; verification
pins both the provider ID and inspected config revision. A provider with
authMode: zcode-app-config or none does not use a NeonDiff-stored API key,
so the native app reports its loaded config without showing a false missing-key
state. api-key-env providers retain the Keychain and verification gate.
Create or install the GitHub App before expecting PR reviews to run. The App
must be installed on the same selected repositories listed in pilotRepos; see
docs/github-app-setup.md for the permission set and
selected-repo install path. The rollout-disabled managed desktop source uses the
broker-issued GitHub App install/OAuth URL and keeps polling its device-bound
completion state while authorization is pending. A fresh installation callback
wins without asking the customer to authorize twice. The unshipped source still
contains Device Flow as an existing-install fallback. Before B1 release, #613
must move that managed customer path to broker-hosted web OAuth with state and
PKCE; Device Flow remains only an optional CLI/headless fallback. Both paths
must verify the exact user-authorized installation/repository intersection, and
installation tokens remain the only review credential. Legacy direct-install
builds still read their public client ID from local config.
Do not store the GitHub App private key, provider API key, license key, tokens, or customer data in this repository. Keep local config, secrets, state DBs, and evidence outside git.
Platform operator paths:
| Platform | Daemon path | Status |
|---|---|---|
| macOS | launchd with docs/launchd.md | Tested beta operator path |
| Linux | systemd with docs/systemd.md | Packaged and covered by Ubuntu smoke tests |
| Docker | Compose recipe with docs/docker.md | Packaged for local/self-hosted workers |
| CI runners | One-shot review or dry-run with docs/ci-runner.md | Documented for Ubuntu-style runners |
| Windows | CLI-only source/package usage | Untested; no supervised daemon claim |
On Linux (hosts, Docker and CI runners), Codex checkout reads need unprivileged user namespaces, which Ubuntu 23.10 and later block by default. NeonDiff checks this before using checkout reads and falls back to diff-only with a warning; see Codex sandbox on Linux to enable them.
NeonDiff is local-first for checkout state, credentials, config, evidence, and operator control. Model egress depends on the provider you choose: local or self-hosted endpoints can keep prompts and diffs on your machine or network, while hosted providers such as GLM/Z.AI through ZCode or hosted OpenAI-compatible gateways receive the review prompt and diff context required to answer.
For setup details, see docs/providers.md. Useful provider resources:
- Z.AI quick start, Z.AI API reference, and Z.AI OpenAI SDK compatibility
- Z.AI current GLM coding model guidance
- Ollama OpenAI compatibility docs
- cheahjs/free-llm-api-resources for volatile free/trial provider discovery, not NeonDiff compatibility proof
Small NeonDiff compatibility matrix:
| Provider or resource | NeonDiff status | Egress posture |
|---|---|---|
| GLM/Z.AI through ZCode | Default beta path; tested by NeonDiff as the current live review route | Hosted provider receives prompts and diffs |
Ollama on localhost |
Compatible by interface; provider doctor/smoke only until adapter proof promotes live review | No-egress only when endpoint and model are local |
| LM Studio, vLLM, or local gateways | Compatible by interface; tracked for provider proof before live promotion | No-egress only for local/self-hosted endpoints |
| Hosted OpenAI-compatible BYOK gateways | Compatible by interface; remote smoke and live review proof required | Hosted provider receives prompts and diffs |
| Free-provider catalogs | Resource only; untested by NeonDiff unless a provider has its own proof issue | Usually hosted; check each provider |
For the blunt launch-facing matrix, including macOS/Linux and backend limits, see docs/known-limitations-and-provider-status.md.
Run a dry-run review before any live posting. Replace --repo owner/name and
--pr 123 below with a repo already listed in your local config's
pilotRepos and an open PR number on that repo — review-pr fails with "repo
must be present in configured repos" if the repo is not in pilotRepos:
neondiff review-pr \
--config config.local.json \
--repo owner/name \
--pr 123 \
--expected-config-revision <verified-config-revision> \
--dry-run true \
--zcode trueUse the exact configRevision returned by the successful provider verification.
Inspect the JSON result and evidence path. Only switch to --dry-run false
after setup checks, focused tests, and the relevant GitHub issue record the
exact repo, PR, head SHA, config path, and public-safe evidence.
If you are contributing as an AI coding agent:
- Read AGENTS.md.
- Reuse or create a GitHub issue before meaningful work.
- Write a failing test, smoke, or docs/eval gate before implementation.
- Keep the PR linked to the issue with
Closes #<issue>orRelated: #<issue>. - Record validation and evidence without raw secrets, raw customer data, or private logs.
For public issue intake and launch-influx handling, use docs/triage-policy.md.
Useful public-product issues:
- #103 NeonDiff public product roadmap
- #104 license and commercial boundary
- #105 pricing implementation
- #107 CLI package and local daemon public install flow
- #113 agent-first CLI and API documentation contract
Default behavior:
- review only configured repos
- skip draft PRs by default
- at most one review per
{repo, pr, head_sha} - never submit
APPROVE - request changes only for validated high-severity findings
- rank findings by severity, then validated confidence; the inline-comment cap keeps the highest-confidence findings
- suppress same-run near-duplicate findings and secret-looking findings instead of posting them
- learned signals (confidence floors, category precision floors, repo-memory false-positive suppression, self-consistency refutation) only ever make the review quieter — they demote or suppress, never escalate
- re-fetch PR state before live operations
- keep ZCode/model tools read-only during review
- periodically prune only stale, clean, inactive NeonDiff review worktrees; cleanup is configurable and fails closed when open-handle safety cannot be proven
- fail closed when credentials, provider readiness, repo policy, or current-head proof is missing
Not claimed:
- not claimed: public launch is complete
- final legal/license adequacy
- hosted review service
- auto-merge or branch repair
- generic GitHub issue mutation
- enterprise or customer-ready security
- calibrated confidence display (stays redacted until the evidence gate in docs/calibration-loop.md passes and a human flips it)
- desktop client readiness
NeonDiff's precision badge is public-safe by default: the generated Shields
endpoint at docs/badges/precision.json shows a gray calibrating (n=...)
state until the calibration aggregate passes the existing public-confidence
gate and a human flips confidenceCalibration.publicDisplay.mode to
"calibrated". Below that gate, no public percentage is displayed.
Copy-paste README badge snippet, replacing the branch if you publish from
somewhere other than main:
[](docs/precision-badge.md)The badge JSON is generated from NeonDiff's own aggregate evidence; the tool does not accept a public-percent override and does not flip calibrated display mode. See docs/precision-badge.md for the review rules behind that contract.
The current repo is the source-available NeonDiff implementation. The public roadmap is
tracked in #103.
Provider registry, .neondiff.yml, desktop client signing/appcast, wiki exports,
and marketplace packaging each have separate
issues and must not be treated as shipped until their PRs and proof gates close.
The ranking/scoring and calibration program (#278) is shipped: confidence-aware ranking and caps, validated-category precedence, same-run near-duplicate suppression, robust false-positive learning, opt-in self-consistency re-checks, risk-weighted queue priority, and the full calibration loop (post-merge outcome observer → label aggregation → human-gated promotion — see docs/calibration-loop.md and docs/vision.md). Shipping the loop's tooling does not flip the calibrated display: that remains off until the evidence gate passes on real review volume and a human applies it. See CHANGELOG.md for the per-version record.
Use LICENSE.md and docs/license-boundary.md as the canonical public license language. Do not copy older issue comments or release notes into public product surfaces when these files are more recent.
For live release operation, use docs/beta-release-runbook.md and docs/release-governance.md. Documentation-only changes do not restart launchd or promote a release by themselves.
For public release readiness, use
docs/public-release-manifest.json with
neondiff release-status --public-release-manifest docs/public-release-manifest.json --expected-public-version <public-version-tag>.
Replace <public-version-tag> with the actual semver tag, such as
v1.0.0; the CLI rejects literal placeholders. The manifest is the
compact version/alignment surface for setup docs, release notes, license API
state, and update-channel readiness.
