From d6274600ab4324239550dcd59eac4eba57ab098a Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 9 Jul 2026 14:53:43 +0100 Subject: [PATCH 1/5] prototype: reframe disposal around primary vs secondary source Retain the prototype as a primary source on a throwaway branch linked from the relevant issue, rather than deleting it, while the distilled answer remains the secondary source. Keeps prototype scaffolding out of the main branch without destroying the runnable evidence. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/prototype-primary-secondary-source.md | 5 +++++ docs/engineering/prototype.md | 6 ++++-- skills/engineering/prototype/LOGIC.md | 2 +- skills/engineering/prototype/SKILL.md | 14 ++++++++++---- skills/engineering/prototype/UI.md | 8 ++++---- 5 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 .changeset/prototype-primary-secondary-source.md diff --git a/.changeset/prototype-primary-secondary-source.md b/.changeset/prototype-primary-secondary-source.md new file mode 100644 index 0000000..c574128 --- /dev/null +++ b/.changeset/prototype-primary-secondary-source.md @@ -0,0 +1,5 @@ +--- +"mattpocock-skills": minor +--- + +Reword how the **`prototype`** skill lets go of its artifacts, around a **primary vs secondary source** distinction. The _secondary source_ is the distilled answer (issue/ADR/commit) — still the part that matters most. The _primary source_ is the prototype itself: rather than deleting it, it's now preserved as runnable evidence on a throwaway branch (`prototype/`) linked from the relevant issue, never merged, so the main branch keeps only the validated decision. diff --git a/docs/engineering/prototype.md b/docs/engineering/prototype.md index af8ca42..14cb85d 100644 --- a/docs/engineering/prototype.md +++ b/docs/engineering/prototype.md @@ -31,9 +31,11 @@ The question decides the shape, and there are two shapes: Picking the wrong branch wastes the whole prototype, so the question comes first. Both branches keep state in memory, run from one command, and surface the full state on every step. -## The answer is the artifact +## Primary and secondary source -The code is disposable; the **answer** is the only thing worth keeping. When the prototype has settled its question, capture the verdict somewhere durable — a commit message, an ADR, an issue, or a `NOTES.md` next to it — alongside the question it answered, then delete or absorb the code. A prototype left rotting in the repo has outlived its purpose. +A finished prototype leaves two things, and they're kept differently. The **secondary source** is the _answer_ — the verdict plus the question it settled, distilled into durable prose (a commit message, an ADR, an issue). That's what future readers consult, and it's the part that matters most. The **primary source** is the _prototype itself_ — the runnable evidence the answer came from. + +The prototype doesn't belong in the main repo: no tests, no error handling, nothing to maintain. But that's not a reason to destroy it. Once the answer is captured, fold any validated decision into the real code, then move the prototype onto a throwaway branch linked from the relevant issue — never merged. The main branch stays clean; the raw exploration stays one click away for anyone who wants to re-run it. A prototype left rotting in the main branch has outlived its purpose — a prototype preserved as a primary source on a side branch hasn't. ## Where it fits diff --git a/skills/engineering/prototype/LOGIC.md b/skills/engineering/prototype/LOGIC.md index 526ecb1..854ae9a 100644 --- a/skills/engineering/prototype/LOGIC.md +++ b/skills/engineering/prototype/LOGIC.md @@ -68,7 +68,7 @@ Give the user the run command. They'll drive it themselves; the interesting mome ### 7. Capture the answer -When the prototype has done its job, the answer to the question is the only thing worth keeping. If the user is around, ask what it taught them. If not, leave a `NOTES.md` next to the prototype so the answer can be filled in (or filled in by you, if you've watched the session) before the prototype gets deleted. +When the prototype has done its job, capture the **answer** — the secondary source — somewhere durable (issue, ADR, commit message). If the user is around, ask what it taught them; if not, leave a `NOTES.md` next to the prototype so the answer can be filled in (or filled in by you, if you've watched the session). Then let go of the prototype the way the [SKILL](SKILL.md) describes: fold any validated logic into the real module, and move the prototype itself — the primary source — onto a throwaway branch linked from the relevant issue rather than deleting it. ## Anti-patterns diff --git a/skills/engineering/prototype/SKILL.md b/skills/engineering/prototype/SKILL.md index 9425f7d..685b499 100644 --- a/skills/engineering/prototype/SKILL.md +++ b/skills/engineering/prototype/SKILL.md @@ -21,10 +21,16 @@ The two branches produce very different artifacts — getting this wrong wastes 1. **Throwaway from day one, and clearly marked as such.** Locate the prototype code close to where it will actually be used (next to the module or page it's prototyping for) so context is obvious — but name it so a casual reader can see it's a prototype, not production. For throwaway UI routes, obey whatever routing convention the project already uses; don't invent a new top-level structure. 2. **One command to run.** Whatever the project's existing task runner supports — `pnpm `, `python `, `bun `, etc. The user must be able to start it without thinking. 3. **No persistence by default.** State lives in memory. Persistence is the thing the prototype is _checking_, not something it should depend on. If the question explicitly involves a database, hit a scratch DB or a local file with a clear "PROTOTYPE — wipe me" name. -4. **Skip the polish.** No tests, no error handling beyond what makes the prototype _runnable_, no abstractions. The point is to learn something fast and then delete it. +4. **Skip the polish.** No tests, no error handling beyond what makes the prototype _runnable_, no abstractions. The point is to learn something fast and then let it go. 5. **Surface the state.** After every action (logic) or on every variant switch (UI), print or render the full relevant state so the user can see what changed. -6. **Delete or absorb when done.** When the prototype has answered its question, either delete it or fold the validated decision into the real code — don't leave it rotting in the repo. +6. **Let go of it when done.** Fold any validated decision into the real code, then preserve the prototype itself as a **primary source** — committed to a throwaway branch linked from the relevant issue, never merged to main (see _Primary vs secondary source_ below). The main branch keeps only the validated decision. -## When done +## When done: primary vs secondary source -The _answer_ is the only thing worth keeping from a prototype. Capture it somewhere durable (commit message, ADR, issue, or a `NOTES.md` next to the prototype) along with the question it was answering. If the user is around, that capture is a quick conversation; if not, leave the placeholder so they (or you, on the next pass) can fill in the verdict before deleting the prototype. +A finished prototype leaves two things behind, and they're kept differently. + +- **The secondary source is the _answer_** — the verdict plus the question it settled, distilled into durable prose: an issue comment, an ADR, or a commit message. This is what future readers actually consult, and it's the part that matters most. If the user is around, capturing it is a quick conversation; if not, leave a placeholder (a `NOTES.md` next to the prototype) so the verdict can be filled in — by them, or by you if you watched the session — before you move the code. + +- **The primary source is the _prototype itself_** — the runnable artifact the answer came from. It's the evidence behind the verdict, so you don't delete it; but with no tests and no maintenance story, it doesn't belong in the main repo either. Once the answer is captured, get the prototype out: commit it to a throwaway branch (e.g. `prototype/`), push it, and link that branch from the relevant issue. Never merge it. The main branch keeps only the validated decision folded into real code; the raw exploration stays on the branch, one click away for anyone who wants to re-run it. + +This is distinct from _absorbing_: lifting a validated reducer, state machine, or UI direction into the real module keeps the **decision**, not the prototype. The throwaway branch is what preserves the primary source. diff --git a/skills/engineering/prototype/UI.md b/skills/engineering/prototype/UI.md index f3b6e64..b99f2c6 100644 --- a/skills/engineering/prototype/UI.md +++ b/skills/engineering/prototype/UI.md @@ -97,12 +97,12 @@ Surface the URL (and the `?variant=` keys). The user will flip through whenever ### 6. Capture the answer and clean up -Once a variant has won, write down which one and why (commit message, ADR, issue, or a `NOTES.md` next to the prototype if running AFK and the user hasn't responded yet). Then: +Once a variant has won, capture the **answer** — the secondary source: which variant and why (commit message, ADR, issue, or a `NOTES.md` next to the prototype if running AFK and the user hasn't responded yet). Then fold the winner into the real code and get the prototype scaffolding out of the main branch: -- **Sub-shape A** — delete the losing variants and the switcher; fold the winner into the existing page. -- **Sub-shape B** — promote the winning variant to a real route, delete the throwaway route and the switcher. +- **Sub-shape A** — fold the winner into the existing page; drop the losing variants and the switcher from main. +- **Sub-shape B** — promote the winning variant to a real route; drop the throwaway route and the switcher from main. -Don't leave variant components or the switcher lying around. They rot fast and confuse the next reader. +Don't leave variant components or the switcher lying around in the main branch — they rot fast and confuse the next reader. But don't just destroy them either: the full set of variants is the primary source, so preserve the prototype on a throwaway branch linked from the relevant issue (see [SKILL](SKILL.md)) before you strip it out of main. ## Anti-patterns From cdec9f6eb24dbfe606e3ad9b3eb457ba09210b85 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 9 Jul 2026 14:57:48 +0100 Subject: [PATCH 2/5] prototype: simplify to single primary-source idea; dedup branch files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the secondary-source label — the actionable distinction is just that the prototype is a primary source to retain on a throwaway branch. Collapse the re-descriptions in LOGIC/UI so they point to SKILL for the disposal concept and add only branch-specific nuance. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/prototype-primary-secondary-source.md | 5 ----- .changeset/prototype-primary-source.md | 5 +++++ docs/engineering/prototype.md | 6 +++--- skills/engineering/prototype/LOGIC.md | 6 +++--- skills/engineering/prototype/SKILL.md | 12 ++++++------ skills/engineering/prototype/UI.md | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) delete mode 100644 .changeset/prototype-primary-secondary-source.md create mode 100644 .changeset/prototype-primary-source.md diff --git a/.changeset/prototype-primary-secondary-source.md b/.changeset/prototype-primary-secondary-source.md deleted file mode 100644 index c574128..0000000 --- a/.changeset/prototype-primary-secondary-source.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"mattpocock-skills": minor ---- - -Reword how the **`prototype`** skill lets go of its artifacts, around a **primary vs secondary source** distinction. The _secondary source_ is the distilled answer (issue/ADR/commit) — still the part that matters most. The _primary source_ is the prototype itself: rather than deleting it, it's now preserved as runnable evidence on a throwaway branch (`prototype/`) linked from the relevant issue, never merged, so the main branch keeps only the validated decision. diff --git a/.changeset/prototype-primary-source.md b/.changeset/prototype-primary-source.md new file mode 100644 index 0000000..5c1da70 --- /dev/null +++ b/.changeset/prototype-primary-source.md @@ -0,0 +1,5 @@ +--- +"mattpocock-skills": minor +--- + +Reword how the **`prototype`** skill lets go of its artifacts around a single idea: **the prototype is a primary source**. Rather than being deleted once it's answered its question, the prototype is kept as runnable evidence on a throwaway branch (`prototype/`) linked from the relevant issue, never merged, so the main branch keeps only the validated decision. The answer (verdict + question) is still captured durably in an issue/ADR/commit. diff --git a/docs/engineering/prototype.md b/docs/engineering/prototype.md index 14cb85d..c3ddf94 100644 --- a/docs/engineering/prototype.md +++ b/docs/engineering/prototype.md @@ -31,11 +31,11 @@ The question decides the shape, and there are two shapes: Picking the wrong branch wastes the whole prototype, so the question comes first. Both branches keep state in memory, run from one command, and surface the full state on every step. -## Primary and secondary source +## Keep the prototype as a primary source -A finished prototype leaves two things, and they're kept differently. The **secondary source** is the _answer_ — the verdict plus the question it settled, distilled into durable prose (a commit message, an ADR, an issue). That's what future readers consult, and it's the part that matters most. The **primary source** is the _prototype itself_ — the runnable evidence the answer came from. +A finished prototype leaves two things. The **answer** — the verdict plus the question it settled — is what you capture durably (a commit message, an ADR, an issue). The **prototype itself is a primary source** — the runnable evidence the answer came from. -The prototype doesn't belong in the main repo: no tests, no error handling, nothing to maintain. But that's not a reason to destroy it. Once the answer is captured, fold any validated decision into the real code, then move the prototype onto a throwaway branch linked from the relevant issue — never merged. The main branch stays clean; the raw exploration stays one click away for anyone who wants to re-run it. A prototype left rotting in the main branch has outlived its purpose — a prototype preserved as a primary source on a side branch hasn't. +The prototype doesn't belong in the main repo: no tests, no error handling, nothing to maintain. But that's not a reason to destroy it. Once the answer is captured, fold any validated decision into the real code, then move the prototype onto a throwaway branch linked from the relevant issue — never merged. The main branch stays clean; the raw exploration stays one click away for anyone who wants to re-run it. A prototype left rotting in the main branch has outlived its purpose — a prototype kept as a primary source on a side branch hasn't. ## Where it fits diff --git a/skills/engineering/prototype/LOGIC.md b/skills/engineering/prototype/LOGIC.md index 854ae9a..ffae9a1 100644 --- a/skills/engineering/prototype/LOGIC.md +++ b/skills/engineering/prototype/LOGIC.md @@ -36,7 +36,7 @@ The right shape depends on the question: Pick whichever shape best fits the question being asked, *not* whichever is easiest to wire to a TUI. Keep it pure: no I/O, no terminal code, no `console.log` for control flow. The TUI imports it and calls into it; nothing flows the other direction. -This is what makes the prototype useful past its own lifetime. When the question's been answered, the validated reducer / machine / function set can be lifted into the real module — the TUI shell gets deleted. +This is what makes the prototype useful past its own lifetime: when the question's been answered, the validated reducer / machine / function set can be lifted into the real module on its own. ### 4. Build the smallest TUI that exposes the state @@ -66,9 +66,9 @@ If the host project has no task runner, just put the command at the top of the p Give the user the run command. They'll drive it themselves; the interesting moments are when they say "wait, that shouldn't be possible" or "huh, I assumed X would be different" — those are the bugs in the _idea_, which is the whole point. If they want new actions added, add them. Prototypes evolve. -### 7. Capture the answer +### 7. Capture the answer and let go -When the prototype has done its job, capture the **answer** — the secondary source — somewhere durable (issue, ADR, commit message). If the user is around, ask what it taught them; if not, leave a `NOTES.md` next to the prototype so the answer can be filled in (or filled in by you, if you've watched the session). Then let go of the prototype the way the [SKILL](SKILL.md) describes: fold any validated logic into the real module, and move the prototype itself — the primary source — onto a throwaway branch linked from the relevant issue rather than deleting it. +Once the prototype has answered its question, capture the answer and dispose of the prototype the way the [SKILL](SKILL.md) describes. The logic-specific mapping: the validated reducer / machine / function set lifts into the real module (the decision, absorbed); the TUI shell rides along to the throwaway branch that keeps the prototype as a primary source. ## Anti-patterns diff --git a/skills/engineering/prototype/SKILL.md b/skills/engineering/prototype/SKILL.md index 685b499..61f5eaa 100644 --- a/skills/engineering/prototype/SKILL.md +++ b/skills/engineering/prototype/SKILL.md @@ -23,14 +23,14 @@ The two branches produce very different artifacts — getting this wrong wastes 3. **No persistence by default.** State lives in memory. Persistence is the thing the prototype is _checking_, not something it should depend on. If the question explicitly involves a database, hit a scratch DB or a local file with a clear "PROTOTYPE — wipe me" name. 4. **Skip the polish.** No tests, no error handling beyond what makes the prototype _runnable_, no abstractions. The point is to learn something fast and then let it go. 5. **Surface the state.** After every action (logic) or on every variant switch (UI), print or render the full relevant state so the user can see what changed. -6. **Let go of it when done.** Fold any validated decision into the real code, then preserve the prototype itself as a **primary source** — committed to a throwaway branch linked from the relevant issue, never merged to main (see _Primary vs secondary source_ below). The main branch keeps only the validated decision. +6. **Let go of it when done.** Fold any validated decision into the real code, then keep the prototype itself as a **primary source** — committed to a throwaway branch linked from the relevant issue, never merged to main (see _Keep it as a primary source_ below). The main branch keeps only the validated decision. -## When done: primary vs secondary source +## When done: keep it as a primary source -A finished prototype leaves two things behind, and they're kept differently. +Two things come out of a finished prototype. -- **The secondary source is the _answer_** — the verdict plus the question it settled, distilled into durable prose: an issue comment, an ADR, or a commit message. This is what future readers actually consult, and it's the part that matters most. If the user is around, capturing it is a quick conversation; if not, leave a placeholder (a `NOTES.md` next to the prototype) so the verdict can be filled in — by them, or by you if you watched the session — before you move the code. +- **The answer** — the verdict plus the question it settled — is what you capture durably: an issue comment, an ADR, or a commit message. If the user is around, that's a quick conversation; if not, leave a placeholder (a `NOTES.md` next to the prototype) so the verdict can be filled in before you move the code. -- **The primary source is the _prototype itself_** — the runnable artifact the answer came from. It's the evidence behind the verdict, so you don't delete it; but with no tests and no maintenance story, it doesn't belong in the main repo either. Once the answer is captured, get the prototype out: commit it to a throwaway branch (e.g. `prototype/`), push it, and link that branch from the relevant issue. Never merge it. The main branch keeps only the validated decision folded into real code; the raw exploration stays on the branch, one click away for anyone who wants to re-run it. +- **The prototype itself is a primary source** — the runnable evidence the answer came from. With no tests and no maintenance story it doesn't belong in the main repo, but that's not a reason to delete it. Once the answer's captured, get the prototype out: commit it to a throwaway branch (e.g. `prototype/`), push it, and link that branch from the relevant issue. Never merge it. The main branch keeps only the validated decision folded into real code; the raw exploration stays on the branch, one click away for anyone who wants to re-run it. -This is distinct from _absorbing_: lifting a validated reducer, state machine, or UI direction into the real module keeps the **decision**, not the prototype. The throwaway branch is what preserves the primary source. +This is distinct from _absorbing_: lifting a validated reducer, state machine, or UI direction into the real module keeps the **decision**, not the prototype. The throwaway branch is what keeps the prototype as a primary source. diff --git a/skills/engineering/prototype/UI.md b/skills/engineering/prototype/UI.md index b99f2c6..42b484c 100644 --- a/skills/engineering/prototype/UI.md +++ b/skills/engineering/prototype/UI.md @@ -97,12 +97,12 @@ Surface the URL (and the `?variant=` keys). The user will flip through whenever ### 6. Capture the answer and clean up -Once a variant has won, capture the **answer** — the secondary source: which variant and why (commit message, ADR, issue, or a `NOTES.md` next to the prototype if running AFK and the user hasn't responded yet). Then fold the winner into the real code and get the prototype scaffolding out of the main branch: +Once a variant has won, capture the answer — which variant and why — and dispose of the prototype the way the [SKILL](SKILL.md) describes. Fold the winner into the real code and get the rest out of the main branch: - **Sub-shape A** — fold the winner into the existing page; drop the losing variants and the switcher from main. - **Sub-shape B** — promote the winning variant to a real route; drop the throwaway route and the switcher from main. -Don't leave variant components or the switcher lying around in the main branch — they rot fast and confuse the next reader. But don't just destroy them either: the full set of variants is the primary source, so preserve the prototype on a throwaway branch linked from the relevant issue (see [SKILL](SKILL.md)) before you strip it out of main. +The full set of variants is the primary source, so it lands on the throwaway branch, not the bin — variant components and the switcher left in the main branch rot fast and confuse the next reader. ## Anti-patterns From 371b9c9c9431c6cffb29a84a383e2afc725109f6 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Fri, 10 Jul 2026 09:39:52 +0100 Subject: [PATCH 3/5] prototype: capture the prototype, don't dispose of it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reframe the artifact handling as capturing the prototype somewhere out of main — a throwaway branch — with a context pointer to it left on the implementation issue, instead of "disposing" of it. The main branch still keeps only the validated decision. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/prototype-primary-source.md | 2 +- docs/engineering/prototype.md | 2 +- skills/engineering/prototype/LOGIC.md | 2 +- skills/engineering/prototype/SKILL.md | 4 ++-- skills/engineering/prototype/UI.md | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.changeset/prototype-primary-source.md b/.changeset/prototype-primary-source.md index 5c1da70..4e97b19 100644 --- a/.changeset/prototype-primary-source.md +++ b/.changeset/prototype-primary-source.md @@ -2,4 +2,4 @@ "mattpocock-skills": minor --- -Reword how the **`prototype`** skill lets go of its artifacts around a single idea: **the prototype is a primary source**. Rather than being deleted once it's answered its question, the prototype is kept as runnable evidence on a throwaway branch (`prototype/`) linked from the relevant issue, never merged, so the main branch keeps only the validated decision. The answer (verdict + question) is still captured durably in an issue/ADR/commit. +Reword how the **`prototype`** skill handles its artifacts around a single idea: **the prototype is a primary source**. Rather than being deleted once it's answered its question, the prototype is captured as runnable evidence on a throwaway branch (`prototype/`) out of main, with a context pointer to it left on the implementation issue — so the main branch keeps only the validated decision while the exploration stays findable. The answer (verdict + question) is still captured durably in an issue/ADR/commit. diff --git a/docs/engineering/prototype.md b/docs/engineering/prototype.md index c3ddf94..208f114 100644 --- a/docs/engineering/prototype.md +++ b/docs/engineering/prototype.md @@ -35,7 +35,7 @@ Picking the wrong branch wastes the whole prototype, so the question comes first A finished prototype leaves two things. The **answer** — the verdict plus the question it settled — is what you capture durably (a commit message, an ADR, an issue). The **prototype itself is a primary source** — the runnable evidence the answer came from. -The prototype doesn't belong in the main repo: no tests, no error handling, nothing to maintain. But that's not a reason to destroy it. Once the answer is captured, fold any validated decision into the real code, then move the prototype onto a throwaway branch linked from the relevant issue — never merged. The main branch stays clean; the raw exploration stays one click away for anyone who wants to re-run it. A prototype left rotting in the main branch has outlived its purpose — a prototype kept as a primary source on a side branch hasn't. +The prototype doesn't belong in the main branch: no tests, no error handling, nothing to maintain. But that's not a reason to destroy it. Once the answer is captured, fold any validated decision into the real code, then capture the prototype on a throwaway branch — out of main, never merged — and leave a context pointer to it on the implementation issue. The main branch stays clean; the raw exploration stays one click away for anyone who wants to re-run it. A prototype left rotting in the main branch has outlived its purpose — a prototype captured as a primary source on a side branch hasn't. ## Where it fits diff --git a/skills/engineering/prototype/LOGIC.md b/skills/engineering/prototype/LOGIC.md index ffae9a1..c86d1bd 100644 --- a/skills/engineering/prototype/LOGIC.md +++ b/skills/engineering/prototype/LOGIC.md @@ -68,7 +68,7 @@ Give the user the run command. They'll drive it themselves; the interesting mome ### 7. Capture the answer and let go -Once the prototype has answered its question, capture the answer and dispose of the prototype the way the [SKILL](SKILL.md) describes. The logic-specific mapping: the validated reducer / machine / function set lifts into the real module (the decision, absorbed); the TUI shell rides along to the throwaway branch that keeps the prototype as a primary source. +Once the prototype has answered its question, capture the answer, then capture the prototype the way the [SKILL](SKILL.md) describes. The logic-specific mapping: the validated reducer / machine / function set lifts into the real module (the decision, absorbed); the TUI shell rides along to the throwaway branch that keeps the prototype as a primary source. ## Anti-patterns diff --git a/skills/engineering/prototype/SKILL.md b/skills/engineering/prototype/SKILL.md index 61f5eaa..ceceab2 100644 --- a/skills/engineering/prototype/SKILL.md +++ b/skills/engineering/prototype/SKILL.md @@ -23,7 +23,7 @@ The two branches produce very different artifacts — getting this wrong wastes 3. **No persistence by default.** State lives in memory. Persistence is the thing the prototype is _checking_, not something it should depend on. If the question explicitly involves a database, hit a scratch DB or a local file with a clear "PROTOTYPE — wipe me" name. 4. **Skip the polish.** No tests, no error handling beyond what makes the prototype _runnable_, no abstractions. The point is to learn something fast and then let it go. 5. **Surface the state.** After every action (logic) or on every variant switch (UI), print or render the full relevant state so the user can see what changed. -6. **Let go of it when done.** Fold any validated decision into the real code, then keep the prototype itself as a **primary source** — committed to a throwaway branch linked from the relevant issue, never merged to main (see _Keep it as a primary source_ below). The main branch keeps only the validated decision. +6. **Capture it when done.** Fold any validated decision into the real code, then capture the prototype itself as a **primary source** — committed to a throwaway branch, out of main, with a pointer to that branch left on the implementation issue (see _Keep it as a primary source_ below). The main branch keeps only the validated decision. ## When done: keep it as a primary source @@ -31,6 +31,6 @@ Two things come out of a finished prototype. - **The answer** — the verdict plus the question it settled — is what you capture durably: an issue comment, an ADR, or a commit message. If the user is around, that's a quick conversation; if not, leave a placeholder (a `NOTES.md` next to the prototype) so the verdict can be filled in before you move the code. -- **The prototype itself is a primary source** — the runnable evidence the answer came from. With no tests and no maintenance story it doesn't belong in the main repo, but that's not a reason to delete it. Once the answer's captured, get the prototype out: commit it to a throwaway branch (e.g. `prototype/`), push it, and link that branch from the relevant issue. Never merge it. The main branch keeps only the validated decision folded into real code; the raw exploration stays on the branch, one click away for anyone who wants to re-run it. +- **The prototype itself is a primary source** — the runnable evidence the answer came from. With no tests and no maintenance story it doesn't belong in the main branch, but that's not a reason to delete it. So capture it somewhere out of main: commit it to a throwaway branch (e.g. `prototype/`), push it, and leave a context pointer to that branch on the implementation issue so anyone can find it later. Never merge it in. The main branch keeps only the validated decision folded into real code; the raw exploration stays on the branch, one click away for anyone who wants to re-run it. This is distinct from _absorbing_: lifting a validated reducer, state machine, or UI direction into the real module keeps the **decision**, not the prototype. The throwaway branch is what keeps the prototype as a primary source. diff --git a/skills/engineering/prototype/UI.md b/skills/engineering/prototype/UI.md index 42b484c..76c0f60 100644 --- a/skills/engineering/prototype/UI.md +++ b/skills/engineering/prototype/UI.md @@ -97,7 +97,7 @@ Surface the URL (and the `?variant=` keys). The user will flip through whenever ### 6. Capture the answer and clean up -Once a variant has won, capture the answer — which variant and why — and dispose of the prototype the way the [SKILL](SKILL.md) describes. Fold the winner into the real code and get the rest out of the main branch: +Once a variant has won, capture the answer — which variant and why — then capture the prototype the way the [SKILL](SKILL.md) describes. Fold the winner into the real code and move the rest onto the throwaway branch, not into main: - **Sub-shape A** — fold the winner into the existing page; drop the losing variants and the switcher from main. - **Sub-shape B** — promote the winning variant to a real route; drop the throwaway route and the switcher from main. From 0375c88bfb1c975241a42baba196d2c0425ae66e Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Fri, 10 Jul 2026 09:49:44 +0100 Subject: [PATCH 4/5] prototype: collapse the when-done section into rule 6 The "keep it as a primary source" section restated rule 6 and was padded with no-ops. Fold the one extra bit (capture the answer) into rule 6 and delete the section: capture the prototype as a primary source on a throwaway branch, pointer on the issue. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/engineering/prototype/SKILL.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/skills/engineering/prototype/SKILL.md b/skills/engineering/prototype/SKILL.md index ceceab2..62c495c 100644 --- a/skills/engineering/prototype/SKILL.md +++ b/skills/engineering/prototype/SKILL.md @@ -23,14 +23,4 @@ The two branches produce very different artifacts — getting this wrong wastes 3. **No persistence by default.** State lives in memory. Persistence is the thing the prototype is _checking_, not something it should depend on. If the question explicitly involves a database, hit a scratch DB or a local file with a clear "PROTOTYPE — wipe me" name. 4. **Skip the polish.** No tests, no error handling beyond what makes the prototype _runnable_, no abstractions. The point is to learn something fast and then let it go. 5. **Surface the state.** After every action (logic) or on every variant switch (UI), print or render the full relevant state so the user can see what changed. -6. **Capture it when done.** Fold any validated decision into the real code, then capture the prototype itself as a **primary source** — committed to a throwaway branch, out of main, with a pointer to that branch left on the implementation issue (see _Keep it as a primary source_ below). The main branch keeps only the validated decision. - -## When done: keep it as a primary source - -Two things come out of a finished prototype. - -- **The answer** — the verdict plus the question it settled — is what you capture durably: an issue comment, an ADR, or a commit message. If the user is around, that's a quick conversation; if not, leave a placeholder (a `NOTES.md` next to the prototype) so the verdict can be filled in before you move the code. - -- **The prototype itself is a primary source** — the runnable evidence the answer came from. With no tests and no maintenance story it doesn't belong in the main branch, but that's not a reason to delete it. So capture it somewhere out of main: commit it to a throwaway branch (e.g. `prototype/`), push it, and leave a context pointer to that branch on the implementation issue so anyone can find it later. Never merge it in. The main branch keeps only the validated decision folded into real code; the raw exploration stays on the branch, one click away for anyone who wants to re-run it. - -This is distinct from _absorbing_: lifting a validated reducer, state machine, or UI direction into the real module keeps the **decision**, not the prototype. The throwaway branch is what keeps the prototype as a primary source. +6. **Capture it when done.** Fold any validated decision into the real code, then capture the prototype itself as a **primary source**: commit it to a throwaway branch, out of main, and leave a context pointer to that branch on the implementation issue. Capture the answer too — the verdict and the question it settled — in the issue or a commit. The main branch keeps only the validated decision. From fa460cbf095a893d14bf41d3db7798cada500259 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Fri, 10 Jul 2026 11:35:29 +0100 Subject: [PATCH 5/5] prototype: drop the vestigial "let it go" Rule 4 is about skipping polish, not the prototype's fate; the trailing "then let it go" was a leftover from the old delete-it framing and now misreads as discard, contradicting capture-as-primary-source. Cut it, and rename LOGIC step 7 off "let go". Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/engineering/prototype/LOGIC.md | 2 +- skills/engineering/prototype/SKILL.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/skills/engineering/prototype/LOGIC.md b/skills/engineering/prototype/LOGIC.md index c86d1bd..fe9a2c2 100644 --- a/skills/engineering/prototype/LOGIC.md +++ b/skills/engineering/prototype/LOGIC.md @@ -66,7 +66,7 @@ If the host project has no task runner, just put the command at the top of the p Give the user the run command. They'll drive it themselves; the interesting moments are when they say "wait, that shouldn't be possible" or "huh, I assumed X would be different" — those are the bugs in the _idea_, which is the whole point. If they want new actions added, add them. Prototypes evolve. -### 7. Capture the answer and let go +### 7. Capture the answer and the prototype Once the prototype has answered its question, capture the answer, then capture the prototype the way the [SKILL](SKILL.md) describes. The logic-specific mapping: the validated reducer / machine / function set lifts into the real module (the decision, absorbed); the TUI shell rides along to the throwaway branch that keeps the prototype as a primary source. diff --git a/skills/engineering/prototype/SKILL.md b/skills/engineering/prototype/SKILL.md index 62c495c..e75d533 100644 --- a/skills/engineering/prototype/SKILL.md +++ b/skills/engineering/prototype/SKILL.md @@ -21,6 +21,6 @@ The two branches produce very different artifacts — getting this wrong wastes 1. **Throwaway from day one, and clearly marked as such.** Locate the prototype code close to where it will actually be used (next to the module or page it's prototyping for) so context is obvious — but name it so a casual reader can see it's a prototype, not production. For throwaway UI routes, obey whatever routing convention the project already uses; don't invent a new top-level structure. 2. **One command to run.** Whatever the project's existing task runner supports — `pnpm `, `python `, `bun `, etc. The user must be able to start it without thinking. 3. **No persistence by default.** State lives in memory. Persistence is the thing the prototype is _checking_, not something it should depend on. If the question explicitly involves a database, hit a scratch DB or a local file with a clear "PROTOTYPE — wipe me" name. -4. **Skip the polish.** No tests, no error handling beyond what makes the prototype _runnable_, no abstractions. The point is to learn something fast and then let it go. +4. **Skip the polish.** No tests, no error handling beyond what makes the prototype _runnable_, no abstractions. The point is to learn something fast. 5. **Surface the state.** After every action (logic) or on every variant switch (UI), print or render the full relevant state so the user can see what changed. 6. **Capture it when done.** Fold any validated decision into the real code, then capture the prototype itself as a **primary source**: commit it to a throwaway branch, out of main, and leave a context pointer to that branch on the implementation issue. Capture the answer too — the verdict and the question it settled — in the issue or a commit. The main branch keeps only the validated decision.