Building Kalendar, Part 1: The Discipline Is the Story
I am building a real product mostly with an AI coding agent, and putting an unusual amount of process in front of it. What the spec-driven, agentic SDLC actually is, what it costs (226,000 words of docs and counting), and where it broke down.
Most “I built an app with AI” stories are about speed. This one is about restraint.
Kalendar is a real product, a SaaS platform for Catholic parish ministry scheduling, and I am building it largely with an AI coding agent. The interesting part isn’t that an agent writes the code. It’s how much process I put in front of the agent before it writes a line. One number captures it: the first line of feature code landed thirteen days into the project, behind roughly 41,000 words of specs, designs, and decisions, and two-thirds of every architectural decision the project has since made. This is the first post in a series that takes that process apart. I want to start with the whole shape of it: what’s here, what it costs, and where it broke down. Later posts go one level down into each piece.
What’s here
Kalendar is built on a spec-driven development system designed for human and agent contributors alike. One rule sits at the center of it and governs everything: one owner per field. No fact is authored in two places.
The binding text lives in version-controlled Markdown, under the same pull-request change control as the code. Before the agent implements anything, a capability walks a fixed pipeline of artifacts, each with a defined owner:
- A Spec: the behavioral contract, and the only normative artifact. What the system must do, observable from outside the boundary.
- A Solution Design: the epic-level architecture that frames the specs, owned by a tech-lead role.
- An SDD (software design document): how one spec gets realized inside that frame.
- A UX Design for anything with a screen, explored as runnable components and approved before it is built.
- A Test Plan: every acceptance criterion mapped to a named, observable verification.
- A task file: the work breakdown the agent actually implements from, then discards.
Only then does code get written.
Above all of that sit steering documents (product, tech, structure) that every task reads first, a set of immutable decision records for cross-cutting choices, and a requirements traceability matrix that a CI linter regenerates on every change and that no human is allowed to hand-edit. Traceability runs from requirement to spec to code to test, and the build fails if a thread is broken.
The agents are not one assistant. They are a set of roles, each with its own prompt: a product owner, a spec author, a tech lead, a task generator, a reviewer, and a completeness checker. Quality is enforced in two tiers. A mechanical tier, written in Python, hard-fails on missing sections or broken traceability. A judgment tier, a reviewer subagent, asks the questions a linter cannot: is this statement actually observable, and does this design truly realize the spec.
If that sounds like a lot of machinery for a product one person is building, it is. That is the point. It is also the cost.
What it costs
Here is the honest ledger, straight out of the repo:
- More than 226,000 words of documentation, across 103 Markdown files.
- 24 architecture decision records.
- 16 specs, 6 solution designs, 10 test plans, 11 task breakdowns.
- 216 files of application code, across three domains actually built out, plus shared plumbing.
Read that again. There is roughly a novel and a half of governing prose sitting in front of a handful of shipped domains. Five more domains are fully specified with zero lines of code behind them so far. The specification pipeline runs faster than the build, which means at any given moment there is more decided than there is done.
None of this appeared late. Thirteen days into the project, before the first line of feature code, 41,000 of those words already existed, along with sixteen of the twenty-four architecture decisions. The design has outrun the build since the very first week.
That is a real cost, and I want to be honest about it in three parts.
The first is upfront time. Every capability pays a tax before any code exists: spec, solution, design, test plan, tasks. For a throwaway prototype that would be absurd. For a product a parish is going to run its Sunday on, it is the price of not guessing.
I will be honest about how this felt. The delay in seeing a working product was frustrating at first. I am used to the reassurance of something running on screen early, and this approach withholds it. But the delay is the point. This was never about speed. It was about discipline, specifically the discipline to follow all the ideal software engineering practices that, as a human doing the work myself, I have always quietly rejected. The spec I would have skipped. The test plan I would have deferred. The decision record I would have kept in my head. The difference now is that I no longer have to summon the willpower to do them. I asked the agent to follow them, and it did, every time, without getting tired or cutting the corner I always cut.
The second is a discipline tax on me. The system only works if I actually hold to it. The moment I let the agent skip the spec and just build the thing, traceability breaks and the whole apparatus starts to lie. The process does not enforce itself. I do.
The third is the risk of decided-but-not-done. A spec written months before its code can be quietly wrong by the time anyone implements it. Runway is not the same as progress.
So was it worth it? Yes, with an asterisk. This has been the clearest proof I have seen that disciplined software delivery can come from an AI-developed solution: not just a quick prototype, but the specs, decisions, and traceability that make software last. That alone made it worth doing.
The miss was in where I put the human. I designed a process that leans on me to advance every stage and approve every gate. That was intentional, but it makes me the bottleneck, and in future projects I have already started moving that line, changing where and how a human needs to be in the loop rather than gating every single step.
And here is the part that reframes the whole cost. A majority of the documentation this process produced, I do not read. It was never really written for me. It is written for the agent, so it can hold context across sessions that it would otherwise lose. Those 226,000 words are less a manual for humans than a memory for the machine. Once you see it that way, the question stops being “why so much documentation” and becomes “what does the agent need to remember to do this well.”
Where it broke down
No process survives contact with a real build unchanged, and this one didn’t. The repo keeps the scars, and they are the most useful part of it.
I reversed the platform, on the record. ADR-002 committed the app to AWS Amplify Gen 2 with Cognito. It looked right on paper. The signal that it wasn’t came during implementation: the wrong things were hard. Amplify pushed an architectural shape I had not clocked when I chose it, and work that should have been simple kept fighting me. That friction was the tell. When the wrong things are hard, the decision is usually wrong. So six decisions later, ADR-008 reversed the platform to SST v3 on OpenNext, keeping only Cognito, and the deployment-process record (ADR-005) was superseded by ADR-009 in the same move.
Here is the part I did not expect: the pivot was trivial. Because the behavior lived in specs and the architecture lived in decision records, swapping the platform underneath was a mechanical change, not a rewrite. The process did not stop me from making the wrong call. What it did was make the wrong call cheap to undo, a numbered decision with its rationale on the record instead of a silent rewrite a later contributor would have had to reverse-engineer.
The methodology was being built alongside the product. Several of those decision records are about the process itself: adding a test-plan artifact, adding a UX design gate, deciding how epic-level specs ratify. I was not following a finished development lifecycle. I was designing one while shipping against it, which means some early work was done under rules that later changed.
Here is a concrete one. My first cut of the process would not let work advance until things passed tests. That sounds rigorous, but it was the wrong gate. Requiring green tests that early forced a tremendous amount of scaffolding just to satisfy the rule, before the implementation it was meant to test even existed. The fix was to get precise about what the gate actually is. I did not need passing tests at that point. I needed a test plan that covered every acceptance criterion, with the tests themselves built during implementation, against that plan. The intent had always been exactly that. My initial lifecycle just was not precise enough in its language to say so, so the process enforced the letter instead of the meaning. Getting the wording right became its own decision record (ADR-015), and reworking the specs already written to match was real work. It is also exactly the kind of work that only surfaces once you are building against your own process.
The name changed underneath the code. The internal packages are still scoped under an old codename “for historical reasons.” The product was renamed to Kalendar after the skeleton was laid. A small thing, but a visible seam: the artifacts outran the identity.
The spec got ahead of the code. Three domains built, five specified and empty. That is either healthy runway or over-investment I will regret, and I genuinely go back and forth on which.
Why carry the weight
So why haul all of this around for something an agent could have thrown together in a weekend?
Because the goal was never a weekend prototype. Kalendar exists to take the mechanical burden of coordination off parish volunteers, so their attention goes to the ministry and not the logistics. A tool people build their week around has to be trustworthy, and trustworthy is not something you can vibe-code into existence. The discipline is what lets an agent move fast without the output quietly drifting away from what was actually asked for.
The tools are new. The discipline is old. Specs, traceability, decision records, and review are the same practices that made software durable long before an agent could type. What has changed is that they are now the interface between a human’s intent and a machine’s speed. Get them right and the agent is leverage. Skip them and you have a very fast way to build the wrong thing.
Next in the series, I will go one level down, into the piece this all rests on: why the docs are the contract and the code is just the fulfillment.
Have a project in mind?
Let's talk through the path from idea to production.