Spec-driven development at a 100-person company: what actually stuck after we tried it

Tobias Werner

Tobias Werner

September 18, 2026

Spec-driven development at a 100-person company: what actually stuck after we tried it

We rolled out spec-driven development because the agents were writing code faster than our tickets could describe the work. The pitch was clean: write the spec, generate the implementation, review the diff against the spec, ship. We were about a hundred people — four product groups, a platform team, the usual constellation of Slack channels that believed they were the source of truth.

Six months later I can tell you what stuck. It is a shorter list than the all-hands slide. It is also the only list I would take to the next company.

What we thought we were buying

We thought we were buying alignment. A spec in the repo, next to the code, in a format a model could read and a human could argue with. We used a mix of Markdown ADRs, a home-grown “capability” template, and for two teams, TypeSpec for the HTTP edges. Product wrote the first draft. Engineering annotated. QA was supposed to turn acceptance into Playwright. Agents were supposed to fill the middle.

What we actually bought, in month one, was a second backlog. Specs that were novels. Specs that were three bullet points and a Figma link. Specs that were generated from Jira and then implemented by generating Jira back from the spec. The loop closed around our own fog.

The cultural tell: people started saying “the spec is stale” the way they used to say “the ticket is stale.” We had not changed the problem. We had renamed the artifact.

What actually stuck

Three practices survived contact with a real quarter. Everything else we quietly stopped enforcing.

1. Specs that name an invariant, not a UI tour

The specs that lived were one or two pages and they contained at least one sentence a test could fail. “Payouts in state LOCKED cannot change beneficiary.” “A user who is not in the tenant cannot appear in search, including after a display-name change.” “The export CSV matches the ledger rows for that period, or we page.”

The specs that died were walkthroughs. “User clicks Export, sees a modal, can choose columns.” An agent will implement that cheerfully and miss that finance needed a stable column order because their VLOOKUP is from 2019. We stopped asking product for screenplay specs. We asked for the sentence that, if false, is an incident.

I now refuse to review a generated PR against a spec that has no invariant. There is nothing to review against. There is only taste, and taste does not scale to a hundred people.

2. The spec lives in the pull request that first makes it true

We tried a Specs space in Notion. It became a museum. We tried a /docs/specs folder that anyone could edit on main. It became a wiki with git blame. What stuck: the spec is a file in the same PR as the first test that encodes it. Later PRs can amend it. If you change behavior without changing the spec, CI fails a little check that diffs the spec path listed in a manifest.

That check is dumb and I love it. It does not prove the spec is right. It proves someone had to look at the spec when they changed the behavior. At a hundred people, “someone had to look” is a lot of the game.

3. Agents get the spec as input, not as decoration

The teams that got value pasted the spec into the agent with the test file first, then asked for implementation. The teams that got sludge asked the agent to “write a spec for this ticket” and then “implement the spec.” That second pattern is how you launder a vague Jira into a confident markdown file into a confident wrong service.

We banned generated specs unless a human signed the invariant paragraph. I put my name on a few. I regretted one, which is the correct rate. If you never regret a spec, you are not writing invariants. You are writing aspirations.

Printed spec pages pinned beside a monitor showing a failing test

What we dropped, and why

Spec coverage as a KPI. We asked teams to report the percentage of stories with a spec. They wrote specs. The number went up. Escaped defects did not go down. We killed the metric. I will not bring it back. Measure the incidents that a spec should have prevented, if you must measure.

A company-wide template with eighteen headings. Platform loved it. Product hated it. The headings that mattered — context, invariant, out of scope, test idea — got buried under “success metrics” and “rollout comms.” The short template won. The long one is still in Confluence. I checked. Nobody has touched it in eleven weeks.

Generating the entire service from the spec. Fine for a greenfield CRUD that we did not care about. Mortal for the settlement service. The model does not know which stored procedure is load-bearing. We spent a sprint deleting a polite, well-typed parallel implementation. I will use generation for the mapper and the test names. I will not use it for the first cut of a money path.

