Zero Zone Of Pain

Your agent can't read the whole repo.
zzop reads it.

A coding agent can't fit your repository in context, and what it doesn't read, it guesses. zzop reads it and answers with one JSON map — which calls reach which routes, and which reach nothing at all. Same input, same answer, every time.

It writes no code. It makes the understanding your agent works from accurate.

The problem

One route was renamed. Nothing noticed.

Two independently authored apps — a React frontend, an Express backend. They share no code and no types. Someone tidies up one backend route.

The backend tidy-up
- router.put('/user',      auth.required, …)
+ router.put('/users/me',  auth.required, …)

The frontend build stays clean — the route is a string literal, so there is no type to check it against — and its mocked tests stay green. The contract is already broken, and a linter, a type-checker or a test suite scoped to one repository is structurally unable to see it: the evidence is split across two repos and never crosses a compiler boundary.

What zzop reports
=== unprovided consumes ===
  "PUT /api/user"       @ fe-vite     src/pages/Settings.jsx:19   
     the call now hits nothing

=== unconsumed provides ===
  "PUT /api/users/me"   @ be-express  auth.controller.ts:61       
     the route nobody calls

Both ends of the break, located to the file and line, across two repos that share nothing on disk.

What it looks at

One engine, three lenses

Cross-layer

Frontend calls joined to backend routes: unconsumed endpoints, method mismatches, path drift — even across repositories.

Security

SQL injection, weak hashing, SSRF, hardcoded secrets — DSL rules plus native analyses, across languages.

Structure

Circular dependencies, dead code, refactor priority — structural debt quantified per file.

Eight languages are parsed natively — TypeScript · Python · Java · C# · Rust · Go · Prisma · SQL. Anything else joins through an adapter.

Why trust it

It tells you what it could not see.

The real hazard in static analysis isn't a wrong answer — it's silence. If "found nothing" and "couldn't look" are indistinguishable, green means nothing.

Deterministic
Same input, byte-identical output. No timestamps, no unstable ordering.
An empty array
Always means analyzed, found nothing. What it couldn't see is reported as absent, never as empty.
What it couldn't do
A capability this run couldn't provide is self-reported in warnings, never stubbed.
Every finding
Names the exact config that silences it — rule findings add the concrete fix and a suppress marker.

That is what separates it from a flat list of findings: results are ranked by refactor ROI, and "two codebases quietly disagree" becomes a first-class finding.

In the field

Run over everything X ever open-sourced.

Twelve repositories X (formerly Twitter) and xAI have open-sourced — from the For You feed to Grok's build system — in one run. The numbers below were measured 2026-08-15 with zzop 0.31.0, and each counts a different thing: walked is files visited in the tree, dispatched is the subset the eight native parsers actually received, and symbols are the declarations those parsers extracted.

x-algorithm
X's For You feed (Rust + Python). 207 of 215 files dispatched to a parser — 96%, the highest in the set, for an honest reason: Rust and Python are head-on coverage. The same run stated the limit too — the service speaks gRPC, which zzop has no recognizer for, so a file importing axum with zero routes is the correct answer, and the run says so.
grok-build
Grok's build system: 71,142 symbols from a single tree — 5.4× what zzop's own repository (13,259) yields.
All twelve trees
12,078 files walked, 4,480 of them dispatched (37%) — the rest are mostly languages outside the eight (Scala above all), and even those still get line counts and text rules. 94,281 symbols in total. One facts run over everything: 73s cold, 30s warm.

The point of this table is refusing to blend two ratios: 96% belongs to one tree (x-algorithm), 37% to the whole set. Hide the low one and the high one stops being credible. To re-measure: clone the repositories and run zzop facts --config once — each tree's coverage block prints its own file / dispatched / symbol counts, and the twelve blocks sum to the totals above. The seconds are that run's wall clock, not a printed field.

What that run saw

171 findings — and how zzop states each one.

The same twelve repositories, run against the rule packs (2026-08-15, zzop 0.32.0). Only four produced any finding; eight came back with zero — a zero is a result too, disclosed rather than hidden. 171 in total, split 5 critical · 122 warning · 44 info. The point that makes the number honest: severity is a lexical judgment, not a vulnerability verdict.

5 critical — all inside tests
All five are conn-string-credentials (a URL embedding scheme://user:pass@host in source), and all five sit inside a #[test] function — test inputs for the code that strips credentials (strip_url_credentials_removes_token). zzop never calls them vulnerabilities. It reports what it lexically sees, names the config key that silences it, and lets a human read them as fixtures in five seconds.
The real signal is in the warnings
Top rules by count: command-and-interpolation 33 · reqwest-no-timeout 24 · hardcoded-secret 19 · high-entropy-secret 13 · fs-check-then-use 9. The cross-layer join added 20 more — contract gaps like unconsumed endpoints and unprovided calls, the layer a single-file rule cannot see.
Eight clean — that's disclosed too
Eight — communitynotes, grok-1, xai-proto, xai-sdk-python, x-algorithm and more — came back with zero. zzop does not read a zero as "safe": the same run records, per tree, what it could not see (languages outside the eight, unresolved handlers, recognizer-less paths like gRPC) in the coverage block, so a zero reads as clean or out of scope, never a blank claim.

This is the product's thesis: zzop does not brag about findings — it states honestly what it saw and what it could not. That all five criticals are test fixtures is not the weakness; the strength is that it did not dress them as vulnerabilities. Reproduce: clone the twelve repositories and run zzop cross --config once — each tree prints counts by severity and rule, and every finding carries a rule id, a file:line, and the config key that silences it. The five graphs of this corpus — including the full dep of all 4,457 files drawn on one canvas — are on a page of their own.

Start

Three lines.

01 zzop init writes the config · once per tree
02 zzop analyze . analyze this tree · JSON out
03 zzop cross ./web ./api join two repositories

No Node.js, no npm, nothing to compile — download the binary from GitHub Releases.

zzop
A plain CLI for a terminal or CI. JSON to stdout.
zzop-mcp
An MCP server for your agent. Install the plugin and you run no commands — the agent asks.

A config is required rather than optional: the names zzop would otherwise guess about your project live in it, and a key you don't declare is a judgment zzop doesn't make.