---
title: "Content Ops: an evidence-first content engine, and what it took to run it at scale"
url: "https://toddpaulbrownjr.com/writing/inside-content-ops/"
author: "Todd Paul Brown Jr."
description: "Content Ops drafts only from an approved knowledge base. Running it at scale meant 92 of 95 pages in two days, a same-night incident loop, and choosing…"
kind: "article"
updated: "2026-09-26T02:50:32+00:00"
---

# Content Ops: an evidence-first content engine, and what it took to run it at scale

Content Ops is live in production at version 5.12. It's a console for running a client's knowledge and content — discovery notes, an open-questions tracker, a knowledge base where documents move through an editorial lifecycle with version history, a content plan built from keyword data, a drafting pipeline that writes only from approved sources, and a one-way sync that publishes approved knowledge into Sadyr so the revenue agent answers from the same documents.

Most AI content starts from a prompt and hopes. Content Ops starts from evidence: what the business actually knows, approved by a person, with sources attached. The AI proposes changes as a changeset, and a human reviews them before anything is written. Adroit runs on it directly — it drafted Adroit's own website, 92 of 95 planned pages in two days of batch runs, with 74 pages updated and 17 created, now live.

I built it because I wanted content that could survive scrutiny. The usual workflow — write from a prompt, maybe check it later — produces content that sounds right until someone asks where a claim came from. Content Ops inverts that: the knowledge base is the source of record, and drafts cite it.

## How it works

Claude Code writes the code, the tests and the documentation. I set the backlog, review, and decide what ships. The app is Next.js and TypeScript with a Python agent layer and PostgreSQL, hosted on Sevalla. Every release has to pass the full test suite and a production build before it's pushed. Current test counts: 839 TypeScript tests and 57 Python tests passing, 0 failing, measured at commit `f861f98` on 25 September 2026.

The architecture is straightforward. A document enters as draft, moves to needs review, then to approved when someone signs off. Approved documents get embedded and indexed. When the drafting agent runs, it pulls context only from approved documents — no web search, no model training data, just the knowledge base. Every claim in a draft carries an internal citation marker pointing back to its source document. A human reads the draft, checks the sources, and decides whether it publishes.

It runs one project at a time. I tested three parallel jobs early on and the process ran out of memory. The choice was a bigger server or a slower queue. I chose slower — the architecture stayed simple, the cost stayed flat, and nothing broke under load because the load never spiked.

## What broke and how I fixed it

The first time Content Ops ran at real concurrency — rewriting Adroit's own live website — it produced three production defects in one night, all traced to the same habit in agent-written code.

About the same time Claude Code shipped in February 2025, and while Google Cloud's blog was describing agentic orchestration as "a new paradigm" that March, I was learning what agent-written code does under pressure. The defects all came from one pattern: deleting an entire database table and re-inserting every row on every write. Harmless at one job at a time. A race condition at three.

**The runs table.** Jobs failed within seconds of starting. The runner's open-heartbeat-close logic still used a whole-table write, which raced under three concurrent jobs and threw duplicate-key errors. I found it directly from the raw crash and fixed it that same evening.

**The artifacts table.** That same evening, I had built a new capability on a hunch: every terminal job path would now write a postmortem record, with an export endpoint and a script to digest the export before I read it raw. It paid for itself before midnight. I deployed the next version, the app fell over, and I uploaded the first postmortem export — 227 entries. The summarizer surfaced the failure in one screen: 29 duplicate-key errors and 151 entries where a project had simply stopped. The cause was the same habit, in a third table. A function that rewrote the whole artifacts table on every stage, which both collided at concurrency three and generated enough database load to exhaust the connection pool. Every API call failed, health checks restarted the app, and nothing worked. Fixed the same night with row-scoped writes.

**The jobs-table polling.** The third defect showed up in a different log entirely — a structured Sevalla log with 749 entries. It showed 311 of 323 API errors were pool timeouts, arriving in bursts of 40-plus distinct IDs every 10 seconds. The cause: the Content Plan screen polled one request per card, for roughly 92 cards, every 10 seconds, and each of those requests read the whole jobs table to find a single row. Fixed with one batched request that returns summary data for all requested IDs at once.

Two lessons. First: agent-written code can carry one architectural habit across multiple unrelated tables, so finding it once doesn't mean it's gone. It showed up in three separate tables before the pattern was fully eliminated. Second: build the diagnostic tooling before the incident that needs it, not after the second one. The postmortem summarizer was built for visibility into the first crash and ended up finding the second defect the same night.

## The batch run

The website rebuild ran from 8 to 9 September 2026. Drafts for 92 of 95 planned pages in two days of batch runs, across a pilot, an out-of-memory-stopped run, a serial run, and a gap-fill run. 74 pages were updated in place and 17 created. The site went live on 23 September, with the home page's JavaScript compressed from 103 KB to 2 KB, CSS from 78 KB to 10 KB, HTML from 79 KB to 34 KB, and eight plugins retired for native theme code.

Content Ops now publishes 24 approved public documents into Sadyr's knowledge base, with 26 more held back deliberately — documents that exist but aren't ready for the public agent to cite yet. Sadyr answers from the approved set, and the chat abstains on anything not in it.

## What cost per page actually is

Cost per page is not published yet. Content Ops began capturing cost data only at version 5.10, and not enough measured history exists to publish a number I would stand behind. The system works, the drafts are good, and the cost is low — but I won't quote a figure until I have five or more priced pages with logged spend.

## What's next

Two demos are live on the production platform: an insurance provider's plan explainer and a sports league's manager rulebook assistant, both running on Sadyr with Content Ops knowledge bases behind them. Status word: demo. No paying customers yet.

The system is stable, the tests pass, and the postmortem tooling catches failures before I see them in a log. The next milestone is the first paying customer — someone who uses Content Ops to draft their own content from their own knowledge base, not a demo I run for them.

Content Ops is what I wanted when I started: an evidence-first content engine that drafts only from what a business actually knows, with every claim traceable to an approved source. It works at scale because I chose slower over bigger, and it survives scrutiny because the knowledge base is the source of record. The drafts cite their sources, a human reads them, and nothing publishes until someone says it's ready.
