Skip to main content
Commands

vg review

Vibgrate Review — architecture and security-control review of the change you just made, run locally from the code map. Produces a signed, versioned receipt, not model prose. Reports change integrity; it does not prove code is secure.

Overview

vg scan answers how far behind is the stack? Vibgrate Review answers a different question about the same repository:

Did this change move the system toward its declared architecture, weaken a security control, or create an implication the author did not account for?

It answers it locally, from the Vibgrate Graph, with deterministic scanners and a policy-owned decision. The result is a signed, versioned receipt (vg.review.receipt.v1) that can stay on disk or be pushed to Vibgrate Cloud and shown commit by commit.

AI coding agents write changes faster than anyone can judge their architectural consequences. Review is the layer that reads the change the way a senior reviewer would — before the pull request, not after the incident.


Usage

vg review                            # the working tree + index, vs HEAD
vg review --base origin/main         # merge-base of HEAD and the base branch
vg review explain arch:<rule>:<path> # the evidence behind one finding
vg review findings-from-diff         # deterministic graph/policy findings only
vg review propose blast:<node_id> --model forge --json
vg review propose arch:<rule>:<path> --model forge --json --findings findings.json
vg review verify review-receipt.json # check a receipt offline

Review reads the code map. If there isn't one, vg review builds it first and shows a progress bar; if the map has drifted from the working tree, it refreshes it incrementally. Pass --no-auto-build to turn that off — then a missing or stale map exits 6, never 0.

The first run in a repository with no review policy also writes a starter one, seeded with the layering shape the repository already exhibits, and tells you it did. It goes into the project config: a new .vibgrate/config.yml when there is no config yet, or a review block added to an existing .vibgrate/config.yml or vibgrate.config.json. A .ts or .js config is never rewritten, so those repositories get .vibgrate/review.toml instead. The policy is written after the review, so it never lands in the change set being reviewed; it is advisory, so it cannot turn a green build red; and --base runs skip it, so a pull request review never writes to the tree. Pass --no-setup to turn that off too.

Options

FlagDefaultDescription
--base <ref>—Review HEAD against the merge-base with <ref>
--format <fmt>texttext, json (the receipt), sarif (security findings only), md
-o, --out <file>—Write the formatted result to a file
--pushoffSend the receipt to Vibgrate Cloud (needs a DSN)
--dsn <dsn>—DSN token for --push (or use VIBGRATE_DSN / vg login)
--strictoffFail the command when --push fails
--fail-on <level>from configGate CI on this decision: none, fail, or needs_review. Omit to use the review policy; gating is off unless enforcement is enforced
--explainoffAdd local-model explanations. Requires a local model; fails closed (exit 6) without one
--include-spansoffInclude evidence line ranges in the pushed receipt
--include-snippetsoffInclude capped source snippets in the pushed receipt
--no-auto-build—Don't build or refresh the code map; exit 6 when it is missing
--no-setup—Don't write a starter review policy
--sign-key <file>$VG_ATTEST_KEY, else .vibgrate/attest-key.pemEd25519 private key to sign the receipt with — the same key vg build --attest and vg evidence use. Minted on first use if absent (keep it, gitignore it)
--no-sign—Leave the receipt unsigned (signature: null)
--write-contextoffWrite .vibgrate/review-context.md — committed agent memory of what Review found
--inject-context [file]offUpdate the managed review block inside an instructions file (default CLAUDE.md)
--offline (global)offNever touch the network — no push, no model fetch

vg review explain

vg review explain <finding-id>
vg review explain arch:<rule>:<path> --base origin/main
vg review explain blast:<node_id>

Prints the evidence behind one finding from the current change: the remediation, its alignment and confidence, whether it is protected, which layer produced it, and each piece of evidence — the graph edge with its source span, and the policy rules it violates. Finding ids are the stable blast:{node_id} / blast:{path}:{name} and arch:{rule}:{path} keys, not rank-local labels.

vg review findings-from-diff

vg review findings-from-diff
vg review findings-from-diff --base origin/main
vg review findings-from-diff --diff pr.patch --format json

The same deterministic scanners vg review runs, printed as the vg.review.findings.v1 document — blast-radius facts from the code graph for changed symbols, plus architecture-policy and security-control findings. No hosted model. --diff reads a unified diff (- is stdin). JSON also includes a publishable array:

