GOne to Two

Chapter 8: The Solo Builder's SDLC

7 min readThis chapter is still being written

You‘ve read the codebase. Audited the foundation. Made the hard calls about what stays and what gets rebuilt. You have a shared understanding of your product that’s more honest than anything you had at the end of zero-to-one. You know where the bodies are.

Now: how do you stop making new ones?

This chapter is about process. I know. The word makes builders flinch. It makes me flinch. But I‘m not talking about Agile ceremonies or sprint planning or story points or any of that theater. I’m talking about a minimal, practical workflow that keeps you from recreating the exact chaos you just spent weeks cleaning up.

At Apex, I had no process for the first several weeks. Here‘s what that looked like: 1,621 commits in 54 days. A fix-to-feature ratio north of 3:1. Four concurrent Claude Code tabs stepping on each other’s commits. Prototypes that accidentally became customer promises. I was moving incredibly fast. I was also moving in circles.

What I learned, painfully, is that every practice that saved me boiled down to two layers: a principle that‘s true regardless of what tools you use, and a practice that implements it with today’s tools. The tools will change. The principles won‘t. I’m going to be explicit about separating those two layers throughout this chapter, because the moment a better tool comes along — and it will — you should be able to swap the practice without losing the principle.

The Pause

The Principle: The act of writing down what you're about to do, before you do it, creates the pause that AI-speed building has eliminated.

This is the thing AI took away from us that we didn‘t notice was gone. When you had to write code by hand, the slowness of typing was itself a form of thinking time. You’d start implementing something and halfway through a function you'd realize the approach was wrong. That friction was a feature. AI-assisted development removed the friction and the thinking went with it.

The fix is to reintroduce a deliberate pause between intent and action. Not a long one. Thirty seconds. Enough to write down what you're about to do and why. Enough to catch yourself before you prototype something that accidentally becomes a customer promise by morning.

The Practice: GitHub issues.

My friend Scott Graves introduced me to this. Before you write any code — any code — create a GitHub issue describing what you're about to do and why. No exceptions. It sounds like overhead. It takes thirty seconds. And it solves four problems at once.

I can hear the pushback: “I tried tracking issues and stopped after three days because the overhead killed my flow state.” The flow state you're protecting is the same one that produced 1,621 commits in 54 days with a 3:1 fix-to-feature ratio. What issues actually interrupt is the dopamine loop of going straight from idea to code — and that loop is precisely the thing that needs interrupting.

Issues solve four problems at once. The impulse problem: a beat of pause between “what if” and “let me just.” The memory problem: you cannot remember what you did last Tuesday, and issues are external memory. The prioritization problem: backlogs can be prioritized, feelings can‘t. And the lone wolf problem: your co-founder can see what you’re working on without asking.

After adopting issues-first at Apex, I went from zero to two hundred issues in less than two weeks.

GitHub issues are today‘s tool. Tomorrow it might be something else — a purpose-built AI task tracker, a voice-activated backlog, who knows. What won’t change is the principle: write it down before you build it. The medium doesn't matter. The pause does.

Isolation

The Principle: Every unit of work deserves its own isolated context. When you let work streams bleed into each other, you multiply the cost of every mistake.

The Practice: One agent, one issue, one branch.

Each Claude Code session picks up exactly one issue and works on a dedicated branch. No concurrent agents working in overlapping areas of the code. At Apex I had four or five tabs open, agents tripping over each other, writing to the same files, creating merge conflicts I'd untangle at midnight. The fix is simple: isolation.

A caveat: parallelism works when the agents are touching completely different areas of the codebase. Two agents — one refactoring the billing module, one adding a feature to the dashboard — can run safely if they don‘t share files. The rule isn’t “never run two agents.” It's “never let two agents write to the same territory.” At Apex the problem was that everything touched the config system, so no area was truly isolated. Know your dependency graph before you parallelize.

This maps to a deeper truth about how AI agents work. An agent is only as good as its context. When you give one agent five different tasks, it loses the thread on all of them. When you give it one task with a clear description — the issue you just wrote — it performs dramatically better. Isolation isn‘t just about avoiding merge conflicts. It’s about giving the AI the focus that produces good work.

