The first version of Codeward's review engine was a single prompt: "Here is a diff. Review it for bugs, security issues, style problems, and architectural concerns." It worked, in the sense that it produced output. The output just wasn't very good.
The problem wasn't the model. It was the framing. Asking one pass to reason about security and architecture and bloat and correctness at once means it does all four shallowly, the same way a human reviewer skimming a 600-line diff at the end of a long day catches the obvious stuff and misses everything subtle. Depth requires focus, and focus requires narrowing scope.
From one generalist to a panel of specialists
We rebuilt the review engine around a simple idea borrowed from how good engineering orgs actually review code: different reviewers look for different things, and the best reviews come from combining several narrow, expert perspectives rather than one broad, shallow one.
Each PR is now handled by a set of specialized agents, each with a narrow mandate:
- A Security Agent focused on auth patterns, secrets exposure, and injection-style risks
- A Bloat Agent focused on duplication, dead code, and unnecessary complexity
- An Architecture Agent focused on boundary violations and module responsibility drift
- Additional agents scoped to specific domains as the platform has matured
Each agent runs independently, inside its own ephemeral sandbox per scan. That isolation isn't just a security boundary — it's also what lets each agent operate with a clean, focused context instead of a shared, cluttered one. A security-focused pass reasoning only about security produces measurably sharper findings than the same model reasoning about security as one bullet point among ten.
Specialization forces better prompts
There's a second, less obvious benefit to splitting agents by domain: it forces you to write much better prompts. A generalist prompt has to hedge — it can't assume much about what kind of code it's looking at or what "good" looks like, so it ends up giving generic advice that applies to everything and helps with nothing.
A security agent, by contrast, can be given a precise, opinionated brief: here are the categories of finding that matter, here's what a false positive looks like, here's the severity threshold that justifies escalating to a GitHub issue versus leaving a comment. That precision is only possible because the agent isn't also trying to reason about naming conventions in the same breath.
Agents need boundaries, not just prompts
Specialization at the prompt level only works if it's matched by isolation at the execution level. Each agent runs in its own Fly.io Firecracker microVM per scan — a fresh, disposable sandbox that's destroyed after the scan completes:
- One agent's analysis can't be polluted by another agent's intermediate state
- A misbehaving or compromised piece of scanned code can't affect other agents' scans, or the host
- Agents can run genuinely in parallel rather than time-sliced through a shared, stateful process
This is also why the queueing layer matters as much as the agents themselves. Each agent's work is a job in a BullMQ queue backed by Redis, which means the system can scale the number of concurrent scans without the agents stepping on each other, and a slow or failed agent doesn't block the rest of the panel from reporting back.
Consolidation is as important as specialization
It's tempting to keep adding narrower and narrower agents — a tool per language, a tool per framework, a tool per vulnerability class. We went the other direction on the security toolchain specifically: we retired four overlapping regex-based scanners in favor of three that covered the same ground with far less redundant noise. More agents isn't automatically better. The goal isn't maximum coverage on paper — it's maximum signal per finding a human actually has to read.
The same discipline applies to knowing when not to build a new agent. A category of finding that shows up once a quarter doesn't justify its own specialized pass; it gets folded into an existing agent's scope instead.
An orchestrator, not a vote
Specialized agents produce specialized findings, which means something has to reconcile them — decide what's actually severe enough to block a merge, what's worth a comment, and what's worth an escalated, tracked issue. That reconciliation layer is its own agent, sitting above the specialists.
Specialization makes each individual finding better, but only an orchestration layer makes the system trustworthy. Without it, you just have five agents shouting at once.
Curious what a panel of specialists finds in your codebase? Codeward's agents are already tuned for the categories that actually matter in production code — not a generic checklist.