[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"lab-entry-ship-with-claude-code":3},{"entry":4,"newer":23,"older":13},{"slug":5,"tag":6,"issueNumber":7,"publishedAt":8,"title":9,"excerpt":10,"readingTimeMinutes":11,"updatedAt":8,"bodyHtml":12,"cover":13,"videoUrl":13,"links":14,"stack":18},"ship-with-claude-code","Lesson",1,"2026-10-13T16:21:59.304547+00:00","How I ship with Claude Code: my spec-driven workflow","How I build this site with Claude Code: specs and tickets as GitHub issues, one ticket per session, and a stop at every decision that's mine to make, not the agent's.",4,"\u003Ch2>The problem\u003C\u002Fh2>\n\u003Cp>An AI coding agent works fast, and it fills every gap with a guess: a fact about me, a component prop, a change to the live database. On my own site, each of those guesses ends up in public. I wanted Claude Code to do most of the typing while every decision that matters stays with me.\u003C\u002Fp>\n\u003Ch2>What I built\u003C\u002Fh2>\n\u003Cp>A workflow made of two parts: rules that live in the repo, and a fixed order of skills that stops wherever a decision is mine. The skills come from Matt Pocock's skills collection. Everything below is how I built this site, including the Lab you're reading.\u003C\u002Fp>\n\u003Ch3>The rules live in the repo\u003C\u002Fh3>\n\u003Cp>Claude Code reads \u003Ccode>CLAUDE.md\u003C\u002Fcode> at the start of every session. Mine is short. It points to the documents that win when sources disagree: a project rules file, a facts file and a writing style guide. The workflow is one line of it:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\">\u003Ccode>**Workflow:** `\u002Fgrill-with-docs` → `\u002Fresearch` (if needed) → `\u002Fprototype` (UI questions) → `\u002Fto-spec` → `\u002Fto-tickets` → `\u002Fimplement` (one ticket per session) → `\u002Fcode-review`. Stop at every owner gate in `PROJECT-RULES.md` §3.\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>The facts file is the only source for anything about me: roles, dates, projects, numbers. If a fact isn't in it, the agent writes \u003Ccode>TBD\u003C\u002Fcode>. It doesn't guess.\u003C\u002Fp>\n\u003Ch3>The steps and where they stop\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>\u003Ccode>\u002Fgrill-with-docs\u003C\u002Fcode> questions me until a fuzzy plan turns into decisions. They're saved as architecture decision records (ADRs) and glossary terms.\u003C\u002Fli>\n\u003Cli>\u003Ccode>\u002Fresearch\u003C\u002Fcode> checks an outside fact against primary sources and saves a cited note, when a decision waits on one.\u003C\u002Fli>\n\u003Cli>\u003Ccode>\u002Fprototype\u003C\u002Fcode> builds throwaway variants on their own branch when a screen can't be settled by talking. I pick one, and the branch is never merged.\u003C\u002Fli>\n\u003Cli>\u003Ccode>\u002Fto-spec\u003C\u002Fcode> writes one spec as a GitHub issue. I approve it.\u003C\u002Fli>\n\u003Cli>\u003Ccode>\u002Fto-tickets\u003C\u002Fcode> splits the spec into tickets with dependencies, each sized for one session. I approve the list.\u003C\u002Fli>\n\u003Cli>\u003Ccode>\u002Fimplement\u003C\u002Fcode> builds one ticket in a new chat and makes one commit on the feature branch.\u003C\u002Fli>\n\u003Cli>\u003Ccode>\u002Fcode-review\u003C\u002Fcode> checks the changes against the repo's standards and against the spec, before I approve a merge.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Nothing is pushed, merged or deployed without my OK.\u003C\u002Fp>\n\u003Ch3>One ticket, one session\u003C\u002Fh3>\n\u003Cp>Each ticket says what to build, which documents it comes from, and how to check it's done. These acceptance criteria are from the ticket that built the Lab's RSS feed:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\">\u003Ccode>- [ ] Every fact traces to `brand-facts.md`; anything unknown is `TBD` and listed in the report.\n- [ ] Typecheck and lint pass.\n- [ ] `\u002Fcode-review` has run; findings fixed or recorded.\n- [ ] One commit on `feature\u002Flab`. No push, merge or deploy.\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Before it writes any code, Claude Code reads the ticket and asks every open question in one message, with its recommendation for each. I answer once, and it builds. At the end it reports what it couldn't match and what's still \u003Ccode>TBD\u003C\u002Fcode>. Anything only I can do, like a secret in the hosting dashboard or a check on the live site, goes into one launch checklist issue.\u003C\u002Fp>\n\u003Ch3>The database is production\u003C\u002Fh3>\n\u003Cp>The site's Supabase project is linked to the repo, and it's the live database. So the schema changes only through migration files, and Claude Code shows me a dry run before anything is applied:\u003C\u002Fp>\n\u003Cpre tabindex=\"0\">\u003Ccode class=\"language-bash\">npx supabase migration new &lt;name&gt;\nnpx supabase db push --dry-run\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>I run the real push myself. Claude Code reads the result, and it never writes test rows to production: pages that need data are checked against mock data.\u003C\u002Fp>\n\u003Ch2>What I learned\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Cstrong>One message of questions beats questions as they come up.\u003C\u002Fstrong> Every open question, each with a recommendation, in one message. I answer in one pass, and the work doesn't stop halfway through a ticket.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>A throwaway prototype is cheap to reject.\u003C\u002Fstrong> I rejected all four variants in the first homepage round and started the second round from reference sites I picked. Nothing had to be unpicked from the main branch.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Check the component library, not the model's memory.\u003C\u002Fstrong> The rules make Claude Code check every Nuxt UI component against the installed version. Building the Lab signup form, it found that the text input drops to 14px on wider screens unless it's set to \u003Ccode>fixed\u003C\u002Fcode>. The approved prototype had that bug.\u003C\u002Fli>\n\u003C\u002Fol>\n",null,[15],{"label":16,"url":17},"Matt Pocock's skills","https:\u002F\u002Fgithub.com\u002Fmattpocock\u002Fskills",[19,20,21,22],"Claude Code","GitHub Issues","Supabase","Nuxt UI",{"slug":24,"tag":25,"issueNumber":26,"publishedAt":27,"title":28},"double-opt-in-without-captcha","Build notes",2,"2026-10-13T18:34:10.191051+00:00","A double opt-in signup without a CAPTCHA"]