<?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: Sohail Ahmad</title>
    <description>The latest articles on DEV Community by Sohail Ahmad (@sohailrajput).</description>
    <link>https://dev.to/sohailrajput</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%2F247213%2F69372fbd-eaf7-48ce-bbd9-96769f8bd260.jpg</url>
      <title>DEV Community: Sohail Ahmad</title>
      <link>https://dev.to/sohailrajput</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sohailrajput"/>
    <language>en</language>
    <item>
      <title>Shipping AI-Generated Features as Stacked PRs: A Complete Spec Kit + gh stack Tutorial</title>
      <dc:creator>Sohail Ahmad</dc:creator>
      <pubDate>Thu, 10 Sep 2026 04:59:29 +0000</pubDate>
      <link>https://dev.to/sohailrajput/shipping-ai-generated-features-as-stacked-prs-a-complete-spec-kit-gh-stack-tutorial-gie</link>
      <guid>https://dev.to/sohailrajput/shipping-ai-generated-features-as-stacked-prs-a-complete-spec-kit-gh-stack-tutorial-gie</guid>
      <description>&lt;p&gt;&lt;em&gt;A step-by-step guide to pairing spec-driven development with stacked pull requests — from &lt;code&gt;specify init&lt;/code&gt; all the way to a fully merged feature.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this tutorial exists
&lt;/h2&gt;

&lt;p&gt;AI coding agents are fast. Dangerously fast. Point an agent at a feature request and ten minutes later you're staring at a pull request with 180 changed files. Nobody reviews that. It sits for days, goes stale, and gets merged with a &lt;code&gt;LGTM&lt;/code&gt; and a prayer.&lt;/p&gt;

&lt;p&gt;The fix is two tools working together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Spec Kit&lt;/strong&gt; (&lt;code&gt;specify&lt;/code&gt;) gives the agent &lt;em&gt;structure&lt;/em&gt; — a spec, a plan, a task list, and gates it must pass before writing code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;gh stack&lt;/code&gt;&lt;/strong&gt; gives the &lt;em&gt;output&lt;/em&gt; structure — instead of one monster PR, the agent ships a &lt;strong&gt;stack&lt;/strong&gt; of small PRs (each ≤ 100 files), each reviewable in minutes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tutorial walks through the entire lifecycle with a real example. By the end you'll have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ A working Spec Kit + &lt;code&gt;gh stack&lt;/code&gt; setup&lt;/li&gt;
&lt;li&gt;✅ A plan that is &lt;em&gt;literally&lt;/em&gt; a stack layout&lt;/li&gt;
&lt;li&gt;✅ An implement loop where &lt;code&gt;gh stack&lt;/code&gt; only fires &lt;strong&gt;after unit tests pass&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;✅ Three open PRs stacked on each other&lt;/li&gt;
&lt;li&gt;✅ A review/merge workflow that takes the stack from open → merged → cleaned up&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What we're building
&lt;/h2&gt;

&lt;p&gt;We're an e-commerce team. The business wants &lt;strong&gt;payments&lt;/strong&gt;: charge cards, refund, webhooks. Estimated scope: ~135 files. That's one unreviewable PR — or a clean 3-PR stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main ── 001-payments ── 001-payments-u2 ── 001-payments-u3
        PR #1            PR #2              PR #3
        Domain (~25f)    API (~40f)         Webhooks+UI (~70f)
        each ≤ 100 files — hard cap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One feature. One stack. Three small reviews. Let's go.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 0 — Prerequisites
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GitHub CLI ≥ 2.x&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gh --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Authenticated: &lt;code&gt;gh auth login&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uv (for Spec Kit)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uv --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Or use &lt;code&gt;pipx&lt;/code&gt;/&lt;code&gt;pip&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An AI agent&lt;/td&gt;
&lt;td&gt;&lt;code&gt;claude --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Works with &lt;code&gt;codex&lt;/code&gt;, &lt;code&gt;copilot&lt;/code&gt;, &lt;code&gt;gemini&lt;/code&gt;, &lt;code&gt;cursor-agent&lt;/code&gt;, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node/Python + test runner&lt;/td&gt;
&lt;td&gt;project-specific&lt;/td&gt;
&lt;td&gt;We use &lt;code&gt;npm run test:unit&lt;/code&gt; below — swap in yours&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Install the stack extension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh extension &lt;span class="nb"&gt;install &lt;/span&gt;hmarr/gh-stack
gh stack &lt;span class="nt"&gt;--help&lt;/span&gt;   &lt;span class="c"&gt;# should print submit / sync / checkout / view&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 1 — Project setup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fresh project with Claude Code as the agent&lt;/span&gt;
uvx &lt;span class="nt"&gt;--from&lt;/span&gt; git+https://github.com/github/spec-kit.git specify init payments-service &lt;span class="nt"&gt;--ai&lt;/span&gt; claude
&lt;span class="nb"&gt;cd &lt;/span&gt;payments-service

