How I AI: No Vibes, Just Intent
The four-document pipeline I use to run long AI-assisted engineering efforts — research, plan, execute, release — so a dozen memoryless chats add up to one coherent build.
This is the process I run today — not an experiment. An earlier case study, Intent-Driven Autonomous Delivery, was a proof of concept asking a narrow question: can an agent take a precisely-specified requirement from intent to a tested, committed branch with no human in the loop? It could. What follows is what that answer turned into once it had to survive real, long-running work — the same premise that intent must be precise enough to execute against, hardened into the pipeline I actually run on every multi-week effort.
The Problem
Every long-running effort I run with an AI coding agent hits the same wall: the agent’s memory ends when the chat does. A multi-week refactor doesn’t fit in one session, so it gets split across a dozen, and each one starts from zero. It re-derives settled decisions, re-litigates closed tradeoffs, quietly widens scope when the work gets awkward, and reports a phase complete because it remembers doing the work rather than because the diff proves it. Reasoning quality isn’t the problem — nothing outside the conversation holds the state, so drift compounds silently and surfaces three phases later. I was losing more time reconstructing context and auditing “done” work than I saved by having the agent write the code.
The Solution
I moved the state out of the conversation and into the repository. Every effort now runs through four stages, each producing a document checked in alongside the code: a research document that investigates and refuses to plan, an implementation plan that phases the research into single-chat units, an execution loop where each phase must first prove the previous one actually landed, and a release step where committing and logging what happened are part of finishing the phase, not a separate request. Every research finding carries an ID that stays traceable to the commit closing it. The chats are disposable; the documents are not. Any fresh session gets a copy-pasteable prompt and reconstructs what it needs from files.
Outcome & Impact
Two research documents — roughly 1,000 lines between them — converted into 19 executable phases across two concurrent plans, each sized to fit a single chat, executed by sessions that share no memory and still land on the same architecture. The measurement-first phases earned their keep immediately: a probe run before any feature code overturned three of the research’s own conclusions (a payload-limiting parameter the vendor silently ignores, a monolithic fetch that proved impossible at every horizon, and a classification field that collides on exactly the dates that matter most). A baseline phase whose only job was to record numbers surfaced an unrelated live defect: a poll meant to run once a minute was firing every 1.1 seconds. Neither would have been caught going straight from “here’s the problem” to “write the code.” Five completed phases are marked done with deviation rather than quietly reshaped, each carrying the measurement that justified the departure — so a future reader can tell a deliberate decision from drift.
My Role & Contributions
| Aspect | Detail |
|---|---|
| Role | Sole author of the process and every document produced by it; I direct the agent, it writes the code |
| Team size | 1, plus AI agents |
| Timeline | Evolved over roughly six months of personal projects; the version described here has run two concurrent efforts to date |
| Scope | Document formats, the ID-traceability scheme, phase-sizing and gating rules, the verification protocol, and the packaged skill that generates plans from research |
| Key decisions | Separating research from planning as a hard rule; keeping progress in the plan file rather than a second document; requiring the next chat to verify the previous chat’s work against the diff; treating measurement as its own phase |
Technical Overview
The pipeline is four artifacts and one loop. Nothing in it is a tool I had to build — it’s a discipline enforced by document structure.
Research is not allowed to plan. Each research document says so in its opening lines, and every finding is tagged measured (a number counted or a code path read at a named commit) or inferred (follows from the code, but needs a live session to confirm). Requirements get stable IDs, unresolved tradeoffs go in an open-questions table alongside what would settle each one, and a final section names what is out of scope so the plan can’t quietly absorb it.
The plan turns findings into phases, and progress lives in the same file. A requirement index maps every research ID to the phase closing it. Each phase carries a goal, numbered tasks, falsifiable acceptance criteria (“this grep returns nothing”, not “performance improved”), and a Do not list for where it could plausibly overreach. Phases are ordered by dependency before severity, with load-bearing orderings called out and justified. Below sits a phase-status table and a reverse-chronological decisions log every phase appends to before committing.
Handoff prompts are the interface. The plan ends with one copy-pasteable blockquote per phase: the model and effort to set, the documents to read, the exact commands that confirm the previous phase landed, and the scope of the current one.
Challenges & Key Decisions
Making a memoryless chat prove the last one landed
Having each phase read the decisions log to learn where things stand fails, because the log is written by the same kind of agent that reports optimistically. So the rule became: “I changed it” is not evidence; the diff is. Every handoff prompt opens by re-grepping the exact symbols the previous phase claimed to change and re-running the specific check it was accepted against, with an explicit instruction to stop and escalate if any of it is missing. That caught a real one: an end-to-end browser spec written in an early phase passed only during certain market-session windows, because the harness stubbed the data but not the clock. It stayed green for two more phases until a later verification step ran it at the wrong hour.
Two efforts on the same files at the same time
A calculation-repair plan and an architecture-refactor plan ran concurrently against an overlapping set of files. Merging them into one sequential mega-plan would have stalled the architecture work behind math verification it didn’t depend on. Instead each plan carries an explicit file-footprint table for the other effort, the two phases that genuinely couldn’t proceed are gated on specific repair phases landing, and “needing to edit a file in the other effort’s footprint” is a stop-and-escalate condition rather than something to negotiate mid-phase. Each effort got its own long-lived local branch. The gates held; the branches never collided.
Deciding what a phase is allowed to touch
The most useful section in a phase turned out to be Do not. Left unconstrained, an agent asked to extract a data contract will improve the contract while it’s in there — renaming a key, fixing a nesting quirk — which makes the identity test unwritable and hides a regression inside a refactor. Writing the guardrails down converts that from a mid-flow judgment call into a stated boundary. The same instinct produced the rule that any extracted contract must first be byte-identical to what it replaces, with the test written before the cutover so it fails first.
Tests that are honest about what they don’t cover
Each plan carries a standing regression set measured green at a named baseline commit, so a failure is a regression rather than an inherited problem. Deliberately excluded suites are listed with their known state and the reason — one is documented as “expected at 28 passed / 1 failed, investigate if that ratio changes,” which beats both fixing it under time pressure and letting it rot unexplained. Fixture-backed tests skip rather than fail when the fixture is absent, since fixture data stays out of version control.
Lessons Learned
- Separating research from planning is the highest-leverage rule here. When one document does both, the investigation bends toward whatever is convenient to implement. Forbidding the research from sequencing anything is what makes it safe to say “I don’t know yet, here’s what would settle it.”
- Measurement deserves its own phase. Both found something the research had wrong, and one found a live defect outside its own scope. Baselines also can’t be captured retroactively — once the render path changes, the “before” number is gone.
- Progress belongs in the plan file, not a second document. An earlier version kept a separate progress file and the two drifted apart within a week. One file means a fresh chat can’t read the stale half.
- Record deviations in the commit message, not just the log. A future
git logread shouldn’t make a deliberate, measured departure look like drift.