A pull request, taken apart in seconds
The engine is deterministic: the same change gets the same review, and every claim points at a line. Here is what happens between the link and the plan.
Read the change
The diff, its commits, the repository tree at the base, the dependency manifests and .visualdiff.json, all from the base revision so a pull request cannot rewrite its own rules. From a link, a webhook, the CLI or a pasted diff.
Take out what is not a change
Blocks moved between files, formatter-only hunks, pure renames, lockfiles and generated code are recognised and set aside. On agent-written changes this is often most of the diff.
Check what is left
About fifty line rules across application code, SQL, Terraform, Kubernetes, Dockerfiles and CI; intent against the description; provenance; tests and assertions; new dependencies against their registries; helpers that already exist.
Place it
Imports are resolved into a graph of the change and the files that depend on it, laid out by architectural layer. With ArchCanvas connected, the change is matched to the running resources it names.
Plan the review
Every hunk lands in read, skim or skip against your time budget, with its reasons, in an order that follows the dependency graph.
Report back
One comment on the pull request, edited on every push. A commit status that can block merging on hold. A card for chat. A Slack message when someone needs to look.
Eight views of one change
The report opens on the plan. Each other tab answers one question a reviewer asks.
- A review plan that fits your attention
Every hunk is sorted into read, skim or skip against a time budget you set. Code moved between files unchanged, formatter churn, lockfiles and generated files go to skip, with the reason on each line.
Read 65 lines in 20 minutes. Skim 190. Skip 327: moved, reformatted, lockfile or docs.- Intent drift
The description says what the change is for. visualdiff checks the code against it and names the areas nobody mentioned.
“Add idempotency keys” also changes auth, a migration and Terraform.- Hallucinated and squatted packages
Agents import packages that were never published, or one letter away from a real one. New dependencies are checked against npm and PyPI and against the names they imitate.
“reqeusts” is not “requests”, and PyPI has never heard of it.- Where your data goes
Every host a change reaches is listed and classified, and the lines that read secrets are joined to the lines that send them. Request bins, tunnels, raw IPs and unknown domains stand out.
Reads every environment variable, encodes it, and POSTs it to webhook.site.- Poisoned installs and instructions
Install scripts, registry redirects, lockfile tampering, pipeline changes and hidden instructions to coding agents are flagged, including in the files the plan would skip.
A hidden comment in CLAUDE.md tells agents to auto-approve telemetry.ts.- New outside vendors
A new SDK, API key or tracking script means a new company your data reaches. Each one is named with what it typically receives, ready for a vendor review.
Adds PostHog (analytics): user events, optionally session recordings.- Déjà vu
New helpers that already exist under another name, and bodies copied from elsewhere in the change.
formatCents is written again in receipt.ts; format.ts already has it.- Who, or what, wrote it
Commit trailers, bot identities, branch names and descriptions reveal Claude Code, Copilot, Cursor, Devin, Codex and a dozen more. Policy can be stricter for agent-written changes.
3 of 3 commits by Claude Code, no human commit after the last one.- Reach into production
Terraform, Kubernetes, env vars and hostnames are matched against your live ArchCanvas map, so the reviewer sees the database behind the diff and what sits two hops away.
Touches orders-db (deletion protection off) and orders-api; 24 resources nearby.- A map of the change
Changed files laid out by architectural layer, with the imports added and removed between them and everything that depends on them faded in behind.
15 files across 6 layers, with every import added or removed between them.
Guardrails in the repository
A .visualdiff.json on the default branch sets the rules: size limits that are tighter for agent-written changes, paths that need tests, protected areas, which findings block. It is read from the base revision, so the pull request under review cannot loosen it.
Anything you leave out keeps its default, shown here.
{
"maxChurn": 1200,
"maxChurnAI": 600,
"maxFiles": 60,
"requireTestsFor": [
"src/**",
"lib/**",
"app/**",
"pkg/**",
"internal/**"
],
"protected": [
{
"path": "**/auth/**",
"reason": "Authentication changes get a security review.",
"level": "warn"
},
{
"path": "**/migrations/**",
"reason": "Schema migrations are reviewed by the data owner.",
"level": "warn"
},
{
"path": ".github/workflows/**",
"reason": "Pipeline changes can leak secrets.",
"level": "warn",
"aiOnly": true
}
],
"blockOn": [
"critical"
],
"requireHumanCommitForAI": true,
"forbidNewDependencies": false,
"ignore": [
"**/__snapshots__/**"
]
}See it on a real change
The sample is an agent-written pull request with six problems in 582 lines.