<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: giboulz</title>
    <description>The latest articles on DEV Community by giboulz (@giboulz).</description>
    <link>https://dev.to/giboulz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4042700%2Fb89de2e7-0313-413a-87a6-a7ed299d25cf.jpg</url>
      <title>DEV Community: giboulz</title>
      <link>https://dev.to/giboulz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/giboulz"/>
    <language>en</language>
    <item>
      <title>I ran 3 months of spec-driven development without ever reading the code</title>
      <dc:creator>giboulz</dc:creator>
      <pubDate>Wed, 22 Jul 2026 21:28:42 +0000</pubDate>
      <link>https://dev.to/giboulz/i-ran-3-months-of-spec-driven-development-without-ever-reading-the-code-1nbc</link>
      <guid>https://dev.to/giboulz/i-ran-3-months-of-spec-driven-development-without-ever-reading-the-code-1nbc</guid>
      <description>&lt;p&gt;I'm a scrum master. I was a developer ten years ago. I have enough background to&lt;br&gt;
discuss design and trade-offs with an LLM — but three months ago I made a&lt;br&gt;
deliberate bet on my solo project: &lt;strong&gt;I would never read the code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The specs define the tests. The tests control the code. The code is a black&lt;br&gt;
box.&lt;/p&gt;

&lt;p&gt;I'm not claiming this is what everyone should do. But it's &lt;em&gt;my&lt;/em&gt; bet, and it&lt;br&gt;
forced a system into existence: when nobody reads the code, the &lt;strong&gt;process&lt;/strong&gt; has&lt;br&gt;
to carry the trust that a code-reading human normally provides. I've just&lt;br&gt;
published that system as a reference implementation:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://github.com/giboulz/backlog-as-data" rel="noopener noreferrer"&gt;backlog-as-data&lt;/a&gt;&lt;/strong&gt; — the full&lt;br&gt;
writeup, the Claude Code skills translated to English, and the CLI source,&lt;br&gt;
verbatim from my daily setup.&lt;/p&gt;

&lt;p&gt;Here's the short version.&lt;/p&gt;
&lt;h2&gt;
  
  
  The backlog is git data, not a document
&lt;/h2&gt;

&lt;p&gt;Most agent task-management tools store tasks in a dedicated place — a&lt;br&gt;
&lt;code&gt;tasks.json&lt;/code&gt;, a database, a &lt;code&gt;backlog/&lt;/code&gt; folder. My bet is different: &lt;strong&gt;the&lt;br&gt;
backlog &lt;em&gt;is&lt;/em&gt; the YAML frontmatter of my spec files.&lt;/strong&gt; One file per ticket,&lt;br&gt;
and the ticket's status is a &lt;strong&gt;field&lt;/strong&gt; — never a location in a document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PARSE-07&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Tolerate CRLF in decklist import&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ticket&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;todo&lt;/span&gt;
&lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;should&lt;/span&gt;
&lt;span class="na"&gt;exec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonnet&lt;/span&gt;
  &lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;think&lt;/span&gt;
  &lt;span class="na"&gt;review&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;light&lt;/span&gt;
  &lt;span class="na"&gt;matured&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-07-22&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# PARSE-07 — Tolerate CRLF in decklist import&lt;/span&gt;

The spec body: design, contracts, test cases. The ticket file IS the spec.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything below the frontmatter is the spec — written by the LLM, after it&lt;br&gt;
has challenged the need I expressed in conversation. The frontmatter is data —&lt;br&gt;
owned by a small CLI, mutated only through it. Same file, so they can never&lt;br&gt;
drift apart.&lt;/p&gt;

&lt;p&gt;Why it matters: "move it to Done" is not an operation. LLMs (and humans)&lt;br&gt;
mangle documents when a state change means relocating text. Making status a&lt;br&gt;
field makes every transition a one-line, idempotent, testable mutation. The&lt;br&gt;
board I look at (a small web page on my server, with GitHub deep links to each&lt;br&gt;
spec) and the readable markdown view are &lt;strong&gt;generated projections&lt;/strong&gt;, locked by&lt;br&gt;
a do-not-edit sentinel and covered by a coherence test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maturation: decide model, effort and review depth per ticket — as data
&lt;/h2&gt;

