AgentDesk turns a company name into a researched outreach email using three
separate AI agents — but the point of this project isn't the emails. It's that
the pipeline is governed so it structurally cannot ship a claim
nobody can back up.
Researcher
Haiku
web search · read-only
→
Drafter
Sonnet
no internet access
→
QA Reviewer
Opus
different model family · can't edit
Five checkpoints stand between a company name and a human inbox — only one is a model:
- Prompt contract — each agent's rules of engagement
- Schema validation — malformed output is rejected, never retried
- Deterministic checks — word count, banned phrases, every claim traced to a source
- Adversarial review — the one model judgment call, scored against the brief
- Release decision — recomputed in code; the reviewer's own verdict is advisory
ESCALATED and HALTED are success states, not errors. If research comes up
thin, the pipeline refuses to draft rather than invent facts — that's a halt. If
the reviewer keeps blocking a draft after the retry budget runs out, the system
routes it to a human instead of quietly lowering the bar — that's an escalation.
Both mean a gate did its job.
REJECTED is different — it's a defect, not the gate doing its job. It means
an agent's own output broke its contract: a field over its length limit, a
malformed id, an unparseable reply. The gate correctly refused to pass it on, but
the correct next step isn't "nothing to see here" — it's fixing the agent that
produced it. Of the 14 REJECTED runs below: 7 were the researcher's schema
under-specification (field-length overruns, malformed claim ids) — fixed in the
source, and confirmed live afterward with zero recurrences across 5 fresh runs.
3 were citation markup leaking from the search tool into brief fields (1 original,
plus 2 more that same live-testing batch found) — also fixed in the source since,
a stripping step this time rather than just a prompt reminder, but verified only
on fixtures so far, not yet proven live. 3 were an output-budget truncation at the
drafter or QA stage, already fixed in an earlier pass before any of this. The
remaining 1 was a single structurally malformed reply, a one-off. These runs
predate all of that and are left as-is, not backfilled or hidden.
Quality gate, measured honestly: on an 18-case mutation harness,
deterministic code alone catches 14 of 18 bad drafts and briefs at zero false
positives. The remaining four need a model's judgment call to catch, and that
measurement hasn't been run yet — stated here as a limitation, not rounded up.