Project
From Scattered Markdown to a Single /specs Directory
For a long time my specs lived everywhere and nowhere. A design decision in a README here, a half-finished plan in a Notion page there, an architecture sketch buried in a pull request description that nobody would ever read again. Each document made sense the day I wrote it. Together they made no sense at all.
The pattern was always the same. I would start a feature with good intentions, write a markdown file describing what I wanted, and then watch that file drift out of sync with the code within a week. By the time the feature shipped, the spec was a fossil—accurate about a world that no longer existed. I kept blaming my discipline. The real problem was that I had no single place where the truth about a project was supposed to live.
So I’m changing the way I work. Everything that describes a system—what it is,
why it exists, what’s built, what’s next, and the bigger bets I’m still
arguing with myself about—now goes into one directory: /specs.
Why one directory
The decision to collapse everything into a single folder sounds almost too simple to matter. It matters because location is a forcing function. When there is exactly one place a spec can be, there is no ambiguity about where to look, where to write, or what is authoritative. The directory becomes the index of the project’s intent, and the code becomes the implementation of that intent rather than the only record of it.
It also changes how I work with Claude Code. When the entire mental model of a
system sits in one navigable tree, I can point an agent at /specs and trust
that it has the full context—not scattered fragments it has to reconstruct from
commit history. The directory is as much for the agent as it is for me. We read
the same source of truth.
What lives inside
I’ve settled on four kinds of documents, each answering a different question.
Architecture answers how does this hang together. It describes the system as it actually is: the services, the data model, the boundaries, the trade-offs I committed to and why. This is the document I reach for when I’ve been away from a project for a month and need to reload the whole thing into my head in ten minutes.
The feature directory answers what exists and what state is it in. It’s a catalogue—one entry per feature, each linking to its own deeper spec. Think of it as the table of contents for the product’s capabilities, kept honest by the fact that anything not listed here effectively doesn’t exist.
The roadmap answers what order are we building this in. Not vague quarterly themes, but a concrete sequence of implementation: what’s shipped, what’s in flight, what’s blocked, and what’s deliberately deferred. It’s the difference between a wish list and a plan.
RFCs answer what are we still deciding. When a choice is large enough that I want to think it through in the open—a new abstraction, a migration, a dependency I’ll regret if I’m wrong—it gets an RFC. Most of them are short. The point isn’t ceremony; it’s leaving a trail of reasoning so that future-me, or an agent acting on my behalf, can understand not just what was decided but why the alternatives were rejected.
Borrowing from how the Claude team writes specs
What pushed me over the edge was reading the Claude Code team’s post, The Unreasonable Effectiveness of HTML. The headline argument is that markdown has quietly become a bottleneck: it’s hard to read a markdown file past a hundred lines, and as agents get better at producing rich output, plain text starts to feel like a cage. The team makes the case for asking Claude to emit HTML instead—higher information density, real visual structure, diagrams, color, and the ability to share something that’s actually pleasant to look at.
That reframed specs for me. A spec isn’t a document you file away; it’s an
interface to a system’s intent, and interfaces should be legible. So while the
canonical source in /specs stays as markdown—diffable, reviewable, friendly to
version control and to agents—the rendered view doesn’t have to be a wall of
text. I can have Claude Code turn the architecture and roadmap into a single
HTML artifact: an interactive overview where features link to their specs, the
roadmap renders as a timeline, and the whole thing is something I’d genuinely
send to a collaborator.
The split is the whole trick. Markdown for the source of truth, HTML for the human-facing view, both generated from the same directory. The team’s insight wasn’t “stop writing markdown.” It was “stop making humans read the raw thing when the agent can render something better.”
Preview deployments make specs real
A spec that renders to HTML wants to be seen, and the fastest way to kill the habit is to make viewing it a chore. So previews are part of the workflow, not an afterthought.
For anything with a backend—or when I want ephemeral, per-branch environments that mirror production—I lean on Coolify. It’s self-hostable, it gives me preview deployments tied to branches, and it keeps the whole thing on infrastructure I control. Push a branch, get a URL, look at the running thing next to its spec.
For a static web app, the rendered specs themselves, or a small artifact that
only needs an edge function or two, I reach for Cloudflare Pages + Workers
instead. Pages handles the static build and global distribution; a Worker covers
the bits of dynamic behavior that would otherwise force me into a heavier stack.
It’s cheap, it’s fast, and for a rendered /specs site it’s frankly overkill in
the best way.
The rule I’m trying to hold to: every spec should be one command away from something I can open in a browser. The moment a plan becomes a link, it stops being a document I have to remember to read and becomes a place I actually go.
What I’m hoping changes
I’m not pretending this is a finished system—it’s a project, and the roadmap for
the roadmap is itself in /specs. But the early signal is good. When the truth
about a system has one home, the drift slows. When the rendered view is worth
looking at, I look at it. And when an agent and I share the same source of
intent, the collaboration stops feeling like dictation and starts feeling like
two readers of the same map.
The old way wasn’t a discipline problem. It was a topology problem—too many places for the truth to hide. One directory, four kinds of documents, rendered to something worth reading, deployed somewhere I can reach. That’s the whole transformation. We’ll see how it survives contact with the next messy feature.