Small issues, small branches. If an issue is going to take more than a day, it‘s too big. Break it down. I resisted this at first — felt like busywork. It’s not. Small issues complete. Large issues drift.

The Deliberate Merge

The Principle: There should be a clear, conscious boundary between “work in progress” and “this is real.” Crossing that boundary should require a deliberate act, not a side effect.

The Practice: Commit freely on the branch. Merge to main deliberately.

Let the AI commit as often as it wants on its branch. But merging to main is a deliberate act. You‘re saying “this is ready.” Mean it. Close the loop: branch merges, issue closes. There’s a trail from intent to implementation to completion. When you look back in a month, you can reconstruct why every change was made.

Skip formal PRs for solo work. A PR to yourself is a performance with no audience. The value of a pull request is the second pair of eyes. When you‘re solo, those eyes don’t exist. The discipline lives in the issue, the branch, and the deliberate merge. When you add a second person — even a part-time contractor — add PRs immediately. Not before.

Commit Messages as Memory

The Principle: In an AI-generated codebase, the commit message is often the only record of human intent.

This deserves its own section because almost nobody gets it right, and the cost is invisible until it's catastrophic.

When you write code by hand, the code itself carries traces of your thinking. Variable names reflect your mental model. Comments explain your reasoning. The structure reveals the plan. When AI writes the code, all of that is gone. The AI doesn't have your intent — it has its interpretation of your prompt. The code it produces is clean, functional, and utterly silent about why it exists.

Commit messages are where that “why” lives now. Not the diff. Not the branch name. The commit message. “Fix bug” tells you nothing. “Resolve race condition in payment webhook handler — duplicate charges were hitting Stripe when webhook retried before first response completed” tells you everything. It tells you what the symptom was, where it lived, and what was actually happening. Six months from now, when something similar surfaces, that message is the difference between a thirty-minute fix and a three-day investigation.

The practice is simple: every commit message should answer “why this change?” not “what changed?” The diff already tells you what changed. The AI will happily generate commit messages for you, but left to its own devices it will describe the what. Train it — or train yourself — to insist on the why. At Apex, the commits where I enforced this discipline are the ones I can still navigate. The ones where I let the AI auto-message are archaeologically opaque.

The Daily Snapshot

The Principle: Regular reflection turns activity into progress. Without it, you confuse motion with direction.

The Practice: End of each day, ask the AI: “What did we do today? What issues did we close? What‘s still open? What should we prioritize tomorrow?” It’s a standup with yourself. Sounds silly. It's the most clarifying two minutes of the day.

The Readiness Contract

The Principle: Every feature exists on a spectrum from experiment to promise. The danger isn‘t building experiments — it’s accidentally selling them as promises.

This isn‘t just a labeling system. It’s a communication protocol between you and everyone who touches your product — co-founders, salespeople, customers. Every feature gets one of four labels:

Sketch — may disappear tomorrow. Not to be sold. Not to be shown to customers as a commitment.

Testing — in front of users for feedback. “We're exploring this” is the honest framing.

Solid — validated, being hardened. Can be sold with caveats about timeline.

Production — battle-tested, documented, monitored. It's a promise.

At Apex, issue #228 — “Sales enablement: document what‘s real vs roadmap” — was the moment we were forced to build this vocabulary retroactively, under pressure, because the visionary had sold things that were still sketches. Don’t wait for that crisis.

The labels might evolve. You might use different words, different tiers. What matters is the principle: everyone touching the product should know the difference between an experiment and a commitment, and that distinction should be explicit, not assumed.

The Maturity Curve

You don‘t need all of this on day one. During zero-to-one, no process is correct — speed is everything. When you enter one-to-two, start with issues-first, one agent per branch, commit message discipline, and daily snapshots. That’s day one. By week three or four, add the readiness contract, small issues, and deliberate merges. As you approach two, layer on the full pipeline — everything above, plus the CI/CD and review practices covered in Chapter 10.

You don't need the full pipeline on day one. You need the pause on day one. Everything else layers on as the stakes increase. And the stakes always increase.