FieldBlast-radiusArchitecture-policy
kindcorrectness (top-level only)correctness (top-level only)
id / finding_keyblast:{node_id} or blast:{path}:{name}arch:{rule}:{path}
sourcescannerscanner
producer / scanner_kindblast_radiusarchitecture
severitylow or mediumlow, medium, or high — never critical from version lag
receiptsexisting capsule verify: / scan: / attest: ids when those facts already existsame

Suggested-fix on those rows is an honest skip (null / skipped_no_patch). Each run also writes .vibgrate/review-propose-handoff.json so vg review propose can resolve those ids without a second findings loop. This path does not post a check run or a review comment.

vg review propose

vg review propose blast:<node_id> --model forge --json
vg review propose blast:<node_id> --model forge --json --base origin/main
vg review propose arch:<rule>:<path> --model forge --json --findings findings.json
vg review propose arch:<rule>:<path> --model relay:<slug> --json

Attaches a PatchIR dry-run to one finding id via the VG Code agent loop — there is no second Review runtime. Lookup is the current change set, then --findings JSON (a findings document or a review receipt), then the last-run .vibgrate/review-propose-handoff.json. Pass the same --base / --in-place / --diff as findings-from-diff when you want that change set explicitly. --model is required:

ShapeMeaningExample
relay:<slug>Hosted Review on Vibgrate Relay--model relay:hosted-coder
spark · flow · forgeLocal Code Mode--model forge

A bare slug is invalid — propose never calls a backend in that case. Dry-run unless you pass --apply --yes on a topic branch. It never writes the default branch. The same model-id shapes are used by vg code and vg models. This command does not post a check run or a review comment.

vg review verify

vg review verify review-receipt.json
vg review verify review-receipt.json --pub trust-root.pem

Checks a receipt offline — no Vibgrate account, no network. It recomputes digests.receipt over the document it holds and verifies the detached Ed25519 signature over that digest. The states are honest and never fabricate a pass:

StateExitMeaning
verified0Signature valid against the key pinned with --pub, and the digest matches
unverified2Intact, but trust is not established — the signer is not pinned, or the receipt is unsigned
failed1The digest no longer matches the contents, or the signature does not verify (altered after signing, or a different key)

Every receipt carries the signer's public key, so integrity can be checked without any setup; who signed it is established only by pinning that key. Pass --json for the machine-readable result.


Decisions

Policy owns the decision, and it is the only layer that writes one. Findings — from the scanners, or from the optional local model — have nowhere to put a verdict.

DecisionExit (gated)Meaning
pass0No material delta, or every finding is target-aligned
fail2An unresolved protected finding, or a high-severity finding above the confidence threshold
needs_review2 with --fail-on needs_review, else 0Findings a human should look at
undetermined2 with --fail-on needs_review, else 0Not enough evidence to decide — deliberately not a pass

Gating is opt-in, exactly as it is for vg scan: without --fail-on or enforcement: enforced in the review policy, every decision is reported, written to the receipt, and the process exits 0. A gate failure exits 2 — the CLI's gate-failed code, shared with vg scan --fail-on — and never 1, which across the CLI means the command itself broke. A missing code map, policy, or model exits 6, which is deliberately never read as a pass.

You get needs_review or undetermined instead of a fake pass when the system does not have enough peers or tests to judge the change. That is the point: a green tick nobody earned is worse than an honest "I could not tell".

Protected findings

An unguarded entrypoint, a removed guard, a validated taint flow, and a known-vulnerable dependency are protected. While one is unresolved, policy cannot emit pass — not through an approved exception, not through low confidence, not through the quick path, and not through anything a model says.

Turn a rule off in the review policy (review.protected) if it does not apply to your repository. That is the only way to stop it gating.


Configuration

The review policy is the review block of the project config — .vibgrate/config.yml or vibgrate.config.json, which take the same settings:

# .vibgrate/config.yml
review:
  enforcement: advisory       # advisory | enforced
  failOn: fail                # none | fail | needs_review
  targetPattern: layered      # the architecture you say you want
  protected:
    unguardedEntrypoint: true
    knownVulnerableDependency: true
    validatedTaint: true

