Prototype — throwaway code that answers a question
A prototype is throwaway code that answers a question. The question decides
the shape:
- "Does this logic or state model feel right?" → a tiny interactive
terminal app that pushes the state machine through cases that are hard to
reason about on paper.
- "What should this look like?" → several radically different UI variants
on a single route, switchable in the browser.
Getting the branch wrong wastes the whole prototype. If the question is
ambiguous and the user is not reachable, default to whichever branch better
matches the surrounding code — a backend module suggests logic, a page or
component suggests UI — and state the assumption at the top of the prototype.
Workflow rules that apply to both branches
- Isolate the prototype from the caller's work. Build it on an isolated
worktree or a clearly named throwaway branch. Never commit to, rebase, or
otherwise alter the branch the user was on without their explicit approval.
- Throwaway from day one, and clearly marked as such. Name files and
routes so a casual reader sees "prototype," and follow the project's
existing conventions rather than inventing new top-level structure.
- One command to run, registered with the project's existing task runner
(
package.json scripts, Makefile, justfile, pyproject.toml); if there
is none, put the command at the top of the prototype's README.
- No persistence by default. State lives in memory; persistence is the
thing a prototype checks, not something it depends on. If the question
explicitly involves a database, use a scratch store with a clear
"PROTOTYPE — wipe me" name.
- Skip the polish. No tests, no error handling beyond runnability, no
abstractions. The point is to learn something fast.
- Surface the state. After every action (logic) or on every variant switch
(UI), show the full relevant state so the user sees what changed.
- Capture it when done. Fold the validated decision into the real code;
keep the prototype itself as a primary source on its throwaway branch with a
context pointer from the relevant issue or commit. The main branch keeps
only the validated decision.
Logic branch — interactive terminal app
State the question first — one paragraph at the top of the file or README; a
logic prototype that answers the wrong question is pure waste. Then:
- Use the host project's language and tooling. No new runtimes or package
managers for a prototype.
- Isolate the logic behind a small pure interface that could be lifted
into the real codebase later — a pure reducer
(state, action) → state, an
explicit state machine when "which actions are legal right now" is part of
the question, a set of pure functions over a plain data type, or a module
with a clear method surface when the logic genuinely owns ongoing state.
Pick the shape that fits the question, not the one easiest to wire to a
terminal. No I/O or terminal code inside the logic module.
- Wrap it in the smallest terminal shell that exposes the state: on every
action, clear the screen and re-render one stable frame — current state
pretty-printed, then the keyboard shortcuts (
[a] add [t] tick [q] quit).
Read one keystroke, dispatch, re-render, loop until quit.
- Hand the run command to the user. The interesting moments are "wait,
that shouldn't be possible" — bugs in the idea, which is the point. Add
actions as they ask.
- On resolution, the validated logic module lifts into the real code; the
terminal shell rides along to the throwaway branch as a primary source.
Anti-patterns: adding tests; wiring to the real database; generalizing for
futures the question does not ask about; blurring logic and shell so the
module is no longer portable; shipping the shell toward production.
UI branch — radically different variants on one route
Default to 3 variants; more than 5 is noise. Two sub-shapes; strongly
prefer the first:
- Adjustment to an existing page (preferred): render variants on the
existing route, gated by a
?variant= URL parameter — the page's real data,
auth, and surroundings stay, only the rendering swaps. A new section that
would naturally live inside an existing page is still this sub-shape.
- A new page (last resort): only when the surface genuinely has no home.
Follow the project's routing conventions and name the route so it is
obviously a prototype.
Variants must be structurally different — different layout, information
hierarchy, primary affordance — not different colors. If two drafts come out
similar, redo one with explicit counter-guidance. Use the project's existing
component and styling system. A floating bottom bar switches variants.
Production-safe gate: the entire variant mechanism — variant components,
switcher bar, and the ?variant= handling — must be unreachable in production
builds: compile it out via the project's dev-mode conditionals, an explicitly
non-production route guard, or by keeping the prototype on its throwaway
branch. Gating only the switcher UI is not enough.
Attribution and license
Derived from skills/engineering/prototype/ (SKILL.md, LOGIC.md,
UI.md) in mattpocock/skills at
commit 2ab958093e83e0ec752e6c1c5932da465bf23e0c, adapted for this package
(worktree isolation, production-safe gating, inlined references). That
material is and remains MIT-licensed: Copyright (c) 2026 Matt Pocock.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: The above copyright
notice and this permission notice shall be included in all copies or
substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS",
WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1---2name: prototype3description: Build a throwaway prototype that answers one design question — an interactive terminal app to pressure-test a state model or logic shape, or several radically different UI variants on one route. Use when the user says "prototype this," "sanity-check this state model," "show me a few options for this page," "mock up some variations," or "/agent-collab:prototype." Also offer this proactively when a design conversation is circling a question that a runnable artifact would settle in minutes — how a state machine handles an awkward case, or which of several layouts actually works with real data.4---56# Prototype — throwaway code that answers a question78A prototype is **throwaway code that answers a question**. The question decides9the shape:1011- **"Does this logic or state model feel right?"** → a tiny interactive12 terminal app that pushes the state machine through cases that are hard to13 reason about on paper.14- **"What should this look like?"** → several radically different UI variants15 on a single route, switchable in the browser.1617Getting the branch wrong wastes the whole prototype. If the question is18ambiguous and the user is not reachable, default to whichever branch better19matches the surrounding code — a backend module suggests logic, a page or20component suggests UI — and state the assumption at the top of the prototype.2122## Workflow rules that apply to both branches23241. **Isolate the prototype from the caller's work.** Build it on an isolated25 worktree or a clearly named throwaway branch. Never commit to, rebase, or26 otherwise alter the branch the user was on without their explicit approval.272. **Throwaway from day one, and clearly marked as such.** Name files and28 routes so a casual reader sees "prototype," and follow the project's29 existing conventions rather than inventing new top-level structure.303. **One command to run**, registered with the project's existing task runner31 (`package.json` scripts, `Makefile`, `justfile`, `pyproject.toml`); if there32 is none, put the command at the top of the prototype's README.334. **No persistence by default.** State lives in memory; persistence is the34 thing a prototype checks, not something it depends on. If the question35 explicitly involves a database, use a scratch store with a clear36 "PROTOTYPE — wipe me" name.375. **Skip the polish.** No tests, no error handling beyond runnability, no38 abstractions. The point is to learn something fast.396. **Surface the state.** After every action (logic) or on every variant switch40 (UI), show the full relevant state so the user sees what changed.417. **Capture it when done.** Fold the validated decision into the real code;42 keep the prototype itself as a primary source on its throwaway branch with a43 context pointer from the relevant issue or commit. The main branch keeps44 only the validated decision.4546## Logic branch — interactive terminal app4748State the question first — one paragraph at the top of the file or README; a49logic prototype that answers the wrong question is pure waste. Then:50511. **Use the host project's language and tooling.** No new runtimes or package52 managers for a prototype.532. **Isolate the logic behind a small pure interface** that could be lifted54 into the real codebase later — a pure reducer `(state, action) → state`, an55 explicit state machine when "which actions are legal right now" is part of56 the question, a set of pure functions over a plain data type, or a module57 with a clear method surface when the logic genuinely owns ongoing state.58 Pick the shape that fits the question, not the one easiest to wire to a59 terminal. No I/O or terminal code inside the logic module.603. **Wrap it in the smallest terminal shell that exposes the state**: on every61 action, clear the screen and re-render one stable frame — current state62 pretty-printed, then the keyboard shortcuts (`[a] add [t] tick [q] quit`).63 Read one keystroke, dispatch, re-render, loop until quit.644. **Hand the run command to the user.** The interesting moments are "wait,65 that shouldn't be possible" — bugs in the idea, which is the point. Add66 actions as they ask.675. **On resolution**, the validated logic module lifts into the real code; the68 terminal shell rides along to the throwaway branch as a primary source.6970Anti-patterns: adding tests; wiring to the real database; generalizing for71futures the question does not ask about; blurring logic and shell so the72module is no longer portable; shipping the shell toward production.7374## UI branch — radically different variants on one route7576Default to **3 variants**; more than 5 is noise. Two sub-shapes; strongly77prefer the first:7879- **Adjustment to an existing page** (preferred): render variants on the80 existing route, gated by a `?variant=` URL parameter — the page's real data,81 auth, and surroundings stay, only the rendering swaps. A new section that82 would naturally live inside an existing page is still this sub-shape.83- **A new page** (last resort): only when the surface genuinely has no home.84 Follow the project's routing conventions and name the route so it is85 obviously a prototype.8687Variants must be **structurally different** — different layout, information88hierarchy, primary affordance — not different colors. If two drafts come out89similar, redo one with explicit counter-guidance. Use the project's existing90component and styling system. A floating bottom bar switches variants.9192**Production-safe gate:** the entire variant mechanism — variant components,93switcher bar, and the `?variant=` handling — must be unreachable in production94builds: compile it out via the project's dev-mode conditionals, an explicitly95non-production route guard, or by keeping the prototype on its throwaway96branch. Gating only the switcher UI is not enough.9798## Attribution and license99100Derived from `skills/engineering/prototype/` (`SKILL.md`, `LOGIC.md`,101`UI.md`) in [mattpocock/skills](https://github.com/mattpocock/skills) at102commit `2ab958093e83e0ec752e6c1c5932da465bf23e0c`, adapted for this package103(worktree isolation, production-safe gating, inlined references). That104material is and remains MIT-licensed: Copyright (c) 2026 Matt Pocock.105Permission is hereby granted, free of charge, to any person obtaining a copy106of this software and associated documentation files (the "Software"), to deal107in the Software without restriction, including without limitation the rights108to use, copy, modify, merge, publish, distribute, sublicense, and/or sell109copies of the Software, and to permit persons to whom the Software is110furnished to do so, subject to the following conditions: The above copyright111notice and this permission notice shall be included in all copies or112substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS",113WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED114TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND115NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE116FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,117TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR118THE USE OR OTHER DEALINGS IN THE SOFTWARE.