Daniel StoyanovSentinelPydantic AI · Python
Sentinelview overviewstack Pydantic AI · Pythonruns 3

specialist agent · Pydantic AI · Python

Sentinel

Finds the bug, then tries to disprove itself

A code review agent with an adversarial second stage. Only findings that survive a majority reach you, so the report is short and real.

Take a look inside3 example reviews

Verification panel · F-418

mediumsrc/session/store.ts:40
killed 2–1 · not reported

Unbounded session payload can be written to a key that never expires

  • correctness: confirmedTrue of the signature: data is Record<string, unknown> and createSession imposes no limit itself.
  • security: refuteddata is never attacker-controlled. Both call sites build it from already-validated server-side fields.
  • repro: refuted64 MiB payload → PayloadTooLarge at store.ts:16, nothing written. express.json caps the body at 16 KiB first.
Raised, then refuted by 2 of 3 lenses, and still shown. From the demo run “A finding gets killed 2–1”.

01What makes it special

  1. Three verifiers, each told to refute

    Every candidate goes to three verifier agents built from the same code with different instructions: correctness, security and repro. They run concurrently, default to refuting when unsure, and a finding is reported only if a strict majority confirms it.

    The repro lens reasons over the diff and the surrounding source. It does not execute code.

  2. Killed findings stay on the page

    Refuted candidates are printed with each lens’s reason, struck through rather than dropped, so you can watch the filter work instead of taking it on faith.

  3. A vague finding fails the type

    Findings are typed Pydantic models, and the failure scenario is a required field that must name something observable: a literal input, an expected-versus-actual result. A hedged claim, or one citing a line the diff does not contain, is rejected and handed back to the model to fix.

  4. No way around the panel

    If the model skips a lens, the orchestrator runs it anyway, and reporting a finding that was never registered is a hard error. A confirmed critical or high exits with code 1, so it drops straight into CI.

02Inside the demo

  1. run 1/3|| vs ?? regressionA one-character change that makes an explicit ttl of 0 unreachable.
  2. run 2/3A finding gets killed 2–1Sentinel raises a plausible OOM claim, then the panel refutes it. Nothing is reported.
  3. run 3/3Critical: auth guard narrowedread_diff fails on a detached HEAD, then an empty bearer turns out to grant scopes ["*"].

Watch forA finding getting killed. Sentinel surfaces its own refuted candidates so you can see the filter working: this is what keeps a review from being plausible-sounding noise.

03Under the hood

Stack
Pydantic AI · Python
Pattern
Typed agent + adversarial verification ensemble
Packages
pydantic-ai · pydantic
Source
agents/sentinel-review/sentinel/reviewer.py
Doc
api_documentation/pydantic-ai.md

Pydantic AI validates every finding against a schema and retries the model when it does not conform, so the verification stage receives structured findings rather than prose it has to parse. Strong typing is what makes the multi-voter stage cheap to build.

Tools

  • read_diffrisk: safeRead the changed hunks under review.
  • raise_findingrisk: safeRaise a candidate finding with a concrete failure scenario.
  • verify_findingrisk: safeAttempt to refute a finding through a named lens.

Watch a review run

The diff, the run log and every panel vote, across 3 reviews.

Take a look inside