The Agentic Harness: What It Actually Takes to Run a Monorepo Through an AI Agent
People ask me some version of the same question when they hear how much of Singularity — the monorepo underneath most of what I've been writing about this year — gets built through Claude Code rather than typed by hand: "so the AI just... writes it?" The honest answer is no, and the interesting part isn't the AI. It's everything I had to build around it before that arrangement became something I could actually trust across a project this size, run over hundreds of sessions, months apart, by an agent with no memory of yesterday unless I gave it one.
I've come to think of that scaffolding as a harness. Not in the "guardrails that stop the AI from doing something bad" sense — I have some of those too — but in the older sense of a harness on a draft animal: a structure that converts raw capability into directed, repeatable work. Claude Code is genuinely capable. Left alone across a 20-plus-bounded-context Nx monorepo with no procedure, it is also genuinely unreliable in exactly the ways you'd expect from something that starts every session with zero context: it forgets decisions, re-litigates settled architecture, drifts a planning doc out of sync with the code three sessions after a hand-off. None of that is a model problem. It's a structure problem, and it's solvable.
The Problem Nobody Warns You About: Zero Memory, Every Session
Here's the thing that surprised me most going into this. The actual coding was never the hard part — Claude Code is good at CQRS handlers and Angular components. The hard part was that every session starts from nothing. There's no persistent "the AI remembers this codebase" the way a human contractor accumulates context over months on a project. Each session is, in a real sense, a new hire who read the whole codebase overnight and forgot everything about the conversation we had yesterday.
That's the actual constraint the entire harness is built to solve. If I can't fix the memory
problem at the model layer, I have to fix it at the process layer: write down what a fresh session
needs to know, in a place a fresh session is required to look, in a format cheap enough to keep
current every single time. That's CLAUDE.md, and it's grown into something closer to an
operating manual than a README — architecture guide, bounded-context tags, Session Start and
Session Stop procedures, a PR checklist, per-step commit discipline, all in one file every session
reads before doing anything else.
Session Start / Session Stop: The Bookends
The two procedures that matter most are the ones that run at the boundary of every working
session — Session Start and Session Stop, both defined in CLAUDE.md.
Session Start is nine steps: load a persistent memory file, check docs/planning/active-projects.md
for what's actually in flight, run git status and git log, find the phase doc for the current
branch, read the phase summary and checklist, scan the parking lots and session notes for anything
left over from last time, run a docs-consistency check across everything just read, brief me in
3–5 bullets, and only then — if needed — cut a new phase branch. Session Stop is the mirror image:
update the checklist, update the phase summary with any new decisions, update the feature doc's
phase status, run the docs-consistency check again, update active-projects.md, lint/test/build
the active project scope, write any hard-won lessons to the knowledge base, update memory, commit,
push, and open the phase PR if the checklist is actually done.
Reading that as a list makes it sound like ceremony. In practice it's the only reason a session
that starts cold can be productive inside the first ten minutes instead of the first hour spent
re-deriving what I already decided last time. docs/planning/active-projects.md right now tracks
five actively "in flight" efforts at once — Developer Portal on a sprint/story/example branch
model, the Lean-Agile MVP Skills work, the docs-store CouchDB+TypeDB spike, the new docs-store-api
Platform API scoping, plus one blocked item — and every one of them has to be resumable by a
session that has never seen it before. That's not a nice-to-have. Without the active-projects
table as a single source of truth, I genuinely could not keep five concurrent long-running efforts
straight across sessions that are sometimes weeks apart.
Docs as the Actual Source of Truth, Not a Record of One
The thing I underestimated when I started working this way is how fast planning docs drift from each other once an AI agent is producing most of them. A feature doc says a phase is "in progress" three sessions after it actually merged. A workshop introduces a renamed term that never propagates into the doc written the day before. A sprint schedule gets duplicated into a second doc and the two quietly diverge.
That drift is what check-docs-consistency exists to catch — a skill, not a one-off review, run
at every Session Start and Session Stop rather than as a periodic sweep. The algorithm is
deliberately narrow: extract every checkable claim from a downstream doc (a count, a status word, a
piece of vocabulary a workshop coined), verify it against the specific upstream doc it depends on,
and classify any mismatch as a stale claim, an un-propagated decision, an append-not-merge
duplication, or an internal contradiction. It was extracted after running that exact check by hand
four times on one project and finding a real defect every single time. Running it at every session
boundary is what lets this monorepo skip an expensive, periodic, workspace-wide consistency sweep —
drift gets caught at the boundary where it's cheapest to fix, one project's docs at a time, instead
of accumulating into something that needs its own dedicated remediation phase later.
Role Personas: Getting the Right Judgment Applied to the Right Work
One thing I got wrong early on: I had written seven detailed, research-grounded role prompts —
Product Owner, UX Designer, Architect, SRE/DevOps, QA Tester, UAT Tester, Developer — as reference
documentation under agents/roles/, and then did the work under the default assistant persona
anyway, because nothing in the tooling actually nudged anyone toward using them. The fix was to
add tooling support for project-scoped subagents, letting me create thin-pointer wrappers for each
role. This is a good example of the harness correcting itself mid-project rather than me writing a
perfect process up front. Claude Code supports project-scoped subagents via .claude/agents/*.md,
so each role file got a thin-pointer wrapper — not a duplicate of the research, just enough to
summarize the identity and non-negotiables and then send the agent to read the source file in full
for anything non-trivial.
The rule for when to actually invoke one is deliberately narrow: use a role subagent when the
task's primary success criterion matches that role's key question — for the UX Designer, "can the
user find and use this capability without help?" Routine work that happens to touch a UI file
doesn't need it. Design judgment as the actual point of the task does. This piece you're reading
right now, for what it's worth, was drafted by the content-writer persona, grounded in
agents/content/voice_system_prompt.md — one more instance of the same pattern applied to
non-code work.
Procedure Discipline: Commits, Branches, and the Cost of Skipping Either
A few of the harness's rules exist purely to make a long AI-driven history legible after the fact.
Per-step commit discipline means every phase step produces exactly one commit before the next step
begins — no batching three checklist items into one commit because it felt faster in the moment.
The phase-branch model requires every implementation commit to land on a phase/<feature>/<N>-<slug>
branch cut from the feature branch, never directly on main or the feature branch itself. Defect
resolution follows a test-first discipline in a very literal sense: write the failing test, commit
it alone so there's a permanent red-state record in git, then fix it in a separate commit.
None of these are abstractly "good practice" bullet points I copied from somewhere. Each one exists because skipping it once caused a real, specific problem that showed up later and was expensive to untangle — which is exactly what the knowledge base is for.
The Knowledge Base: Lessons That Would Otherwise Repeat
docs/knowledge-base/lessons-learned.md is, as of this writing, over 7,600 lines, and I don't
think of that length as bloat — it's the actual cost of not re-learning the same trap twice. A
recent entry: copying a workshop-authored Gherkin Feature verbatim into a real Cucumber suite hit
three separate failures before the first Scenario would even run — a soft-wrapped Then step that
Gherkin's parser reads as two malformed lines instead of one wrapped sentence, a Cucumber
Expression {string} silently failing to match an unquoted identifier (reported as "Undefined,"
not an error), and a regex step definition throwing an arity mismatch because a capture group had
no matching function parameter. Every one of those three failures is either silent or mislabeled by
default. None of them look like what's actually wrong until you've hit it once and written it down.
Another one, from designing the Sprint/Story/Example branch lifecycle itself: a text-only version
of a process that had originally been designed as a diagram quietly dropped an entire branch — the
perpetual dev branch every merged Example needs for continuous integration and third-party
webhook connectivity a local workstation doesn't have. Nothing about the text procedure was
internally inconsistent. The diagram just encoded a parallel branch a linear list of steps doesn't
naturally represent, and the gap was invisible until I supplied the original reference diagram and
noticed the row was missing. The general lesson I took from that one: when a process was originally
designed as a diagram, ask for the diagram before finalizing an ADR from the prose description
alone. A process description in words is a lossy re-encoding of the original design, and the losses
are exactly the kind of thing that look complete until someone who remembers the original notices
what isn't there.
I'd be lying if I said every lesson in that file represents an hour saved later. Some of them are narrow enough that I'll probably never hit that exact trap again regardless of whether it's written down. But the pattern — something takes real time to diagnose, the root cause isn't obvious from the error message, and hitting it again cold would waste the same time — is a good enough filter that the file has stayed genuinely useful rather than turning into noise.
What I'd Still Call Unfinished
In the spirit of not smoothing this into something tidier than it is: the harness has gaps I know
about and haven't closed. Wrapper drift is an accepted, unenforced risk — if a source role file in
agents/roles/ changes meaningfully, nothing automatically flags that its .claude/agents/
wrapper needs a spot-check. The check-docs-consistency catches drift between planning docs, but
it explicitly doesn't cover published content — voice and factual accuracy in things like this
article are a separate reviewer's job. And the whole thing assumes a level of discipline about
reading the phase docs before writing code that is easy to skip when a session feels rushed; the
harness makes skipping it visible after the fact (a stale checklist, a check-docs-consistency
failure), not impossible in the moment.
What I can say with more confidence is the shape of the trade this is: less time evaluating whether a given line of generated code is locally correct, and a lot more time up front designing the procedure that makes an amnesiac collaborator produce something coherent across a project this size, over a timeline long enough that no single session can hold the whole thing in its head. That second kind of work turned out to be the real engineering problem. The code was, comparatively, the easy part.
If you're running something similar — long-horizon work through an AI agent across a codebase big enough that no one session can hold the whole thing — I'd genuinely like to hear what your version of a memory file, a session-boundary procedure, or a lessons-learned log looks like. I suspect a lot of us are independently converging on the same shape of answer.
Want to know more?
Interested in "The Agentic Harness: What It Actually Takes to Run a Monorepo Through an AI Agent"? Leave your details and I'll follow up with more information.