This document is the user guide for prview.
If you want to work on the repo, see docs/development.md.
If you want to understand the architecture, see docs/architecture.md.
For the prview.toml and .prview-policy.yml configuration files, see docs/configuration.md.
cd prview-rs
cargo build --release
./target/release/prview --helpcargo install --path .
prview --helpFull installation details, including release binaries and checksums, are in docs/INSTALL.md.
prviewAutomatically:
- detects the profile (JS/Rust/Python/Mixed)
- uses the current branch as the target
- diffs against the repo's default base
- in standard mode, generates the full artifact pack
- runs tests and lint by default, unless you pick a lighter mode (
--quick,--update,--ai-only) or an explicit--skip-*
The prview tool can analyze repositories that use any base branch
(develop, main, master, etc.); by default it resolves the first of
develop, main, master that exists.
prview --quickSkips tests, lint, and heuristics. Diffs and core artifacts only.
prview --quick analyzes the current local branch (HEAD) and compares it
against the bases resolved for the current repo. It does not pick a PR number
automatically.
To review a specific GitHub PR:
prview --pr 23 --quickprview gate
prview gate --strict
prview gate --jsonprview gate runs the standard fast gate profile, consumes the existing
policy/merge-gate verdict, and exits with a stable automation contract. It does
not compute a second verdict path.
| Exit code | Meaning |
|---|---|
0 |
PASS, or CONDITIONAL without --strict |
1 |
BLOCK |
2 |
CONDITIONAL with --strict |
3 |
Gate execution failed before a trustworthy verdict was available |
--json makes stdout machine-readable (schema_version: "gate-json/v1") with
the verdict, caveats, blocking issues, and artifact paths.
Local pre-push hook recipes and the recommended Shadow -> Warn -> Block rollout
are in docs/gate-playbook.md.
prview gate applies its own deterministic pre-push profile. It runs as a
quick, quiet review and does not inherit global step opt-ins such as
--with-tests, --with-lint, --with-security, or --security-full.
Effective profile:
| Surface | Gate behavior |
|---|---|
| Rust / Cargo | Cargo check runs; Clippy, Rustfmt, Cargo test, and Cargo audit stay visible as skipped checks |
| Security | Semgrep runs when the semgrep binary is available |
| Geiger | Cargo geiger is out of the gate profile |
| Tests, lint, bundle, heuristics | Disabled for the pre-push gate budget |
| JS/TS | Existing JS checks only run when repo-local node_modules tools exist; they are not part of the measured budget below |
Measured on 2026-07-06 with a prebuilt release binary
(target/release/prview); compile time is excluded.
| Repo checkout | State | Runs | Wall times | Mean | Verdicts | Dominant measured check |
|---|---|---|---|---|---|---|
prview-rs |
feat/gate-core, W1-B worktree dirty |
2 | 8.73s, 7.36s | 8.05s | CONDITIONAL / exit 0 |
Semgrep 4.41s; Cargo check cached |
pensieve |
chore/deprivatize, clean checkout, 14 commits behind origin |
2 | 48.27s, 45.95s | 47.11s | CONDITIONAL / exit 0 |
Semgrep 32.78s |
This repository ships a composite Action at action.yml for external CI usage.
It installs prview, runs prview gate --json, and maps the step result only
from the gate exit-code contract:
| Exit code | Action result |
|---|---|
0 |
success (PASS, or CONDITIONAL without strict mode) |
1 |
failure (BLOCK) |
2 |
failure (CONDITIONAL with strict mode) |
3 |
failure (gate execution error) |
Minimal blocking gate:
permissions:
contents: read
security-events: write
jobs:
prview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: vetcoders/prview-rs@main # pin to a released tag once one ships `prview gate`
id: prview
with:
strict: "true"
version: "latest"
- uses: github/codeql-action/upload-sarif@v3
if: ${{ steps.prview.outputs['sarif-path'] != '' }}
with:
sarif_file: ${{ steps.prview.outputs['sarif-path'] }}Use strict: "false" for advisory rollout: CONDITIONAL remains exit 0,
while BLOCK still exits 1. Extra CLI flags can be passed as whitespace-
separated args.
The Action prefers cargo-binstall when that binary is already available on the
runner and falls back to cargo install prview --locked --force. Set version
to a published release that contains prview gate, or latest for the newest
release. The gate command is not in the 0.5.0 crate; until a release that
includes it is published, install the action from main.
SARIF upload requires permissions: security-events: write. prview writes
30_context/INLINE_FINDINGS.sarif only when there are inline findings or
advisories. GitHub code scanning limits matter for large diffs: SARIF uploads
must be at most 10 MB after gzip compression, and GitHub displays at most 50
annotations per workflow step.
prview feature/my-feature main
prview feature/x main| Mode | What it does |
|---|---|
| standard (default) | Full review with tests and lint enabled by default |
--quick |
Light pass: skip tests/lint/bundle/heuristics |
--deep |
All heavier checks enabled (including security and heuristics) |
--ci |
Like deep, tuned for automation: no colors, strict non-zero exit |
--update |
Incremental rerun after new commits, skipping heavy checks unless forced |
--ai-only |
Minimal artifact pack for AI/review flows |
# 1) Fast daily check of the current branch
prview --quick
# 2) Check a specific GitHub PR
prview --pr 23 --quick
# 3) Deeper PR analysis (tests + lint + full gate)
prview --pr 23 --deep
# 4) Compact JSON for automation (stdout = JSON only)
prview --pr 23 --quick --json --quiet
# 5) Automation gate with contractual exit codes
prview gate --json
# 6) Pick up new commits without a full run
prview --update
# 7) Fast machine-readable repo state (branch, HEAD, dirty, latest run)
prview state --json --fastThe repo ships a ready-to-source file:
tools/shell/prview-aliases.zsh
To wire it up:
echo 'source $HOME/Git/prview-rs/tools/shell/prview-aliases.zsh' >> $HOME/.zshrc
source $HOME/.zshrcThis is a practical shortlist of the most common flags. The full, always-current option list is available via:
prview --help| Flag | Effect |
|---|---|
--quick |
Skip tests/lint/bundle/heuristics |
--deep |
Enable all checks (including security and heuristics) |
--ci |
CI mode: all checks, no colors, strict exit |
--ai-only |
Minimal checks, AI context pack only |
| Flag | Effect |
|---|---|
--with-tests |
Force tests on when a preset disabled them; also restores tests for standard --remote-only |
--skip-tests |
Skip tests |
--with-lint |
Force linters on when a preset disabled them; also restores heavier Rust lint for standard --remote-only |
--skip-lint |
Skip linters |
--with-bundle |
Enable the bundle build |
--skip-bundle |
Skip the bundle build |
--with-security |
Raise the heavy security posture (does not add cargo-geiger or full-tree Semgrep) |
--skip-security |
Skip heavy security checks |
--security-full |
Full security tier: runs full-tree Semgrep and adds cargo-geiger's unsafe scan (slow; off even under --deep) |
By default, Semgrep is scoped to the change when prview can resolve a clean git
baseline: it passes Semgrep --baseline-commit <merge-base> so existing
findings outside the diff do not degrade the merge verdict. If the worktree is
dirty or the merge-base is unavailable, prview falls back to a full scan and the
artifact classifier still separates introduced from pre-existing findings.
Semgrep parse/scan errors remain surfaced even when no rule findings are
introduced.
| Flag | Effect |
|---|---|
--profile auto |
Auto-detect (default) |
--profile js |
JavaScript/TypeScript only |
--profile rust |
Rust only |
--profile python |
Python only |
--profile mixed |
All available |
| Flag | Effect |
|---|---|
--update |
Incremental update (skip heavy checks) |
-R, --remote |
Analyze a branch from origin/ |
--remote-only |
Resolve bases from origin/* only; a faster remote-review preset in standard mode |
--local-only |
Resolve bases from local refs only |
--policy-file <path> |
Path to .prview-policy.yml |
--policy-mode <shadow|warn|block> |
Override the policy mode |
--why-blocked |
Explain why the merge gate is blocking |
| Flag | Effect |
|---|---|
-q, --quiet |
Minimal output |
--json |
JSON output |
--no-color |
Disable ANSI colors |
--no-zip |
Skip ZIP creation |
--no-dashboard |
Skip HTML dashboard generation |
prview --profile rust --with-tests feature/x mainprview --profile python --with-tests --with-lintprview --profile mixed --deepprview --ci feature/x mainAfter new commits on a branch:
prview --update feature/x mainprview --json --quiet feature/x main > summary.jsonIn --json --quiet mode, stdout contains only the compact JSON summary
(no banners or text summaries). This payload is meant for scripts and agents:
it carries the verdict, output_dir, a short checks_summary, top_failures,
context_artifacts, and paths to artifacts. Full detail stays in the run files
on disk, especially the canonical RUN.json and MERGE_GATE.json pair, plus
PR_REVIEW.md.
Artifacts are written to $PRVIEW_HOME/runs/<repo>/<branch>/<run_id>/
or, when PRVIEW_HOME is unset, to
$HOME/.prview/runs/<repo>/<branch>/<run_id>/ in an ordered numbered layout.
New run ids use a timestamp plus short HEAD suffix, for example
20260704-120500-a1b2c3d; treat the full value as opaque.
A latest symlink points at the most recent run in
$PRVIEW_HOME/runs/<repo>/<branch>/latest or
$HOME/.prview/runs/<repo>/<branch>/latest when PRVIEW_HOME is unset.
$HOME/.prview/runs/my-repo/feature-x/20260225-185357/
├── 00_summary/
│ ├── RUN.json # Run metadata, execution mode, check inventory
│ ├── FAILURES_SUMMARY.md # Compact blocking failures without raw dumps
│ ├── MANIFEST.json # SHA256 hashes for generated files
│ ├── SANITY.json # Integrity validation results
│ ├── MERGE_GATE.json # Machine-readable merge decision
│ ├── pr-metadata.txt # Branch, bases, profile
│ ├── file-status.txt # A/M/D + file paths
│ └── commit-list.txt # hash date author message
├── 10_diff/
│ ├── full.patch # Full diff with diff-stat header (+N -N per file)
│ ├── per-commit-diffs/ # Individual per-commit patches
│ │ ├── 00-SUMMARY.md # Commit stats + batch mapping + thematic labels
│ │ ├── 01-abc1234-message.patch
│ │ └── ...
│ └── per-file-diffs/ # Hotspots: files with >=80 lines changed
│ ├── 00-INDEX.txt # Index with diff-stat per file
│ └── *.patch
├── 20_quality/
│ ├── *.result.json # Per-check machine-readable outputs
│ ├── *.log # Per-check raw logs
│ ├── full-checks.log # Full output from all checks
│ ├── checks-errors.log # Filtered: errors/warnings only, with +/-2 lines of context
│ ├── coverage-delta.txt # Source<->test mapping with change status
│ └── BREAKING_CHANGES.md # Removed pub symbols, changed signatures
├── 30_context/
│ ├── INLINE_FINDINGS.sarif # Optional: only when the run has findings/advisories
│ ├── changed-tests.txt # Test files changed in this PR
│ ├── cargo-tree.txt # (Rust) dependency tree for CVE/dependency paths
│ ├── tsc-trace.log # (JS) optional module-resolution diagnostics
│ ├── eslint-report.json # (JS) ESLint result
│ └── vitest-report.json # (JS) Vitest result
├── dashboard.html # Visual HTML summary
└── artifacts.zip # Everything zipped
Several generators produce high-signal artifacts — each writes a file only when it has something worth showing:
| Artifact | Description | When generated |
|---|---|---|
checks-errors.log |
Errors and warnings from checks with +/-2 lines of context | When checks found errors |
BREAKING_CHANGES.md |
Removed pub symbols, changed signatures, new env requirements |
When breaking changes are detected |
coverage-delta.txt |
Source-file-to-test mapping (multi-strategy matching) | When the diff contains source files |
per-file-diffs/ |
Individual patches for files with >=80 lines changed |
When such hotspots exist |
When a generator produces no file, the CLI prints an i note explaining why.
00_summary/MERGE_GATE.jsonis the canonical source of check statuses.PR_REVIEW.mdis a concise review narrative, not a raw log dump.00_summary/FAILURES_SUMMARY.mdsummarizes blocking failures and advisories without copying whole JSON files.- When
30_context/INLINE_FINDINGS.sarifexists, it emits findings per location/advisory and is suitable for annotation integrations. - In Rust runs,
PR_REVIEW.mdandFAILURES_SUMMARY.mdcan surface dependency paths to vulnerable crates based on30_context/cargo-tree.txt. 10_diff/per-commit-diffs/00-SUMMARY.mdcarries both the batching and thematic batch labels.20_quality/coverage-delta.txtis a heuristic; for Rust it drops DELETED files in favor of disk searches for orphaned tests (raising anORPHANED_TEST_DETECTEDflag). Inline#[cfg(test)]modules are handled silently, without false alarms.- In fast
remote-onlyruns, heavier diagnostics such as30_context/tsc-trace.logor30_context/tauri-info.logmay be intentionally skipped. CheckRUN.jsonforrecommended/reasonnotes on whether they are worth generating.
For large PRs, per-commit diffs are grouped automatically:
| Commit count | Behavior |
|---|---|
| <=10 | Individual .patch per commit |
| 11–50 | Batches of 5 commits in batch-NN.patch |
| >50 | Per-commit diffs skipped (only full.patch) |
The policy-aware merge decision. Details: docs/contracts/merge_gate.md.
Run from a directory inside a git repo.
The named base branch does not exist. Pass an existing branch explicitly:
prview feature/x develop
# or, if the repo has no develop:
prview feature/x mainMake sure tsconfig.json exists and pnpm/npm are available.
Check that cargo is on PATH and Cargo.toml is valid.