&lt;span class="c"&gt;# Existing repo instead?&lt;/span&gt;
&lt;span class="c"&gt;# uvx --from git+https://github.com/github/spec-kit.git specify init --here --ai claude&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spec Kit drops its templates into &lt;code&gt;.specify/&lt;/code&gt; and configures your agent's command slash-commands (&lt;code&gt;/speckit.*&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now create the &lt;strong&gt;cap-enforcement gate&lt;/strong&gt; — the script that makes the 100-file rule real rather than a suggestion the agent can ignore:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;scripts/check-stack-cap.sh&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# Hard cap: max changed files per stack unit. Usage:&lt;/span&gt;
&lt;span class="c"&gt;#   scripts/check-stack-cap.sh &amp;lt;parent-branch&amp;gt;   e.g. main, or the unit below&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;CAP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;STACK_FILE_CAP&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;100&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;PARENT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?Usage:&lt;span class="p"&gt; check-stack-cap.sh &amp;lt;parent-branch&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git merge-base &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PARENT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; HEAD&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; HEAD | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'/^$/d'&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Files changed vs '&lt;/span&gt;&lt;span class="nv"&gt;$PARENT&lt;/span&gt;&lt;span class="s2"&gt;': &lt;/span&gt;&lt;span class="nv"&gt;$COUNT&lt;/span&gt;&lt;span class="s2"&gt; / &lt;/span&gt;&lt;span class="nv"&gt;$CAP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt; COUNT &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; CAP &lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"❌ FILE CAP EXCEEDED — do NOT push or run gh stack. Split this unit."&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"✅ Within cap — safe to push and submit."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x scripts/check-stack-cap.sh
git add scripts/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"chore: stack file-cap gate"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔑 &lt;strong&gt;Key idea:&lt;/strong&gt; the gate runs &lt;em&gt;before&lt;/em&gt; anything touches GitHub. If tests are red or the cap is blown, &lt;code&gt;gh stack&lt;/code&gt; never runs. Bake this into your agent's rules in Part 2.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 2 — Teach the agent the contract
&lt;/h2&gt;

&lt;p&gt;Run the constitution command and paste this addendum (it becomes project law the agent reads on every task):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/speckit.constitution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add to the generated file:&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="gu"&gt;## Delivery — Stacked PRs (non-negotiable)&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; One feature = one gh stack of units U1..Un, implemented strictly in order.
&lt;span class="p"&gt;2.&lt;/span&gt; HARD CAP: each unit ≤ 100 changed files, verified by
   scripts/check-stack-cap.sh &lt;span class="nt"&gt;&amp;lt;parent-branch&amp;gt;&lt;/span&gt;. Exceeding it ⇒ split the unit.
&lt;span class="p"&gt;3.&lt;/span&gt; Unit sequence: implement → unit tests PASS → commit → cap check →
   git push -u → gh stack submit → create next unit branch.
&lt;span class="p"&gt;4.&lt;/span&gt; NEVER run gh stack with failing tests or a failed cap check.
&lt;span class="p"&gt;5.&lt;/span&gt; U1 branch = the spec-kit feature branch (parent: main).
   U(k) branch = &lt;span class="nt"&gt;&amp;lt;feature&amp;gt;&lt;/span&gt;-uk (parent: U(k-1)). No forward dependencies.
&lt;span class="p"&gt;6.&lt;/span&gt; Merge bottom-up. Run gh stack sync after every merge.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole contract. Everything below is this loop, repeated.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 3 — &lt;code&gt;/speckit.specify&lt;/code&gt; (and clarify)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/speckit.specify Build payments: card charge, refund, and webhook ingestion.
This branch is the bottom of a gh stack — spec docs ship in PR #1.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Spec Kit creates the branch and commits the spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⏺ Created branch 001-payments
⏺ Created specs/001-payments/spec.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That branch — &lt;code&gt;001-payments&lt;/code&gt; — is now &lt;strong&gt;unit U1, the bottom of your stack&lt;/strong&gt;. Add clarifications with &lt;code&gt;/speckit.clarify&lt;/code&gt; if the spec has open questions, then commit any changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 4 — &lt;code&gt;/speckit.plan&lt;/code&gt;: plan the feature &lt;em&gt;as&lt;/em&gt; a stack
&lt;/h2&gt;