&lt;p&gt;Committing to a ticket and deciding &lt;em&gt;how hard to think about it&lt;/em&gt; are separate&lt;br&gt;
acts. Before any agent runs, a ticket gets &lt;strong&gt;matured&lt;/strong&gt; with a triplet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;model&lt;/code&gt; — which model implements it (&lt;code&gt;haiku&lt;/code&gt; → &lt;code&gt;fable&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;effort&lt;/code&gt; — reasoning depth injected into the prompt&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;review&lt;/code&gt; — the review gate dosage: &lt;code&gt;none&lt;/code&gt;, &lt;code&gt;light&lt;/code&gt; (1 reviewer), &lt;code&gt;deep&lt;/code&gt; (3)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A trivial rename gets &lt;code&gt;haiku / none / none&lt;/code&gt;. An irreversible data migration&lt;br&gt;
gets the most capable model, maximum reasoning, three reviewers. The decision&lt;br&gt;
is versioned with the ticket and auditable months later (&lt;code&gt;matured: &amp;lt;date&amp;gt;&lt;/code&gt;).&lt;br&gt;
And the implementer sub-agent runs &lt;em&gt;exactly&lt;/em&gt; the matured model — its report&lt;br&gt;
must open with &lt;code&gt;Model used: …&lt;/code&gt; so the decision is verifiable after the fact.&lt;/p&gt;

&lt;p&gt;This is lean thinking applied to agent budget: pay for defect detection in&lt;br&gt;
proportion to the cost of a defect slipping through.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lifecycle is applied by hooks, not by anyone's memory
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;todo → wip → merged → shipped&lt;/code&gt; is set by hooks attached to my workflow&lt;br&gt;
commands — launch sets &lt;code&gt;wip&lt;/code&gt;, integration sets &lt;code&gt;merged&lt;/code&gt; (only for tickets&lt;br&gt;
whose &lt;code&gt;feat(TICKET-ID):&lt;/code&gt; commit is &lt;em&gt;actually on the branch&lt;/em&gt;), deploy sets&lt;br&gt;
&lt;code&gt;shipped&lt;/code&gt;. Nobody — human or agent — moves the back half of the lifecycle by&lt;br&gt;
hand. The hooks always exit 0 (lifecycle automation must never block a&lt;br&gt;
delivery) and commit surgically (a shared main checkout with 10+ parallel&lt;br&gt;
worktrees taught me that &lt;code&gt;git add specs/&lt;/code&gt; sweeps up a neighbor session's&lt;br&gt;
work — lesson learned the hard way, with a date on it).&lt;/p&gt;

&lt;h2&gt;
  
  
  The review gate: reviewers who know nothing
&lt;/h2&gt;

&lt;p&gt;This is the part I haven't seen elsewhere. When the implementer sub-agent&lt;br&gt;
finishes (in its own isolated git worktree), the orchestrator spawns&lt;br&gt;
&lt;strong&gt;fresh-context reviewers&lt;/strong&gt;: they get the ticket id, the spec path, the&lt;br&gt;
worktree, the commit SHA, and four review axes. &lt;em&gt;Nothing else.&lt;/em&gt; No summary of&lt;br&gt;
what the implementer did, no hints of where to look. Contaminating a&lt;br&gt;
reviewer's context is the main vector for confirmation bias.&lt;/p&gt;

&lt;p&gt;Three details that took incidents to learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The evidence of review is produced by the orchestrator, never by the
entity it audits.&lt;/strong&gt; The implementer doesn't know the dosage, never sees the
reviewer prompt, and cannot attest to anything about the review. The SHA is
read from git programmatically (a hand-transcribed SHA once arrived with 39
characters), and &lt;code&gt;git status&lt;/code&gt; is checked before and after the review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Findings have exactly two exits&lt;/strong&gt;: fixed, or escalated with justification
(spec is wrong / pre-existing debt / fix breaks a green test). "Not a big
deal" is not a disposition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reviewers report findings only — no praise.&lt;/strong&gt; A report that says
"everything else conforms" manufactures false confidence. It once
accompanied a report that declared conformant the very decisions it was
missing a defect in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Does it work? The day before publishing, I ran the gate on the published repo&lt;br&gt;
itself: a fresh reviewer compared my English translations against the French&lt;br&gt;
originals and raised 3 findings — including a mistranslated counter that would&lt;br&gt;
have silently corrupted the review register of anyone following the English&lt;br&gt;
version. The gate paid for itself on its first public outing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the human actually does
&lt;/h2&gt;

&lt;p&gt;My three touchpoints per ticket are all decisions, never mechanics: agreeing&lt;br&gt;
on the need (in conversation — the LLM challenges me, then writes the spec),&lt;br&gt;
saying "mature it and run it" (with the review dosage), and deciding to&lt;br&gt;
deploy. Everything in between — the CLI calls, the spec writing, the agent&lt;br&gt;
orchestration, the integration — is the agent's job. I never type a backlog&lt;br&gt;
command. The CLI is agent-facing: determinism comes from the agent having no&lt;br&gt;
hand-editing path, not from me doing the bookkeeping.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm &lt;em&gt;not&lt;/em&gt; claiming
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;That you should stop reading code. This is my bet, on my solo project, with
my risk profile.&lt;/li&gt;
&lt;li&gt;That this is a product. It's a reference implementation extracted from a
working setup — read it, steal the ideas, adapt the pieces. The
&lt;a href="https://github.com/giboulz/backlog-as-data" rel="noopener noreferrer"&gt;README&lt;/a&gt; has a section on
exactly which pieces transplant well.&lt;/li&gt;
&lt;li&gt;That the system is finished. Its biggest open problem is honest in the
README: every rule in it came from an incident retro that &lt;em&gt;I&lt;/em&gt; ran by habit —
the skill doesn't yet trigger its own improvement loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're running coding agents daily and your backlog is still a markdown&lt;br&gt;
to-do list that gets mangled every time an agent "moves something to Done" —&lt;br&gt;
the data model alone might be worth the read:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://github.com/giboulz/backlog-as-data" rel="noopener noreferrer"&gt;github.com/giboulz/backlog-as-data&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Happy to answer anything in the comments — including whether the&lt;br&gt;
never-read-the-code bet has burned me yet.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agile</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