QA owning the spec after the fact. That recreated the 2014 waterfall with better fonts. QA now reviews the invariant and adds the case we forgot. They do not become the documentation department.

The 100-person problems the blog posts skip

At ten people, spec-driven is a habit. At a hundred, it is a coordination protocol, and protocols get politics.

Platform wanted every spec to mention their new event bus. Product wanted no spec to mention infrastructure. We settled on: you may not add a dependency in a spec unless the implementation PR is allowed to add it. That sounds obvious. It stopped a class of “the spec says Kafka” arguments that were really “platform would like Kafka.”

Legal wanted specs for anything that touched personal data. Fair. They also wanted to approve the markdown. We gave them a label and a 48-hour SLA, and we put the PII fields in a table, not in prose. Prose is where lawyers and models both hallucinate. Tables are boring. Boring is good.

Two product groups specified the same “identity” concept differently. The agent, to its credit, implemented both. Users, to their credit, were confused. The thing that stuck was a shared glossary of twenty words in the repo — not a 200-page domain bible. Twenty words. If your company cannot agree on twenty words, spec-driven development will only help you generate the disagreement faster.

A meeting room wall with a short glossary and crossed-out process posters

What I would tell another 100-person shop

Do not roll this out as a transformation. Pick one team with a domain that already has a few sharp rules — billing, access, something with a regulator. Run the three practices for a quarter. If escaped defects on that team do not move, you do not have a spec problem. You have a test problem or a staffing problem.

Do not make “spec-driven” a synonym for “we use agents.” You can write invariants without a model. You can use a model without invariants. The second one is how you get a confident demo and a messy quarter.

Do not let the spec replace the conversation with the person who will be on-call. I still want a fifteen-minute walkthrough of the failure mode. The spec is the memory. The walkthrough is the transfer. We dropped the walkthrough in month two because we felt modern. We put it back after an incident that was, in hindsight, described in paragraph four of a spec nobody had read out loud.

Tooling: I do not care if you use Gherkin, a markdown template, TypeSpec, or a checklist. I care that the artifact is in git, that CI notices when behavior and artifact diverge, and that a human owns the invariant sentence. We used GitHub Actions and a small Go checker. You can use whatever. The checker is twenty minutes of work. The ownership is the project.

How we ran the weekly spec review without turning it into theater

We kept a thirty-minute review, once a week, for specs that were about to hit an agent. Not a readout of every file. Two specs, max. The author read the invariant out loud. Someone who was not the author tried to invent a case that still satisfied the sentence and broke the product. If nobody could, the spec was probably a slogan. If everybody could, we tightened the sentence before anyone opened Cursor.

I insisted the on-call for that service be in the room or on the thread. Their boredom was a signal. If they shrugged, the spec was not about a failure they feared. We were specifying the demo again.

This meeting is the one I would keep at a hundred people. It is cheap. It creates the shared memory the markdown file cannot. And it is the opposite of a transformation program: no coaches, no maturity model, no dashboard. Just the habit of saying the dangerous sentence where other people can hear it.

The honest scorecard

Stuck: invariant-first specs, spec-in-the-PR, agents consuming rather than inventing the spec, a tiny shared glossary, legal tables for PII.

Did not stick: coverage KPIs, the eighteen-heading template, generate-the-service theater, QA-as-after-the-fact-authors, Notion as source of truth.

Net: we ship a little slower on the first story of a new capability and a lot faster on the fifth, because the fifth has something to be wrong against. Agents made the fifth even faster, when the spec was good. They made the first story more dangerous, when the spec was a generated fog.

If you are a hundred people and you want this, steal the short list. Leave the religion. Spec-driven development is not a methodology you install. It is a habit of writing down the sentence that must remain true after the model has gone home. That sentence is what stuck. The rest was a slide.

More articles for you