The Dissent
shippedAn agentic newsroom that researches, writes, edits, and publishes daily journalism across a set of specialized desks — autonomous end to end, live on the web.
- Stack
- Next.js · React · Python · Postgres · edge-deployed frontend · frontier and open-weight models
Where this came from
I'm a heavy news reader, and I kept noticing the same gap: the stories I cared about most — local, niche, weirdly specific — were exactly the ones no newsroom could afford to staff. Beat coverage is expensive. So I started sketching the inverse: what would a paper look like if the marginal cost of one more desk, one more beat, one more story was close to zero?
The Dissent is my answer: a daily newspaper where the entire newsroom is a set of cooperating agents, and humans set the standards instead of typing every word. It publishes every day, and it's still the first thing I check every morning — which feels like the real success metric.

The shape of the system
Ingestion and production are separate tiers with an append-only handoff between them, so acquisition can fail, stall, or be replaced without the newsroom noticing. Everything downstream of that handoff is a durable state machine: a story is a row with an explicit lifecycle, and every transition is a committed fact rather than a step in a script. Crashes don't lose work; they lose a subprocess.
acquisition → normalize → candidate pool → lifecycle state machine
→ reporting agent → draft → editorial review
→ revise ⟲ / endorse → publish → edge
A dispatcher watches lifecycle state and claims work under mutual exclusion at the data layer, so exactly one worker ever owns a story — no leader election, no external queue broker, no split-brain. Claimed work runs as a bounded child process with ceilings on wall clock, turn count, and spend; an agent that goes strange gets reaped rather than reasoned with. Reactive work — a story waiting on a reporter, a draft waiting on review — always preempts speculative beat scanning, which means the system spends its budget on things a reader will actually see.
Each desk is a self-contained agent with its own prompts, sources, and tool surface. One of them is the editor: it reviews every draft that reaches ready and either endorses it or returns it with revisions. Nothing publishes without passing that gate.
Fault domains are the product
The most important decision in the codebase is also the least fashionable one: desks share no runtime. Common capability is vendored into each desk rather than linked from a central module, and equivalence is enforced by tests instead of by discipline. It is deliberate duplication, and it has paid for itself many times over.
The property I actually wanted is blast radius. Any desk can be rewritten, upgraded, or deleted without touching the others, and when one breaks at 3 a.m., it breaks alone. The same instinct runs through operations: run caps, per-run budgets, circuit breakers, timeouts, quota parking, idempotent publishing, and dedup gates at every stage where duplicate work could escape. The system is designed to fail quietly and recover on its own, because nobody is watching it most of the time.
Cost is an architectural constraint
An agentic system you can't afford to run is a demo. The first working version burned real money per day for a modest amount of output; a round of cost work cut spend by roughly 80% while output went up. The lever wasn't cheaper prompts — it was treating model selection as policy rather than habit.
Every model call in the system resolves through a single routing layer that maps each pipeline step to a capability tier. The tiers are defined by consequence, not by convenience:
- Reversible work — classification, tagging, dedup checks, beat scans — runs on the cheapest tool-capable model that clears the bar. Being wrong here costs a retry.
- Research work — legs of reporting, drafts on the softer desks — runs mid-tier, optimizing for tool-use quality and latency.
- Liability work — final editorial review, investigations, anything asserting facts about named real people — runs frontier-tier only. The router fails closed: if a liability step ever resolves to a model outside the approved set, it raises rather than degrades.
The quality bar lives at review, so that's where the compute goes; everything upstream is allowed to be cheap. Pair that with aggressive context reuse — a newsroom re-reads its own institutional memory constantly — and that's most of the cost story.

The retrieval layer
Every published article and research artifact is embedded on write. The vector index started as a purely defensive instrument: a semantic dedup gate that stops the paper from running the same story twice even when two sources describe it in completely different language — the case exact-match and URL-level dedup will never catch.
The interesting work is turning that index offensive, in three layers that stack. Cluster inbound material to detect a story forming before anyone assigns it. Make reranked recall mandatory at draft time, so no reporter writes as though the paper has no memory. And eventually close a slow loop where reader behavior informs prompt revisions — gated on human approval, because an unsupervised optimizer pointed at engagement is how you get a tabloid. The foundation is shipped; the rest is specced and queued.
From a paper to a fleet
The Dissent started as a San Francisco paper. It isn't anymore. The architecture turned out to be portable: single-tenant per market, one deployment per city, market-specific behavior expressed as configuration overrides rather than forks. There are three editions running today as sibling deployments, supervised from a small fleet console that treats each city as a managed instance.
A scheduled coding agent ships incremental features to the site on its own. Recurring jobs handle digests, byline curation, source monitoring, and settlement. My role has drifted from writer-of-code to something closer to publisher: I set standards, read the output, and intervene where the system needs judgment.

What it taught me
The demo version of this project is easy; the production version is the actual work. Reliability came from boring decisions — isolation between components, explicit lifecycle states, gates between stages, ceilings on everything — not from better prompts. And economics turned out to be a design problem in its own right: an agentic system you can't afford to run is a demo; one you can is a product.
It's the project that taught me the most about making agents reliable in production rather than impressive in a screenshot — and it's still publishing while I sleep.