&lt;p&gt;This is where the two tools fuse. Don't let the plan be prose — make it a &lt;strong&gt;stack layout&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/speckit.plan Use PostgreSQL + NestJS + Stripe SDK.

STACK CONSTRAINTS (mandatory):
- Organize implementation as stacked units U1..Un.
- U1 must build and test green alone; each U(k) depends only on U1..U(k-1).
- Each unit ≤ 100 changed files — estimate files per unit, split proactively.
- Add a "## Stack Layout" table: Unit | Branch | Purpose | Depends on | Est. files.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent writes back into &lt;code&gt;plan.md&lt;/code&gt;:&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="gu"&gt;## Stack Layout&lt;/span&gt;
| Unit | Branch             | Purpose                    | Depends on | Est. files |
|------|--------------------|----------------------------|------------|------------|
| U1   | 001-payments       | Domain model + migrations  | main       | ~25        |
| U2   | 001-payments-u2    | REST API + contract tests  | U1         | ~40        |
| U3   | 001-payments-u3    | Webhooks + admin UI        | U2         | ~70        |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 If any unit estimates &amp;gt; 100 files at this stage, the agent should split it &lt;em&gt;now&lt;/em&gt;, in the plan — not mid-implementation.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 5 — &lt;code&gt;/speckit.tasks&lt;/code&gt; + &lt;code&gt;/speckit.analyze&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Group every task under a unit, and give each unit an &lt;strong&gt;exit definition&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/speckit.tasks

STACK CONSTRAINTS (mandatory):
- Group tasks under "## Unit N" headings; each task belongs to exactly one unit.
- Per unit define: unit-test command and exit criteria:
  tests green + scripts/check-stack-cap.sh &amp;lt;parent&amp;gt; exit 0.
- Estimated files &amp;gt; 100 for any unit ⇒ split it before finalizing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resulting &lt;code&gt;tasks.md&lt;/code&gt; (excerpt):&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="gu"&gt;## Unit 1 — Domain Core (001-payments, parent: main)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] T001 Payment schema migration
&lt;span class="p"&gt;-&lt;/span&gt; [ ] T002 Payment aggregate + state machine
&lt;span class="p"&gt;-&lt;/span&gt; [ ] T003 Unit tests
&lt;span class="gs"&gt;**Exit:**&lt;/span&gt; &lt;span class="sb"&gt;`npm run test:unit`&lt;/span&gt; → commit → &lt;span class="sb"&gt;`scripts/check-stack-cap.sh main`&lt;/span&gt;
→ push → &lt;span class="sb"&gt;`gh stack submit`&lt;/span&gt; → checkout &lt;span class="sb"&gt;`001-payments-u2`&lt;/span&gt;

&lt;span class="gu"&gt;## Unit 2 — API (001-payments-u2, parent: 001-payments)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] T004 POST /payments endpoint
&lt;span class="p"&gt;-&lt;/span&gt; [ ] T005 GET /payments/:id
&lt;span class="p"&gt;-&lt;/span&gt; [ ] T006 Contract tests
&lt;span class="gs"&gt;**Exit:**&lt;/span&gt; same pattern, parent = &lt;span class="sb"&gt;`001-payments`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then sanity-check the structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/speckit.analyze
Also verify: every task maps to one unit; no gaps or forward deps in the
unit chain; no unit's file estimate exceeds 100.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 6 — &lt;code&gt;/speckit.implement&lt;/code&gt;: the unit loop
&lt;/h2&gt;

&lt;p&gt;This is the heart of the tutorial. Kick off:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/speckit.implement

EXECUTION RULES (mandatory):
- One unit at a time, in order U1..Un.
- Unit complete ONLY when: unit tests pass AND scripts/check-stack-cap.sh
  &amp;lt;parent&amp;gt; exits 0.
- Then: commit → push -u → gh stack submit → git checkout -b &amp;lt;next-unit&amp;gt;.
- Never run gh stack with red tests or a failed cap check.
- Cap exceeded mid-unit ⇒ stop, split remaining tasks into a new unit in
  tasks.md, finish the loop, continue.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔁 Unit 1
&lt;/h3&gt;

