Skip to content
All builds

RelayResearch Pipeline

What it does for you

A four-agent research pipeline with strict JSON contracts, capped retries, a full run trace, and a citation checker that verifies every quote against its source.

Relay screenshot

Screenshots

Relay screenshot 1

In more detail

Relay takes a research job and passes it down a line of four AI agents: a Researcher, an Outliner, a Drafter, and an Editor. Every handoff gets checked against a strict contract, and the final brief only keeps facts that cite a source and quote it accurately. The demo runs on a fictional pack of 8 sources about heat pumps for homeowners, and it is labeled fictional everywhere it shows up.

Honest limits

The sources are fictional fixtures, not real research. Claude mode runs each stage through the API and holds it to the same validators, but it was tested with a simulated reply, not live calls. No paid APIs were called during the builds. The Cowork skill that pulls real sources with WebSearch and WebFetch ships in the folder, but the case study does not record a live run of it.

How I built it

This was one of the Claude Cowork projects. I told Cowork to one-shot all of them, and for this one I set the spec: four stages, contracts written as plain JavaScript validators, retries capped at 2, a full run trace, a citation checker that verifies quotes against the source text, subagent files, and a Cowork skill.

A separate Cowork session built it in one autonomous pass: the fixture sources, the core, the 200-assertion test file, the page, four agent definitions, the skill, and a sample PDF. That session dropped finished builds of all 20 Cowork projects into the repo within about a minute. To be honest, setting up a Cowork plugin felt faster than setting up a Claude Code build.

Cowork also checked its own screenshots, caught an API key field that should have been hidden (a display: grid rule beat the hidden attribute), fixed it, and reshot.

What I learned

  • Fault injection belongs in the design, not just the test file. A pure stage returns the same wrong answer every time you retry it, so the only way to see the retry path work is a wrapper that misbehaves only on attempt 1.
  • A "does this sentence carry a fact" rule needs comparisons, not just numbers. My first cue list missed "saw the largest bill reductions," so those sentences could have gone uncited. Adding largest, smaller, fewer, more than, and less than closed the gap.
  • A hype-word filter has to fix the grammar it breaks. Swapping in "large" produced "An large number," so the replacement now captures the article and re-picks a or an.
  • Never let a stage vouch for itself. The Editor returns a citation report, and the orchestrator recomputes it and fails the stage if they disagree. It also clones every input, and a test proves a hostile stage cannot corrupt the source pack.

What carried forward

The skeleton is the house pattern from June: a DOM-free core (pipeline.js) imported by both the page and verify.mjs, plus a zero-dependency serve.mjs, so the shipped code is the tested code. What I took out of it: treat every agent handoff as a contract the orchestrator checks itself. That same "verify it in code" thinking shows up again in #76 and #77.

If I took it further

I would have the Researcher return character offsets with each quote so the viewer can highlight the exact span in the source. I would also cache each stage by its input so a retry of stage 3 never re-runs stages 1 and 2 in Claude mode.

#071 Built with Claude Cowork September 23, 2026 200 automated checks

Want one like this?