The Multi-Agent Audit

Point sixty-seven read-only agents at one codebase, slice it eight ways, and let each agent look at exactly one thing. The output is not opinions — it is a single prioritized report with a technical-debt score. This is how the audit runs, and what two real ones found.

Version 1.0 · Updated

01

One Read, Many Eyes

An audit is a read fan-out: many agents looking, nothing changing. The pattern is mechanical. Partition the codebase into disjoint slices, assign every slice to every analysis domain, run the resulting grid of agents in waves, then hand all of their findings to a single synthesis agent that collapses them into one report. The same machinery, run in the opposite direction, becomes autonomous remediation — see the companion field report for the write half.

67parallel agents
8analysis domains
16waves
0–100debt score

Every agent runs in the background and writes its findings to a file; the main context stays clean and is notified on completion. A manifest.json records which agents finished and which are pending, so an interrupted run resumes from the last wave instead of starting over. Nothing the agents touch is mutated — the entire pass is non-destructive by construction.

02

Eight Domains, One Pass

Each domain is a lens — a fixed set of questions an agent asks of the code in front of it. Eight lenses sweep every partition; a ninth, axial drift, gets its own two-step pass (see §4). The lenses do not overlap, so two agents never report the same class of issue from different angles.

DomainWhat it looks for
ArchitectureLayer violations, circular dependencies, coupling
SecurityOWASP categories, credential handling, injection vectors
Code SmellsGod classes, long functions, DRY violations
Type SafetyAny usage, missing hints, type: ignore
Async PatternsRace conditions, blocking calls inside async, resource leaks
Error HandlingBare excepts, swallowed exceptions, missing context
Test QualityCoverage gaps, flaky patterns, mock overuse
Tech DebtTODOs, deprecated APIs, magic numbers
Axial DriftWrong-axis duplication — the N×M trap (§4)
03

Partition and Wave

The codebase is cut into source partitions and test partitions — slices by code area, not by size. One agent gets one (domain × partition) cell: a security lens over the adapters, a type-safety lens over the hub core. That keeps every prompt narrow and every finding traceable to a place. Agents launch five at a time — enough parallelism to finish in minutes, not so much that the final synthesis drowns in context.

1
Partition
Split source into P1–P8 and tests into T1–T6 by code area, so no two agents read the same files.
2
Launch a wave
Five domain×partition agents start in the background, each with one lens and one slice.
3
Collect
Wait for the wave to finish, then write each agent's findings to its own file in a consistent format.
4
Checkpoint
Update the manifest — completed and pending agents — so the run is resumable from here.
5
Synthesize
A final agent reads every findings file and emits one prioritized report.

Partitioning by code area is what makes the audit cheap to read at the end. Each finding already carries a file and a line; synthesis is a merge, not a re-investigation.

05

The Report It Produces

Sixty-six findings files are useless as a deliverable. The synthesis agent reads them all and writes a single AUDIT-SUMMARY.md — the only artifact a human is meant to open first.

  • Executive summary. Overall health, security posture, test-coverage status, the headline debt items.
  • Severity buckets. Every finding sorted into P0 (critical), P1 (high), P2 (medium), P3 (low) — with file and line.
  • Axial-drift summary. Contracts kept versus broken, N×M traps, and which were confirmed by semantic search.
  • Metrics dashboard. Issue counts per domain, the severity distribution, and a single technical-debt score on a 0–100 scale where 100 is pristine.
  • Recommended actions. Prioritized, each with an effort estimate, plus a top-10 quick-wins list: high impact, low effort.

The debt score is the one number you can track release over release. Everything else tells you what to fix; the score tells you whether the codebase is getting healthier.

06

Two Real Audits

The pattern is not theoretical. Roxabi runs it on its own agent factory, and the recaps live in the open. Two are worth reading in full.

A — Quality audit, 2 June 2026. A full sweep of the factory codebase: 3,291 files, every domain, every partition.

3,291files audited
1,258issues found
72/100debt score
11 / 0contracts kept / broken

The severity split was 2 · 172 · 664 · 427 across P0–P3, and all eleven import-linter contracts held — the architecture was sound, the debt was volume, not collapse. The two P0s are the kind of bug a single test run hides. One was a 165-line process_one method fusing streaming and non-streaming paths, processor hooks, session-ID updates, and error handling into one unreadable block. The sharper one: _log_turn caught every exception, logged it, and returned — and the caller then ack()'d the JetStream message. A failed SQLite write therefore permanently lost the conversation turn, with a green log line to mask it. Green ≠ correct, found by reading, not by running. This audit is the precursor the Autonomous Remediation report later paid down.

B — Codebase audit, 18 May 2026. A narrower, transversal pass on three axes — hexagonal purity, code mutualization, simplification — and a different kind of result.

This one scored no debt number; it produced a refactor map. The verdict was reassuring: zero import-linter violations, clean layers, isolated packages — the debt was localized, not systemic. Three jobs stood out: ~350 lines of dead code from a retired routing cluster, removable with zero risk; a handful of implicit ports scattered outside core/ports/; and a NATS heartbeat lifecycle copied verbatim across four clients, begging for a shared base class. What makes the recap worth reading is its discipline about false positives — two apparent duplications turned out to be deliberate role interfaces (Fowler) distinct from driven ports (Cockburn), and were renamed to break the homonymy rather than merged. An audit that cannot tell drift from intent generates busywork; this one drew the line and shipped seven PRs the next day.

Every recap — quality sweeps, cluster audits, token-isolation reviews — sits in one folder, alongside the playbook that defines the method.

07

What Scales

Agent count tracks codebase size, not ambition. The wave width stays roughly constant; only the number of waves grows.

CodebaseAgentsWave sizeDuration
< 50 files184~12 min
50 – 200 files344~22 min
200 – 500 files505~45 min
500+ files69+5~65+ min

The findings are specific to one repository. The shape is not — these are the parts that carry to any codebase.

  • Partition by area. One agent, one lens, one slice. No duplicate work, every finding pinned to a place.
  • Five-by-five waves. Parallel enough to be fast, bounded enough that synthesis still fits in one context.
  • Manifest-tracked. An interrupted run resumes from the last wave instead of starting over.
  • Two-step drift. A linter catches structure; a semantic agent catches intent; search confirms both.
  • Second-opinion gating. An unconfirmed claim is downgraded, not asserted — high recall without the false-positive tax.

The audit is only the read half. Once the report exists, the same fan-out runs in reverse to pay it down — that run is the Autonomous Remediation report. Read, then write, fully on the record.