&lt;p&gt;The agent implements T001–T003. Then you (or the agent) run the loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run &lt;span class="nb"&gt;test&lt;/span&gt;:unit
&lt;span class="c"&gt;# ✔ 42 tests passing                          ← GATE 1: tests green&lt;/span&gt;

git add &lt;span class="nt"&gt;-A&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat(u1): payment domain model + migrations"&lt;/span&gt;

scripts/check-stack-cap.sh main
&lt;span class="c"&gt;# Files changed vs 'main': 25 / 100&lt;/span&gt;
&lt;span class="c"&gt;# ✅ Within cap — safe to push and submit.     ← GATE 2: cap green&lt;/span&gt;

git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin 001-payments
gh stack submit &lt;span class="nt"&gt;--draft&lt;/span&gt; &lt;span class="nt"&gt;--fill&lt;/span&gt;                ← NOW the stack &lt;span class="nb"&gt;command &lt;/span&gt;runs
&lt;span class="c"&gt;# ✔ Created https://github.com/acme/payments-service/pull/1&lt;/span&gt;

git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; 001-payments-u2               ← stack the next unit on top
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;PR #1 exists.&lt;/strong&gt; Both gates were green first — that's the discipline.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔁 Unit 2
&lt;/h3&gt;

&lt;p&gt;You're now on &lt;code&gt;001-payments-u2&lt;/code&gt;, branched &lt;em&gt;from&lt;/em&gt; U1. Implement T004–T006, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run &lt;span class="nb"&gt;test&lt;/span&gt;:unit                    &lt;span class="c"&gt;# ✔ 57 tests passing&lt;/span&gt;
git add &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat(u2): payments REST API"&lt;/span&gt;
scripts/check-stack-cap.sh 001-payments
&lt;span class="c"&gt;# Files changed vs '001-payments': 40 / 100&lt;/span&gt;
&lt;span class="c"&gt;# ✅ Within cap.&lt;/span&gt;
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin 001-payments-u2
gh stack submit &lt;span class="nt"&gt;--draft&lt;/span&gt; &lt;span class="nt"&gt;--fill&lt;/span&gt;
&lt;span class="c"&gt;# ✔ Created https://github.com/acme/payments-service/pull/2&lt;/span&gt;
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; 001-payments-u3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: &lt;code&gt;gh stack submit&lt;/code&gt; is &lt;strong&gt;idempotent&lt;/strong&gt;. Each run creates missing PRs and updates existing ones — so the whole stack stays fresh and CI keeps running on every PR while you build upward.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔁 Unit 3
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run &lt;span class="nb"&gt;test&lt;/span&gt;:unit
git add &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat(u3): stripe webhooks + admin UI"&lt;/span&gt;
scripts/check-stack-cap.sh 001-payments-u2
&lt;span class="c"&gt;# Files changed vs '001-payments-u2': 70 / 100&lt;/span&gt;
&lt;span class="c"&gt;# ✅ Within cap.&lt;/span&gt;
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin 001-payments-u3
gh stack submit &lt;span class="nt"&gt;--fill&lt;/span&gt;
&lt;span class="c"&gt;# ✔ Created https://github.com/acme/payments-service/pull/3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The moment of truth — view the stack
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main
└─ 001-payments (#1, draft)
   └─ 001-payments-u2 (#2, draft)
      └─ 001-payments-u3 (#3, draft)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three PRs. Largest is 70 files. Every one had green tests before it was pushed. 🎉&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unit Exit Checklist&lt;/strong&gt; (before touching the next unit):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;code&gt;tasks.md&lt;/code&gt; boxes ticked for this unit&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;npm run test:unit&lt;/code&gt; green&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;check-stack-cap.sh &amp;lt;parent&amp;gt;&lt;/code&gt; → &lt;code&gt;✅&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Committed &amp;amp; pushed&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;gh stack submit&lt;/code&gt; ran clean&lt;/li&gt;
&lt;li&gt;[ ] Next unit branch created&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part 7 — You have PRs. Now what?
&lt;/h2&gt;

&lt;p&gt;This is where most stacked-PR guides stop. Ours doesn't.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.1 Move PR #1 out of draft when review starts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;ready 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.2 Handling review feedback — mid-stack edits are normal
&lt;/h3&gt;

&lt;p&gt;A reviewer requests a change to the domain model… in &lt;strong&gt;U1&lt;/strong&gt;, the &lt;em&gt;bottom&lt;/em&gt; PR. With stacked PRs this is cheap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh stack checkout        &lt;span class="c"&gt;# interactive picker:&lt;/span&gt;
&lt;span class="c"&gt;# ? Select a branch (…): 001-payments          ← pick the bottom PR's branch&lt;/span&gt;

&lt;span class="c"&gt;# …apply the fix, with tests…&lt;/span&gt;
npm run &lt;span class="nb"&gt;test&lt;/span&gt;:unit &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git add &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix(u1): review feedback"&lt;/span&gt;
scripts/check-stack-cap.sh main &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git push

gh stack &lt;span class="nb"&gt;sync&lt;/span&gt;            &lt;span class="c"&gt;# ✨ rebases U2 and U3 on top of your fix automatically&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open PR #2 and #3 — GitHub now shows them updated with the fix. &lt;strong&gt;One commit, one push, one sync.&lt;/strong&gt; No cherry-pick hell.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.3 Merging: strictly bottom-up
&lt;/h3&gt;

&lt;p&gt;Never merge U2 before U1. The rhythm is &lt;strong&gt;merge → sync → repeat&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Merge the bottom PR&lt;/span&gt;
gh &lt;span class="nb"&gt;pr &lt;/span&gt;merge 1 &lt;span class="nt"&gt;--squash&lt;/span&gt;
gh stack &lt;span class="nb"&gt;sync&lt;/span&gt;            &lt;span class="c"&gt;# re-parents U2 onto main; PR #2 now targets main&lt;/span&gt;

&lt;span class="c"&gt;# Reviewers approve PR #2 (now reviewable standalone!)&lt;/span&gt;
gh &lt;span class="nb"&gt;pr &lt;/span&gt;merge 2 &lt;span class="nt"&gt;--squash&lt;/span&gt;
gh stack &lt;span class="nb"&gt;sync&lt;/span&gt;            &lt;span class="c"&gt;# PR #3 re-targets main&lt;/span&gt;

gh &lt;span class="nb"&gt;pr &lt;/span&gt;merge 3 &lt;span class="nt"&gt;--squash&lt;/span&gt;
gh stack &lt;span class="nb"&gt;sync&lt;/span&gt;            &lt;span class="c"&gt;# stack fully landed 🏁&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each PR gets &lt;em&gt;smaller and more standalone&lt;/em&gt; as the stack dissolves from the bottom — reviewers see shrinking diffs, not growing ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.4 Cleanup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout main &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git pull
git branch &lt;span class="nt"&gt;-D&lt;/span&gt; 001-payments 001-payments-u2 001-payments-u3
git push origin &lt;span class="nt"&gt;--delete&lt;/span&gt; 001-payments 001-payments-u2 001-payments-u3  &lt;span class="c"&gt;# if not auto-deleted&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feature landed. Next feature starts the cycle again at Part 3.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 8 — When the 100-file cap bites mid-unit
&lt;/h2&gt;

&lt;p&gt;It will happen eventually. The agent is deep into U3, and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scripts/check-stack-cap.sh 001-payments-u2
&lt;span class="c"&gt;# Files changed vs '001-payments-u2': 112 / 100&lt;/span&gt;
&lt;span class="c"&gt;# ❌ FILE CAP EXCEEDED — do NOT push or run gh stack. Split this unit.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The recovery procedure (the agent follows this automatically if you adopted the constitution):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stop.&lt;/strong&gt; Do not push, do not run &lt;code&gt;gh stack&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the overflow is in the last commit: &lt;code&gt;git reset --soft HEAD~1&lt;/code&gt; (keep the work staged).&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;tasks.md&lt;/code&gt;: move unfinished/overflow tasks into a &lt;strong&gt;new unit&lt;/strong&gt; (e.g., split U3 → U3a "Webhooks" / U3b "Admin UI").&lt;/li&gt;
&lt;li&gt;Commit what fits within the cap → run the exit loop → push → submit.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git checkout -b 001-payments-u3b&lt;/code&gt; and continue the loop.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The stack becomes four PRs instead of three. &lt;strong&gt;That's the system working&lt;/strong&gt;, not failing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 9 — Troubleshooting
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gh stack submit&lt;/code&gt; only creates one PR&lt;/td&gt;
&lt;td&gt;Child branch wasn't created &lt;em&gt;from&lt;/em&gt; the parent — broken ancestry&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git checkout -b &amp;lt;child&amp;gt; &amp;lt;parent&amp;gt;&lt;/code&gt; from scratch; never open stacked PRs manually&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PR targets &lt;code&gt;main&lt;/code&gt; instead of the unit below&lt;/td&gt;
&lt;td&gt;PR created outside &lt;code&gt;gh stack submit&lt;/code&gt;, or ancestry broken&lt;/td&gt;
&lt;td&gt;Delete PR, fix ancestry, re-&lt;code&gt;submit&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cap fails at push time&lt;/td&gt;
&lt;td&gt;Files added after planning&lt;/td&gt;
&lt;td&gt;Part 8 split procedure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conflicts during &lt;code&gt;gh stack sync&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;main&lt;/code&gt; or a lower unit moved&lt;/td&gt;
&lt;td&gt;Fix conflicts branch-by-branch → &lt;code&gt;git rebase --continue&lt;/code&gt; → rerun &lt;code&gt;gh stack sync&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixed U1, but U2's CI broke&lt;/td&gt;
&lt;td&gt;Legit stacked coupling — U2 built on old U1&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gh stack checkout&lt;/code&gt; U2, fix, push, &lt;code&gt;gh stack sync&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent runs &lt;code&gt;gh stack&lt;/code&gt; with red tests&lt;/td&gt;
&lt;td&gt;Constitution rules not loaded&lt;/td&gt;
&lt;td&gt;Re-paste contract into the prompt; verify &lt;code&gt;.specify/&lt;/code&gt; constitution contains rule #4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Part 10 — Recap &amp;amp; cheat sheet
&lt;/h2&gt;

&lt;p&gt;The entire methodology in one line:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Plan the stack → build a unit → tests green → cap green → &lt;code&gt;gh stack submit&lt;/code&gt; → stack the next unit → merge bottom-up → sync.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ── Stack lifecycle ──────────────────────────────&lt;/span&gt;
gh stack submit &lt;span class="nt"&gt;--draft&lt;/span&gt; &lt;span class="nt"&gt;--fill&lt;/span&gt;   &lt;span class="c"&gt;# create/update PRs (idempotent — run every unit)&lt;/span&gt;
gh stack view                    &lt;span class="c"&gt;# visualize the stack&lt;/span&gt;
gh stack checkout                &lt;span class="c"&gt;# hop to any branch (for review fixes)&lt;/span&gt;
gh stack &lt;span class="nb"&gt;sync&lt;/span&gt;                    &lt;span class="c"&gt;# rebase/re-parent after fixes and merges&lt;/span&gt;
gh &lt;span class="nb"&gt;pr &lt;/span&gt;merge &amp;lt;n&amp;gt; &lt;span class="nt"&gt;--squash&lt;/span&gt;         &lt;span class="c"&gt;# merge bottom PR, then…&lt;/span&gt;

&lt;span class="c"&gt;# ── The gate (before EVERY submit) ───────────────&lt;/span&gt;
npm run &lt;span class="nb"&gt;test&lt;/span&gt;:unit                        &lt;span class="c"&gt;# gate 1: tests&lt;/span&gt;
scripts/check-stack-cap.sh &amp;lt;parent&amp;gt;      &lt;span class="c"&gt;# gate 2: ≤100 files&lt;/span&gt;

&lt;span class="c"&gt;# ── Overrides ────────────────────────────────────&lt;/span&gt;
&lt;span class="nv"&gt;STACK_FILE_CAP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50 scripts/check-stack-cap.sh main   &lt;span class="c"&gt;# tighter temporary cap&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why this combination wins
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Spec Kit's answer&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;gh stack&lt;/code&gt;'s answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent builds the wrong thing&lt;/td&gt;
&lt;td&gt;Spec + plan + clarify gates&lt;/td&gt;
&lt;td&gt;Small PRs get early feedback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unreviewable mega-PRs&lt;/td&gt;
&lt;td&gt;Tasks grouped into ≤100-file units&lt;/td&gt;
&lt;td&gt;Stacked PRs, auto-managed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent "finishes" broken code&lt;/td&gt;
&lt;td&gt;Constitution: tests before &lt;em&gt;anything&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;gh stack&lt;/code&gt; literally cannot run until gates pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Merge-day pain&lt;/td&gt;
&lt;td&gt;Ordered units&lt;/td&gt;
&lt;td&gt;Bottom-up merge + &lt;code&gt;gh stack sync&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Next steps:&lt;/strong&gt; try it on your smallest real feature first. Tighten &lt;code&gt;STACK_FILE_CAP&lt;/code&gt; to 50 and watch your review times drop. And put the Part 2 contract in your constitution &lt;em&gt;today&lt;/em&gt; — it's the difference between an agent that follows the loop and one that ships you another 180-file PR.&lt;/p&gt;

</description>
      <category>speckit</category>
      <category>genai</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
