This document covers working on the prview repo.
If you just want to use the tool, see docs/usage.md.
If you want to understand the module layout and execution flow, see docs/architecture.md.
git clone https://github.com/vetcoders/prview-rs.git
cd prview-rs
cargo buildThis repo is trunk-based:
mainis the trunk and the stable release branch- feature / fix / chore branches (
feat/*,fix/*,chore/*) are created frommain - every branch opens a PR back into
main - PRs land as merge commits (no squash)
- release tags (
v*) are cut frommain
# Debug build (faster compile)
cargo build
./target/debug/prview --help
# Release build (optimized)
cargo build --release
./target/release/prview --quickcargo install cargo-watch
cargo watch -x buildcargo test --lib
cargo test --test json_contractFor Rust review flow, a standard prview run executes tests by default.
You disable them only with a lighter preset (--quick, --update, --ai-only)
or an explicit --skip-tests. Exception: standard --remote-only is now a
deliberately faster preset, so tests must be restored there with --with-tests
or by using --deep.
cargo clippy -- -D warnings
cargo fmt --allLikewise, lint is on by default for Rust in standard mode. --with-lint mostly
matters when you want to restore it after a lighter preset. Under standard
--remote-only, heavy Rust lint (clippy, rustfmt) is trimmed, so --with-lint
or --deep restores the fuller pass.
Before pushing, run the same gate CI runs:
make precommit # fast pre-commit gate
make check # full local gate (fmt + clippy + tests)cargo doc --opensrc/
├── main.rs # Entry point
├── lib.rs # App orchestration
├── cli/mod.rs # CLI parsing (clap)
├── config/mod.rs # Configuration & profile detection
├── git/mod.rs # Git operations (git2, Patch API)
├── checks/ # Quality checks (trait-based)
├── heuristics/ # Structural analysis (loctree)
├── artifacts/
│ ├── mod.rs # Core layout, patches, merge gate, ZIP
│ ├── signal/ # High-signal generators (one module per domain)
│ └── dashboard.rs # HTML dashboard
├── mcp/ # MCP server (stdio) for agent integrations
├── scope/ # Scoped review packs (filter by files/commits)
├── policy/ # Policy parser + blocking semantics
├── regression/ # Regression detection (diff, perf, deps, score)
├── state/ # Incremental repo state
├── storage/ # Persistent run storage ($PRVIEW_HOME)
├── cache/ # Hash-based caching
├── tui/ # Terminal UI mode
├── output/ # Terminal output formatting
├── proc.rs # Subprocess hardening (process groups, timeouts)
├── check_id.rs # Stable check identifiers
└── paths.rs # Repo-bounded path validation
- Create the file
src/checks/newcheck.rs:
use super::{run_command, Check, CheckResult, CheckStatus};
use crate::Config;
use anyhow::Result;
use async_trait::async_trait;
pub struct NewCheck;
#[async_trait]
impl Check for NewCheck {
fn name(&self) -> &str {
"NewCheck"
}
fn can_run(&self, config: &Config) -> bool {
// When this check makes sense
config.profile.has_something
}
async fn run(&self, config: &Config) -> Result<CheckResult> {
let start = std::time::Instant::now();
let output = run_command("mytool", &["--check"], &config.repo_root).await?;
let status = if output.status.success() {
CheckStatus::Passed
} else {
CheckStatus::Failed
};
Ok(CheckResult {
name: self.name().to_string(),
status,
duration: start.elapsed(),
output: String::from_utf8_lossy(&output.stdout).to_string(),
cached: false,
})
}
}- Register it in
src/checks/mod.rs:
mod newcheck;
pub use newcheck::NewCheck;
fn get_checks_for_profile(config: &Config) -> Vec<Box<dyn Check>> {
let mut checks = Vec::new();
// Add in the right place
if config.run_lint {
checks.push(Box::new(NewCheck));
}
checks
}In src/config/mod.rs:
#[derive(Debug, Clone, Copy)]
pub enum ProfileKind {
Js,
Rust,
Python,
Mixed,
Generic,
NewLanguage, // Add
}
fn detect_profile(repo_root: &PathBuf, requested: Profile) -> Result<DetectedProfile> {
// Add detection
let has_newlang = repo_root.join("newlang.config").exists();
// ...
}Two places depending on the type:
In src/artifacts/mod.rs, add it to the right numbered-layout section:
pub fn generate(...) -> Result<PathBuf> {
// ...
// 20_quality/
generate_my_artifact(&quality_dir, diffs)?;
// ...
}
fn generate_my_artifact(dir: &Path, diffs: &[Diff]) -> Result<()> {
let content = "...";
std::fs::write(dir.join("my_artifact.txt"), content)?;
Ok(())
}Signal generators live in src/artifacts/signal/, one module per domain. Add
src/artifacts/signal/my_signal.rs:
pub fn generate_my_signal(dir: &Path, diffs: &[Diff]) -> Result<()> {
let findings = analyze(diffs);
if findings.is_empty() {
return Ok(()); // No file = no noise
}
std::fs::write(dir.join("my_signal.txt"), format_findings(&findings))?;
Ok(())
}Then register it in src/artifacts/signal/mod.rs (mod my_signal; pub use my_signal::*;)
and call it from artifacts/mod.rs in the signal-generators section, with status logging.
When you change the layout, filenames, or review-flow semantics, update these together with the code:
README.mdfor the quick entry pointdocs/usage.mdfor the output layout and artifact interpretationdocs/architecture.mdfor the module map and responsibilitiesdocs/contracts/merge_gate.mdif theMERGE_GATE.jsonschema or paths change
Pay special attention to root-level navigators (AI_INDEX.md, PR_REVIEW.md,
report.json) and the numbered layout in 00_summary/, 10_diff/,
20_quality/, 30_context/.
The --json stdout is not a full export of the artifact pack. Treat it as a
compact contract for automation; the full truth about a run stays in the
artifacts written to disk.
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_profile_detection() {
// ...
}
}# Test against a real repo
cd /path/to/some/repo
/path/to/prview/target/debug/prview --quick// Temporary debug prints
eprintln!("DEBUG: {:?}", variable);RUST_BACKTRACE=1 cargo run -- --quickRUST_LOG=debug cargo run -- --quickcargo build --release
perf record ./target/release/prview --quick
perf reporthyperfine './target/release/prview --quick'cargo build --release
ls -la target/release/prview# Linux (from Mac)
cargo build --release --target x86_64-unknown-linux-gnu
# Windows (from Mac)
cargo build --release --target x86_64-pc-windows-gnuThis document describes the current way of working on the repo and extending the code. It is not a product roadmap.
For the current state of CLI features:
prview --helpFor the latest design decisions:
- check open PRs against
main - read
README.mdas the repo-level entry point - treat historical plans under
docs/plans/as a record of work, not a source of truth