cli · v0.1.1
Skills / prototype/logic
Fixture. This page is the stdout of wayfinder skill prototype/logic, run against a config with tracker value github cli and two registered ticket skills (grill-design, pre-mortem). Change either and this render changes with it.
A supporting file. prototype/logic is disclosed by prototype, which is where an agent is told to fetch it. It carries no station of its own on the route.
$ wayfinder skill prototype/logic79 lines
1# Logic Prototype
2
3A tiny interactive terminal app that lets the user drive a state model by hand. Use this when the question is about **business logic, state transitions, or data shape** — the kind of thing that looks reasonable on paper but only feels wrong once you push it through real cases.
4
5## When this is the right shape
6
7- "I'm not sure if this state machine handles the edge case where X then Y."
8- "Does this data model actually let me represent the case where..."
9- "I want to feel out what the API should look like before writing it."
10- Anything where the user wants to **press buttons and watch state change**.
11
12If the question is "what should this look like" — wrong branch. Use [UI.md](UI.md).
13
14## Process
15
16### 1. State the question
17
18Before writing code, write down what state model and what question you're prototyping. One paragraph, in the prototype's README or a comment at the top of the file. A logic prototype that answers the wrong question is pure waste — make the question explicit so it can be checked later, whether the user is watching now or returning to it AFK.
19
20### 2. Pick the language
21
22Use whatever the host project uses. If the project has no obvious runtime (e.g. a docs repo), ask.
23
24Match the project's existing conventions for tooling — don't add a new package manager or runtime just for the prototype.
25
26### 3. Isolate the logic in a portable module
27
28Put the actual logic — the bit that's answering the question — behind a small, pure interface that could be lifted out and dropped into the real codebase later. The TUI around it is throwaway; the logic module shouldn't be.
29
30The right shape depends on the question:
31
32- **A pure reducer** — `(state, action) => state`. Good when actions are discrete events and state is a single value.
33- **A state machine** — explicit states and transitions. Good when "which actions are even legal right now" is part of the question.
34- **A small set of pure functions** over a plain data type. Good when there's no implicit current state — just transformations.
35- **A class or module with a clear method surface** when the logic genuinely owns ongoing internal state.
36
37Pick 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.
38
39This 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.
40
41### 4. Build the smallest TUI that exposes the state
42
43Build it as a **lightweight TUI** — on every tick, clear the screen (`console.clear()` / `print("\033[2J\033[H")` / equivalent) and re-render the whole frame. The user should always see one stable view, not an ever-growing scrollback.
44
45Each frame has two parts, in this order:
46
471. **Current state**, pretty-printed and diff-friendly (one field per line, or formatted JSON). Use **bold** for field names or section headers and **dim** for less important context (timestamps, IDs, derived values). Native ANSI escape codes are fine — `\x1b[1m` bold, `\x1b[2m` dim, `\x1b[0m` reset. No need to pull in a styling library unless one is already in the project.
482. **Keyboard shortcuts**, listed at the bottom: `[a] add user [d] delete user [t] tick clock [q] quit`. Bold the key, dim the description, or vice-versa — whatever reads cleanly.
49
50Behaviour:
51
521. **Initialise state** — a single in-memory object/struct. Render the first frame on start.
532. **Read one keystroke (or one line)** at a time, dispatch to a handler that mutates state.
543. **Re-render** the full frame after every action — don't append, replace.
554. **Loop until quit.**
56
57The whole frame should fit on one screen.
58
59### 5. Make it runnable in one command
60
61Add a script to the project's existing task runner (`package.json` scripts, `Makefile`, `justfile`, `pyproject.toml`). The user should run `pnpm run <prototype-name>` or equivalent — never need to remember a path.
62
63If the host project has no task runner, just put the command at the top of the prototype's README.
64
65### 6. Hand it over
66
67Give 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.
68
69### 7. Capture the answer and the prototype
70
71Once 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.
72
73## Anti-patterns
74
75- **Don't add tests.** A prototype that needs tests is no longer a prototype.
76- **Don't wire it to the real database.** Use an in-memory store unless the question is specifically about persistence.
77- **Don't generalise.** No "what if we wanted to support X later." The prototype answers one question.
78- **Don't blur the logic and the TUI together.** If the reducer / state machine references `console.log`, prompts, or terminal escape codes, it's no longer portable. Keep the TUI as a thin shell over a pure module.
79- **Don't ship the TUI shell into production.** The shell is optimised for being driven by hand from a terminal. The logic module behind it is the bit worth keeping.