Read from the trusted base branch when --base is given, so a pull request cannot weaken the policy applied to itself. The same goes for the team files in .vibgrate/review/ (ignore.md, policy.md, merge.md, checks/*.md): with --base they come from the base branch, and a change's edits to them apply after it merges. If the base has no policy, Review uses the defaults, never the change's own copy. It is read as data: a review block in a .ts or .js config is never run, so keep it in YAML or JSON.

Repositories that already have .vibgrate/review.toml keep working: it is read whenever the config has no review block. Its keys are the snake_case forms of the ones above (fail_on, target_pattern, [review.protected]). vg doctor tells you when a review block makes review.toml redundant.

Declaring targetPattern is what turns a layering observation into a regression. Without it, a dependency that skips a tier is reported as a medium finding about the repository's own majority — because a majority is not a decision, and Review will not treat it as one.


In CI

The same binary, the same policy, the same receipt schema as on a laptop.

vg review --base "origin/$BASE_REF" --format json --out review-receipt.json

Review builds the map itself on a cold runner, so a separate vg build step is optional. Keep one if you want the map build timed and cached as its own CI step.

Set VG_ATTEST_KEY from a CI secret so every receipt is signed by the same key — then a downstream job, or an auditor, can pin its public half with vg review verify --pub and get verified rather than unverified. Without it the runner mints a throwaway key: the receipt is still signed and tamper-evident, but the signer cannot be recognised across runs.

Start with the default --fail-on fail so only a fail stops the build, and move to --fail-on needs_review once a repository has opted into enforcement.

--format sarif uploads the security findings to GitHub code scanning. Architectural findings stay on the receipt and the check summary on purpose: code scanning is a security surface, and filling it with layering observations trains reviewers to ignore it.


Privacy

Source stays on your machine. --push sends the receipt — decisions, claims, evidence ids, paths, digests, versions — never the analysis capsule and never source text. Line ranges are opt-in with --include-spans; snippets are a second, explicit opt-in with --include-snippets, and are capped. With no DSN, the receipt stays local.


What it does not claim

  • It does not prove code is secure, correct, or free of vulnerabilities.
  • It does not replace Semgrep, CodeQL, a compiler, or your tests.
  • It does not govern AI-system fairness or model risk — that is a different category.
  • Absence of findings is not a certification.

Related

  • vg scan — stack currency, the other half of the picture
  • vg code — the VG Code loop vg review propose reuses
  • vg models — Code Modes (spark / flow / forge)
  • CI integration — wiring the gate into your pipeline

Example use cases

Expand any use case to watch a live replay of the real @vibgrate/cli running against one of our test repositories. Nothing executes in your browser — these are recordings of actual runs, with the scan time shown as of now.

vg review

Related Documentation

Vibgrate CLI

See a real scan run

A replay of the actual CLI running against our test repositories — live progress, real findings, a genuine DriftScore. Nothing executes in your browser.

Replay
demo@vibgrate — bash
❯ npx @vibgrate/cli scan
 
╭──────────────────────────────────────────╮
│ Vibgrate Drift Report │
╰──────────────────────────────────────────╯
 
── node-turborepo (node) .
Runtime: >=18.0.0 (6 majors behind)
Frameworks:
Turbo: 1.13.4 → 2.11.7 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
1 current 1 1-behind 3 2+ behind 1 unknown
 
── @repo/admin (node) apps/admin
Frameworks:
TanStack Query: 5.104.1 → 5.104.1 (current)
React: 18.3.1 → 19.3.0 (1 behind)
React DOM: 18.3.1 → 19.3.0 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Vite: 5.4.21 → 8.3.3 (3 behind)
Dependencies:
3 current 9 1-behind 3 2+ behind 4 unknown
 
── @repo/api (node) apps/api
Frameworks:
Express: 4.22.3 → 5.2.1 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Vitest: 1.6.1 → 5.0.3 (4 behind)
Dependencies:
7 current 4 1-behind 4 2+ behind 4 unknown
 
── @repo/web (node) apps/web
Frameworks:
Next.js: 14.2.35 → 16.4.0 (2 behind)
React: 18.3.1 → 19.3.0 (1 behind)
React DOM: 18.3.1 → 19.3.0 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
2 current 6 1-behind 3 2+ behind 5 unknown
 
── @repo/config (node) packages/config
Frameworks:
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
2 current 2 1-behind 5 2+ behind 0 unknown
 
── @repo/database (node) packages/database
Frameworks:
Prisma: 5.22.0 → 7.10.0 (2 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
1 current 0 1-behind 3 2+ behind 1 unknown
 
── @repo/types (node) packages/types
Frameworks:
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
0 current 0 1-behind 1 2+ behind 1 unknown
 
── @repo/ui (node) packages/ui
Frameworks:
React: 18.3.1 → 19.3.0 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
React: 18.3.1 → 19.3.0 (1 behind)
Dependencies:
1 current 4 1-behind 1 2+ behind 1 unknown
 
── @repo/utils (node) packages/utils
Frameworks:
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Vitest: 1.6.1 → 5.0.3 (4 behind)
Dependencies:
0 current 1 1-behind 2 2+ behind 1 unknown
 
Tech Stack
Frontend: React, React DOM
Meta-frameworks: Next.js
Bundlers: tsx, Turbo, Vite
CSS / UI: Autoprefixer, PostCSS, Tailwind CSS
Backend: Express
ORM / Database: Prisma, Prisma Client
Testing: Vitest
Lint & Format: ESLint, ESLint Prettier, ESLint React, Prettier, typescript-eslint
 
Services & Integrations
Auth: JWT 9.0.3
Databases: Prisma 5.22.0
 
TypeScript
v5.3.3 · strict ✔ · MIXED · target: ES2022
 
Build & Deploy
Package Managers: pnpm
Monorepo: npm-workspaces, pnpm-workspaces, turbo
 
Product Purpose Signals
Frameworks: react, nextjs
Evidence: 177
Top Signals:
- [heading] Dashboard (apps/admin/src/pages/Dashboard.tsx)
- [title] Revenue Overview (apps/admin/src/pages/Dashboard.tsx)
- [copy] workspace:* (packages/ui/package.json)
- [copy] ./dist (packages/ui/tsconfig.json)
- [copy] ./src/index.ts (packages/ui/package.json)
- [copy] @repo/config/tsconfig-base.json (packages/ui/tsconfig.json)
- [copy] @repo/ui (packages/ui/package.json)
- [copy] #3b82f6 (apps/admin/src/pages/Dashboard.tsx)
Unknowns:
- No pricing or billing evidence found.
- No integrations/connectors evidence found.
- No route structure evidence found.
 
Security Posture
Lockfile ✖ · .env ✔ · node_modules ✔
 
Platform
Native modules: turbo
 
Code Quality
Files: 36 · Functions: 183 · Avg complexity: 2.62 · Avg length: 21.13 lines
Max nesting: 2 · Circular deps: 0 · Dead code: 0%
God files: apps/admin/src/pages/Products (448 lines)
 
Database Schema
postgresql · 8 models · 1 enum
Models: Address, CartItem, Category, Order, OrderItem (+3 more)
 
Findings (16 errors, 11 warnings)
✖ Node.js runtime ">=18.0.0" reached end-of-life on 2025-04-30 (latest: 24.0.0).
vibgrate/runtime-eol in .
⚠ TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in .
✖ 60% of dependencies are 2+ major versions behind in node-turborepo.
vibgrate/dependency-rot in .
✖ @types/node is 6 major versions behind (spec: ^20.11.0, latest: 26.6.4).
vibgrate/dependency-major-lag in .
⚠ TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in apps/admin
✖ Vite is 3 major versions behind (current: 5.4.21, latest: 8.3.3).
vibgrate/framework-major-lag in apps/admin
✖ vite is 3 major versions behind (spec: ^5.0.12, latest: 8.3.3).
vibgrate/dependency-major-lag in apps/admin
⚠ TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in apps/api
✖ Vitest is 4 major versions behind (current: 1.6.1, latest: 5.0.3).
vibgrate/framework-major-lag in apps/api
✖ @types/node is 6 major versions behind (spec: ^20.11.0, latest: 26.6.4).
vibgrate/dependency-major-lag in apps/api
✖ vitest is 4 major versions behind (spec: ^1.2.1, latest: 5.0.3).
vibgrate/dependency-major-lag in apps/api
⚠ Next.js is 2 major versions behind (current: 14.2.35, latest: 16.4.0).
vibgrate/framework-major-lag in apps/web
⚠ TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in apps/web
✖ @types/node is 6 major versions behind (spec: ^20.11.0, latest: 26.6.4).
vibgrate/dependency-major-lag in apps/web
⚠ TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/config
✖ 56% of dependencies are 2+ major versions behind in @repo/config.
vibgrate/dependency-rot in packages/config
✖ eslint-plugin-react-hooks is 3 major versions behind (spec: ^4.6.0, latest: 7.1.1).
vibgrate/dependency-major-lag in packages/config
⚠ Prisma is 2 major versions behind (current: 5.22.0, latest: 7.10.0).
vibgrate/framework-major-lag in packages/database
⚠ TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/database
✖ 75% of dependencies are 2+ major versions behind in @repo/database.
vibgrate/dependency-rot in packages/database
⚠ TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/types
✖ 100% of dependencies are 2+ major versions behind in @repo/types.
vibgrate/dependency-rot in packages/types
⚠ TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/ui
⚠ TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/utils
✖ Vitest is 4 major versions behind (current: 1.6.1, latest: 5.0.3).
vibgrate/framework-major-lag in packages/utils
✖ 67% of dependencies are 2+ major versions behind in @repo/utils.
vibgrate/dependency-rot in packages/utils
✖ vitest is 4 major versions behind (spec: ^1.2.1, latest: 5.0.3).
vibgrate/dependency-major-lag in packages/utils
 
╭──────────────────────────────────────────╮
│ Top Priority Actions │
╰──────────────────────────────────────────╯
 
1. Upgrade EOL runtime in node-turborepo
End-of-life runtimes no longer receive security patches and block ecosystem upgrades.
./.
>=18.0.0 → 24.0.0 (6 majors behind)
Impact: −10 drift points (runtime & EOL)
 
2. Fix security posture: no lockfile found
Without a lockfile, installs are non-deterministic. Run the install command to generate one and commit it.
./
Missing: package-lock.json, pnpm-lock.yaml, or yarn.lock
 
3. Upgrade Vitest 1.6.1 → 5.0.3 in @repo/api (+2 more)
4 major versions behind. Major framework drift increases breaking change risk and blocks access to security fixes and performance improvements.
./apps/api
Vitest: 1.6.1 → 5.0.3 (4 majors behind)
./packages/utils
Vitest: 1.6.1 → 5.0.3 (4 majors behind)
./apps/admin
Vite: 5.4.21 → 8.3.3 (3 majors behind)
Impact: −5–15 drift points
 
4. Reduce dependency rot in @repo/types (100% severely outdated)
1 of 1 dependencies are 2+ majors behind. Run `npm outdated` and prioritise packages with known CVEs or breaking API changes.
./packages/types
typescript: 5.9.3 → 7.0.2 (2 majors behind)
Impact: −5–10 drift points
 
5. Reduce dependency rot in @repo/database (75% severely outdated)
3 of 4 dependencies are 2+ majors behind. Run `npm outdated` and prioritise packages with known CVEs or breaking API changes.
./packages/database
@prisma/client: 5.22.0 → 7.10.0 (2 majors behind)
prisma: 5.22.0 → 7.10.0 (2 majors behind)
typescript: 5.9.3 → 7.0.2 (2 majors behind)
Impact: −5–10 drift points
 
╭──────────────────────────────────────────╮
│ Architecture Layers │
╰──────────────────────────────────────────╯
 
Archetype: nextjs (80% confidence)
Files classified: 24 (11 unclassified)
Folders classified: 8
apps/admin/src presentation 100% 4 files
apps/admin/src/pages presentation 100% 2 files
apps/api/src/middleware middleware 100% 2 files
apps/api/src/routes routing 100% 2 files
apps/web/src/app presentation 100% 4 files
apps/web/src/app/products presentation 100% 2 files
apps/web/src/app/products/[id] presentation 100% 1 file
packages/ui/src presentation 100% 6 files
Unclassified source (sample): 11
 
presentation 15 files drift ████████████████████ 100 risk high
routing 4 files drift ████████████████████ 100 risk high
middleware 2 files drift ███████▍░░░░░░░░░░░░ 37 risk moderate
config 2 files drift ░░░░░░░░░░░░░░░░░░░░ 0 risk none
shared 1 file drift ████████████████████ 100 risk high
 
╭──────────────────────────────────────────╮
│ DriftScore Summary │
╰──────────────────────────────────────────╯
 
DriftScore: 70/100
Risk Level: HIGH
Projects: 9
Classified: 8 nano · 1 micro · 0 small · 0 standard
Billable: 0.42 · 9 detected → 0.42 billable projects (micro-project pricing)
0.1 micro · 0.32 nano
These fractions add up across repositories, then round down to whole billable projects.
 
Score Breakdown
Runtime: ████████████████████ 100
Frameworks: ███████████▊░░░░░░░░ 59
Dependencies: ██████▌░░░░░░░░░░░░░ 33
EOL Risk: ████████████████████ 100
 
Scanned at 2026-10-07T12:34:03.236Z · 6.6s · 286 files scanned · 56 workspace files · 27 dirs
❯
Press Run to start.