AI code review that proves your code stayed private. It reviews your pull requests inside hardware-sealed enclaves, so nobody sees your code, us included, and every review comes with a receipt you can check yourself.
Install on GitHub · See a real review · Check a receipt
A second pair of private eyes on your pull requests. (Say the repo's name out loud.)
When a pull request opens, a check named Private Investigator appears within seconds. A few minutes later a review lands: findings on changed lines as inline comments, the rest in the review body, and at the end what was verified and a link to the review's receipt. The page shows a real one.
- Sealed hardware. Your code is read only inside attested enclaves (Intel TDX, with NVIDIA confidential GPUs for the model), and sent to the model end-to-end encrypted. The servers in between relay only ciphertext.
- Signed answers. Every reply the review uses is signed by the model's enclave, over the exact request and response.
- A receipt anyone can check. It records the attestations and signatures, and holds hashes, never your code. The page re-checks it in your browser.
The details, and the limits of the proof, are in What a run proves.
It is a second opinion, not a sign-off, and every review says so.
npm run eval measures it on pull requests whose bugs are known, with the
same review the App and the Action run:
- Planted bugs (a dropped auth check, an off-by-one, an XSS sink, a logged secret, a cross-file break, a swallowed error, a race): the App and the Action each caught every one, in 4 runs of 4. These cases live in a private repository for now, and the App's runs used a longer reply limit than the hosted App's 4,096 tokens; the eval now runs it as hosted.
- False positives: none, in 8 runs on a clean pull request and on one where an earlier review raised a known false positive.
- Real bugs: it misses regressions that span files in money and permission
paths. On
near-agencies#94, two such bugs that Claude's review caught, it found one in 1 run of 4 and the other in none. Every configuration tried so far misses them: more reasoning, the full changed files, an invariants prompt, a deep question-driven pass, and tracing each changed function's callers.
New cases and models are measured before any claim here changes. React 👍 or 👎 on a finding: that is how it is measured on real code.
The CLI and GitHub Action also accept explicit commit reviews. The hosted App
still uses /review on PRs; it does not review standalone commits yet.
node review/review.mjs --repo owner/repo --commit COMMIT_SHA
node review/review.mjs --repo owner/repo --base BASE_REF --head HEAD_REFUse GITHUB_TOKEN and NEARAI_API_KEY as for PR reviews. Posting needs
contents: read and checks: write with an installation token (including the
workflow's github.token). Findings and the receipt hash appear in an
informational Private Investigator check on the resolved head SHA. The receipt
records the repository and exact base/head SHAs. A running check is created
before model credits are spent; a failed review marks it as failed. A completed
review is neutral, even when findings exist: it is informational.
--dry-run previews the check without publishing and works with a read-only
token. It still runs the model review and spends model credits.
The complete check report is saved as private-review.json before publishing
or checking GitHub's output-size limit. --review path.json chooses another
path, including for dry-runs. This file contains findings and may include code;
it is separate from the receipt, which contains hashes rather than findings.
The Action retains it as a separate, uniquely named private-review.<id>.json report artifact even if publishing fails. Each invocation uses its own output directory, so a failed invocation cannot reuse an earlier report or receipt. CLI filenames remain unchanged.
An oversized report is saved in full and the check fails; no partial findings
are published. With PR reviews, --review also saves the report when supplied.
--receipt path.json selects the receipt file. Ordinary user/OAuth tokens cannot
publish checks; for local use, choose a GitHub App installation token or dry-run.
A single commit is compared to its first parent, including merge commits. Ranges require the base to be an ancestor of the head; resolve a merge base explicitly for diverged branches. Root commits and comparisons reaching GitHub's 300-file limit are refused; empty ranges stop without spending model credits. Rubric files come from the resolved base revision.
For a manual Action workflow, use explicit inputs (replace the pin with the feature's released commit SHA):
name: Review commit range
on:
workflow_dispatch:
inputs:
base:
description: Ancestor revision
required: true
head:
description: Head revision
required: true
permissions:
contents: read
checks: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: MultiAgency/private-ai/review@<commit sha>
with:
nearai-api-key: ${{ secrets.NEARAI_API_KEY }}
base: ${{ inputs.base }}
head: ${{ inputs.head }}Alternatively pass commit: alone. Explicit commit/range inputs take precedence
over the event's PR default. Explicitly combining them with pr: is rejected.
With no commit/range inputs, PR and /review comment events keep reviewing the
PR that triggered the workflow.
Automatic push reviews are not enabled by this example. Existing PR re-reviews
continue to check earlier findings and report those still open.
Install it
and pick the repositories. Reviews are opt-in: someone with write access
comments /review on the pull request, or presses Re-run on its check. Opening
or pushing alone does not start a review. New installations get a 30-day trial
with 40 reviews; each check says how many reviews and days are left. When the
trial ends, the check points at the upgrade page. A shared monthly pool still
caps total free usage across all installations.
- Where your code goes: an attested OutLayer enclave fetches it from GitHub with the App's token and sends it end-to-end encrypted to the attested NEAR AI model. Each step of the review is an OutLayer run whose attestation binds what it returned, and nothing that leaves a run names your repository or holds your code.
- The receipt is published to OutLayer's public storage. It commits to your pull request with a salt that only the review's link carries, so the public receipt does not name your repository; the link opens and checks it.
- What its operators can see: GitHub's event notices (titles, descriptions, who pushed) pass through the relay, which forwards only ids and holds them only while a review runs, plus review counts per installation and when steps run. Never code, never the review.
- What it keeps: a review's working state is sealed in the enclave's storage and deleted when the review finishes or fails. What stays is the review on your pull request, the public receipt (with its count of new findings), the installation's trial (start time and review count), the shared monthly free-pool count, and a sealed marker per request (a hash of its ids, and when it ran) that stops a repeated delivery from reviewing twice. Uninstalling stops reviews; nothing else holds your code.
- Who can start a review: a
/reviewcomment (write access) or Re-run on the check, through our relay. The relay drops a/reviewfrom someone with no history in the repository; the enclave checks the rest on GitHub.
Runs on your GitHub runner, which already has your code, with your own NEAR AI
Cloud key, so no enclave of ours touches it. The page
writes the workflow for a repository, pinned to the latest commit. By hand: add
a workflow, and a NEAR AI Cloud API key as the NEARAI_API_KEY secret.
The workflow reviews new commits and accepts /review comments from someone
with write access. It must be on the default branch for comment events to run.
name: private-review
# Private AI review: the model reads this pull request only inside a NEAR AI
# Cloud enclave, end-to-end encrypted. See https://github.com/MultiAgency/private-ai
on:
pull_request:
types: [opened, synchronize, ready_for_review, reopened]
issue_comment:
types: [created]
# Run by hand (Actions tab, Run workflow) to check the setup: no code is read.
workflow_dispatch:
jobs:
# A refused comment cannot load the model key or cancel an ongoing review.
gate:
if: >-
github.event_name == 'workflow_dispatch'
|| (github.event_name == 'pull_request'
&& github.event.pull_request.head.repo.full_name == github.repository
&& !github.event.pull_request.draft)
|| (github.event_name == 'issue_comment'
&& github.event.issue.pull_request
&& startsWith(github.event.comment.body, '/review')
&& contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR", "CONTRIBUTOR"]'), github.event.comment.author_association))
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
allowed: ${{ steps.gate.outputs.allowed }}
steps:
- id: gate
uses: MultiAgency/private-ai/review/gate@<commit sha>
with:
allow-forks: "false"
review:
needs: gate
if: needs.gate.outputs.allowed == 'true'
runs-on: ubuntu-latest
concurrency:
group: private-review-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
issues: write
steps:
- uses: MultiAgency/private-ai/review@<commit sha>
with:
nearai-api-key: ${{ secrets.NEARAI_API_KEY }}The Action uploads each invocation’s receipt as a uniquely named
private-review.<id>-receipt.json artifact,
which downloads as that file, ready for the page's checker. It names the pull
request and commits it reviewed; what ties it to the review is the hash the
review quotes, so check that the two match.
Existing setups. Older generated workflows only listen for /review when
fork reviews are enabled. To migrate:
- Replace the complete workflow with the example above, or regenerate it with
the setup page. Adding
issue_commentalone leaves the old job condition in place, which can still skip comment-triggered reviews. - Replace
<commit sha>in bothuseslines with the same 40-character commit containing this fix. Keep the separate gate job, itspull-requests: readpermission, and the explicitallow-forkssetting. The existingNEARAI_API_KEYsecret needs no change. - Merge the workflow into the repository's default branch. On an open,
non-draft PR, comment
/reviewas someone with write access. The gate should pass, followed by a review and a receipt artifact. Fork PRs requireallow-forks: "true"; read-only commenters cannot start a review.
Forks. Pull requests from forks get no secrets on their pull-request events.
To accept authorized /review comments on them, tick the fork option on
the page, or set
allow-forks: "true" on the separate review/gate job.
The gate checks the commenter's effective repository permission. A
refused comment never starts the review job, so it never loads the key and
never cancels a review in progress through the job's concurrency group. The
review Action repeats the check for workflows without the gate.
Choosing a model. The model input takes any NEAR AI Cloud model that runs
in NEAR's own enclaves. Before any code is sent, the review checks the model
with the attestation checks below. If it fails, the review stops. To list the
models that pass today:
NEARAI_API_KEY=… npm run modelsA model passes when its machine is fully patched (TCB UpToDate).
allow-unpatched-model: "true" also accepts a model whose Intel platform
update is pending, which is the Qwen models today, but never a revoked one.
That is a weaker guarantee, so the review and the receipt both state it, and a
receipt is re-checked under the policy it records. Models NEAR AI Cloud can't
attest, such as those served through third parties, can't be chosen. The App
uses z-ai/glm-5.3-flash.
Locally, without posting:
npm ci
GITHUB_TOKEN=… NEARAI_API_KEY=… node review/review.mjs --repo owner/name --pr 12 --dry-runThe review follows REVIEW.md and AGENTS.md from the pull request's base
commit (rubric: names other files in the Action), or a default Bugs and
Security pass when neither exists. The model reads the diff, and the head
commit through read-only tools (list, read, search). It runs nothing, and no
path leaves the commit. Both run the same review,
review/review.json.
Before any data is sent, a run checks NEAR AI Cloud's attestation report for a fresh nonce:
- Model enclave: the TDX quote verifies against Intel's collateral with TCB
status
UpToDate, debug mode off. The quote binds the enclave's signing key and our nonce. Its configuration measurement matches the attested compose file, and its event log replays to RTMR3. NVIDIA's attestation service approves its GPUs for the same nonce, in a verdict NVIDIA signs. The receipt keeps that verdict, and the NVIDIA key that signed it with its certificate chain: NVIDIA rotates its keys within days, so the key counts as NVIDIA's when its certificate was issued by NVIDIA's attestation intermediate (pinned incore/attest.mjs) and was valid when the verdict was signed. Receipts written before they kept the key are served by an archive of NVIDIA's keys,core/nvidia-keys.json(npm run nvidia-keys), held to the same check. - Gateway enclave: the same quote checks, except that a pending platform
patch (
OutOfDateand the like) is allowed andRevokedis not. Under end-to-end encryption the gateway relays only ciphertext.
Then every request is end-to-end encrypted to the model enclave's key, using NEAR AI Cloud's E2EE v2 with all fields covered. That includes tool definitions and tool calls, so the gateway sees roles, ids and token counts but no content. Each reply is used only after the model enclave's signature over the exact request and response bytes checks out. If any check fails, the run stops.
What it does not prove:
- What happens on the machine that runs the service. The Action runs on
the client's own runner, which already has their code; this repository is
public so anyone can read what it does. The App runs in an attested OutLayer
enclave whose receipt names the exact build. Each release is recorded with
its commit in
app/builds.jsonbefore it runs, and the checker accepts only recorded builds of our project. A recorded build rebuilds bit for bit from its commit in a pinned container (app/build.sh, with Docker), and CI rebuilds each one when it is recorded (app/verify-builds.sh). - Which model instance answered. Instances of a model share one signing key, so the signature proves an attested enclave answered, not which one (see NEAR's verification notes).
- Which image the model enclave runs, and what it does. The check proves a production Intel TDX enclave holds the signing key, and shows its compose hash; it does not compare its measurements with NEAR's published compose files, and auditing those images is a separate step. NVIDIA's verdict is tied to that enclave by the shared nonce, not by the quote itself.
Drop it on the page, or:
git clone https://github.com/MultiAgency/private-ai && cd private-ai && npm ci
node core/verify.mjs private-review-receipt.jsonBoth run verifyReceipt. It re-runs the attestation checks
on the recorded report against current Intel collateral, and checks NVIDIA's
recorded verdict against the NVIDIA key that signed it, back to NVIDIA's pinned
intermediate. It also checks every response
signature against the attested model key. The receipt holds hashes of the
encrypted requests and responses, not the bytes, so it carries none of the
reviewed code.
Private Investigator is the first service of MultiAgency's private AI: services that work on private data with AI, and prove where the data went.
review/: the GitHub Action, and the review both paths run.app/: the GitHub App, in Rust, run on OutLayer;relay/is its webhook relay.core/: what every service shares, in Node and in the browser alike.site/: the page, which sets a repository up, shows a real review, and checks receipts in the browser.eval/: the quality measurements.
Questions and bugs: open an issue.
npm test runs offline. It uses a real attestation report recorded with its
Intel collateral and NVIDIA's verdict, a real signed turn, the page's sample
receipt, and a stand-in enclave for the loop.
npm run sample refreshes the page's sample: a dry-run review of
near-agencies#78 saved as site/sample-review.json, its receipt, and the Intel
collateral and NVIDIA key the tests check that receipt with. It needs
GITHUB_TOKEN and NEARAI_API_KEY.
npm run site builds the page into _site/, with the sample review rendered
in. esbuild bundles site/app.js with the lockfile's packages, so the browser
checker loads no code from a CDN. The pages workflow publishes it on every
push to main.