Ideas to Execution
The runbook above is how one feature gets built. By late
August the harder problem was volume. Ideas were coming in
faster than I could shape them, two different AI vendors were
doing the work, and there were usually three or four sessions
running at the same time. Without some structure, the backlog
turns into whatever I mentioned most recently. So the
structure got built, and it's enforced by tools rather than by
my memory.
Three Vendors, One Set of Rules
I use Claude and Codex side by side in the same five
repositories, with Gemini as a third that only ever reviews.
The rules for how work gets done are written once, and the two
that write code read the same file. One copy each of the
skills that execute a plan, ship, and build an idea, shared by
Claude and Codex. A plan that Codex builds follows the same
model choices, reviews, and stop rules as one that Claude
builds.
When Claude reviews a plan, it hands the plan to Codex for a
second read, with no ability to change anything. When Codex
reviews, it does the same in reverse, calling Claude with
read-only tools. Gemini is the adversarial third read over
both of them, taking the plans and diffs from Claude and from
Codex and hunting for what each one missed, and it only ever
reads. Models from three different companies fail in different
ways, so one catches what another would wave through.
Who Reviews Whom
Claude
Writes code, and reviews the plans and diffs the
others wrote
Build + review
Codex
Writes code, and reviews the plans and diffs the
others wrote
Build + review
Gemini
Reviews both Claude's and Codex's plans and diffs, an
independent third read
Read-only
Every plan and every diff is read by at least one vendor
that didn't write it.
Both toolchains carry the same blocklist naming one model that
is never to be used, after it burned us on this codebase. On
September 10 I moved implementation from Sonnet 5 to Opus 4.8,
because reviews kept catching the same kind of small logic
mistakes and fixing them cost more than the cheaper model
saved. The runbook above reflects that. What matters is that
the process didn't have to change when the model did.
The last piece is shared memory. AI sessions don't remember
yesterday, and two of them running at once don't know about
each other. So every session writes what it did to a status
log in the documentation repository, which now holds 399
entries, 391 of them tagged by vendor: 292 from Claude and 99
from Codex. The rules for writing to it fit on an index card.
Re-read the file right before you write. Add to the end, never
edit what's there. Commit the second you're done. Never touch
text another session left behind. Uncommitted text is the only
thing one session can wipe out in another, so the rules make
sure it only exists for a few seconds.
My Day: A Board That Enforces Its Own Rules
My Day is the tool that sits between an idea and a branch of
code. It's three pieces: a Mac app, a small server on a
Raspberry Pi, and a phone app. The Mac app watches 31
repositories across seven projects and tells me which ones
need a human, whether that's something to push, something to
commit, something to merge, or something blocked. The phone
can capture an idea from anywhere and read the board, but it
can't move a card. The piece that matters here is the Ideas
board. Think of a JIRA board where every column move runs a
skill, and every skill has a gate.
The Board
Anyone
Inbox
Captured word for word from the desktop, the phone, or
a session. Capture isn't allowed to plan or build
Claude / Codex
Shaped
A short brief with kill criteria, an effort rating,
and rough tasks, written after reading the actual code
Claude / Codex
Planned
A step-by-step plan committed into the target
repository
Both vendors
Reviewed
The other vendor tries to poke holes in the plan.
Capped at ten waiting, because my reading is the
bottleneck
Michael
Queued
The go decision. Small ideas can skip plan and review
through an express lane
Claude / Codex
Building
Runs on its own, in its own copy of the code, with
four written reasons to stop
Claude / Codex
Built
Reviewed, tested, committed, pushed, and written up as
a GitHub issue. Never deployed
Michael
Shipped
Deployed or accepted by a human, issue closed. A
killed state is reachable from anywhere and records
why
Behind the board is a single JSON file, and exactly one piece
of code is allowed to write to it. That code locks the file,
re-reads it, bumps a version number, writes, and commits,
because several sessions run at once and any of them might
reach for the board at the same moment. There's no way to just
set an idea's stage. The only path is the move command, and
when it refuses, it tells you what stage the idea is in and
what would advance it. A stage has to be earned. An idea can't
become shaped without a brief, planned without a plan file,
reviewed without a verdict, or built without a GitHub issue,
so the board can't show progress that didn't happen. The moves
only I can make are queue, ship, and kill, plus three that
need a written reason: sending a plan back, resetting a build
that died, and reopening something that was killed.
The board went live on August 22. In the 23 days since, 74
ideas have gone through it, 62 of them for Haunts.
Thirty-eight are shipped, ten were killed with the reason on
record, and seven are built and waiting on the next app store
build. The median idea takes twelve and a half hours from
inbox to shipped. Across 45 build runs, the median time from
queued to a pushed branch is thirty minutes, and the longest
was just under three and a half hours. Twenty-five of the
ideas that made it to built or shipped were rated high effort.
This isn't a board for typo fixes.
The Board in 23 Days
74 ideas through the board
62 for Haunts
Shipped ·
38
Built, awaiting
store build · 7
Still in flight
· 19
Killed, reason on
record · 10
12.5h
Median idea, inbox to shipped
30min
Median build, queued to pushed
25
High-effort ideas built or shipped
Unattended Work Has Written Stops
A build runs while I'm doing something else. That's only safe
because the reasons it has to stop are written down as tests,
so halting never rests on the AI's judgment. There are four.
Any production action beyond the routine ones. Any file the
plan didn't name. A test suite that was already failing when
the work started, or a serious finding it can't fix inside the
plan. And any database change the plan didn't expect. When one
of those hits, the session writes why on the GitHub issue,
puts the idea back in the queue, and stops. A build also never
deploys. It ends at push, every time.
And every session, watched or not, ends by filing a GitHub
issue that records what was asked, what changed, and where the
files are. There are 296 of those across the five
repositories, the paper trail for six months of work done by
agents that don't remember yesterday.
One Afternoon on the Board
One Idea, Start to Push
17:03
Inbox
Fix the findings from a fresh mobile-app audit
17:24
Shaped
Codex reads the code and writes the brief
17:51
Planned
Twelve tasks, each testable, across 123 places in the
app
18:25
Reviewed twice
Codex and Claude, each reading the source. Fourteen
findings folded in, one dropped
18:29
Queued
Michael gives the go
↻ Two stops, scope widened twice
18:32
Build starts
In its own copy of the code
~18:47
Stops on an unnamed file
The right fix needs a file the plan didn't name.
Scope widened, and it stops again
20:04
Pushed, every check green
2,898 node · 776 Jest · 482 component
· typecheck · lint. Still not deployed
September 14 shows the whole thing in one idea. At 17:03 a
card landed in the inbox: fix the findings from a fresh audit
of the mobile app. Codex shaped it by 17:24 and had a plan by
17:51, twelve tasks, each testable on its own, with a list of
the 123 places in the app the fixes would touch. By 18:25 the
plan had been reviewed twice, once by Codex and once by
Claude, each reading the source on its own. Fourteen real
findings were folded in and one worry about a deadlock was
dropped because it didn't hold up. I queued it at 18:29. The
build started at 18:32 in its own copy of the code and stopped
fifteen minutes later, because the right fix needed a file the
plan hadn't named. It wrote that on the issue and handed the
card back to me. I widened the scope, it hit the same kind of
stop on a different file, I widened it again, and at 20:04 the
branch was pushed with every check green: 2,898 node tests,
776 Jest tests, 482 mounted-component tests, typecheck, and
lint.
Three hours from idea to a reviewed, tested, pushed branch,
with two decisions from me in the middle. It still isn't
deployed, because deploying isn't something the pipeline is
allowed to do.