fix(skills): align invocation and prose conventions
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
# Logic Prototype
|
# Logic Prototype
|
||||||
|
|
||||||
A 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.
|
A 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.
|
||||||
|
|
||||||
## When this is the right shape
|
## When this is the right shape
|
||||||
|
|
||||||
@@ -9,47 +10,65 @@ A tiny interactive terminal app that lets the user drive a state model by hand.
|
|||||||
- "I want to feel out what the API should look like before writing it."
|
- "I want to feel out what the API should look like before writing it."
|
||||||
- Anything where the user wants to **press buttons and watch state change**.
|
- Anything where the user wants to **press buttons and watch state change**.
|
||||||
|
|
||||||
If the question is "what should this look like" — wrong branch. Use [UI.md](UI.md).
|
If the question is "what should this look like" — wrong branch.
|
||||||
|
Use [UI.md](UI.md).
|
||||||
|
|
||||||
## Process
|
## Process
|
||||||
|
|
||||||
### 1. State the question
|
### 1. State the question
|
||||||
|
|
||||||
Before 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.
|
Before 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.
|
||||||
|
|
||||||
### 2. Pick the language
|
### 2. Pick the language
|
||||||
|
|
||||||
Use whatever the host project uses. If the project has no obvious runtime (e.g. a docs repo), ask.
|
Use whatever the host project uses.
|
||||||
|
If the project has no obvious runtime (e.g. a docs repo), ask.
|
||||||
|
|
||||||
Match the project's existing conventions for tooling — don't add a new package manager or runtime just for the prototype.
|
Match the project's existing conventions for tooling — don't add a new package manager or runtime just for the prototype.
|
||||||
|
|
||||||
### 3. Isolate the logic in a portable module
|
### 3. Isolate the logic in a portable module
|
||||||
|
|
||||||
Put 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.
|
Put 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.
|
||||||
|
|
||||||
The right shape depends on the question:
|
The right shape depends on the question:
|
||||||
|
|
||||||
- **A pure reducer** — `(state, action) => state`. Good when actions are discrete events and state is a single value.
|
- **A pure reducer** — `(state, action) => state`.
|
||||||
- **A state machine** — explicit states and transitions. Good when "which actions are even legal right now" is part of the question.
|
Good when actions are discrete events and state is a single value.
|
||||||
- **A small set of pure functions** over a plain data type. Good when there's no implicit current state — just transformations.
|
- **A state machine** — explicit states and transitions.
|
||||||
|
Good when "which actions are even legal right now" is part of the question.
|
||||||
|
- **A small set of pure functions** over a plain data type.
|
||||||
|
Good when there's no implicit current state — just transformations.
|
||||||
- **A class or module with a clear method surface** when the logic genuinely owns ongoing internal state.
|
- **A class or module with a clear method surface** when the logic genuinely owns ongoing internal state.
|
||||||
|
|
||||||
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.
|
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 on its own.
|
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
|
### 4. Build the smallest TUI that exposes the state
|
||||||
|
|
||||||
Build 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.
|
Build 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.
|
||||||
|
|
||||||
Each frame has two parts, in this order:
|
Each frame has two parts, in this order:
|
||||||
|
|
||||||
1. **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.
|
1. **Current state**, pretty-printed and diff-friendly (one field per line, or formatted JSON).
|
||||||
2. **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.
|
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.
|
||||||
|
2. **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.
|
||||||
|
|
||||||
Behaviour:
|
Behaviour:
|
||||||
|
|
||||||
1. **Initialise state** — a single in-memory object/struct. Render the first frame on start.
|
1. **Initialise state** — a single in-memory object/struct.
|
||||||
|
Render the first frame on start.
|
||||||
2. **Read one keystroke (or one line)** at a time, dispatch to a handler that mutates state.
|
2. **Read one keystroke (or one line)** at a time, dispatch to a handler that mutates state.
|
||||||
3. **Re-render** the full frame after every action — don't append, replace.
|
3. **Re-render** the full frame after every action — don't append, replace.
|
||||||
4. **Loop until quit.**
|
4. **Loop until quit.**
|
||||||
@@ -58,13 +77,18 @@ The whole frame should fit on one screen.
|
|||||||
|
|
||||||
### 5. Make it runnable in one command
|
### 5. Make it runnable in one command
|
||||||
|
|
||||||
Add 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.
|
Add 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.
|
||||||
|
|
||||||
If the host project has no task runner, just put the command at the top of the prototype's README.
|
If the host project has no task runner, just put the command at the top of the prototype's README.
|
||||||
|
|
||||||
### 6. Hand it over
|
### 6. Hand it over
|
||||||
|
|
||||||
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.
|
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 the prototype
|
### 7. Capture the answer and the prototype
|
||||||
|
|
||||||
@@ -75,8 +99,16 @@ The TUI shell rides along to the throwaway branch that keeps the prototype as a
|
|||||||
|
|
||||||
## Anti-patterns
|
## Anti-patterns
|
||||||
|
|
||||||
- **Don't add tests.** A prototype that needs tests is no longer a prototype.
|
- **Don't add tests.**
|
||||||
- **Don't wire it to the real database.** Use an in-memory store unless the question is specifically about persistence.
|
A prototype that needs tests is no longer a prototype.
|
||||||
- **Don't generalise.** No "what if we wanted to support X later." The prototype answers one question.
|
- **Don't wire it to the real database.**
|
||||||
- **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.
|
Use an in-memory store unless the question is specifically about persistence.
|
||||||
- **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.
|
- **Don't generalise.**
|
||||||
|
No "what if we wanted to support X later."
|
||||||
|
The prototype answers one question.
|
||||||
|
- **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.
|
||||||
|
- **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.
|
||||||
|
|||||||
@@ -5,22 +5,43 @@ description: Build a throwaway prototype to answer a design question. Use when t
|
|||||||
|
|
||||||
# Prototype
|
# Prototype
|
||||||
|
|
||||||
A prototype is **throwaway code that answers a question**. The question decides the shape.
|
A prototype is **throwaway code that answers a question**.
|
||||||
|
The question decides the shape.
|
||||||
|
|
||||||
## Pick a branch
|
## Pick a branch
|
||||||
|
|
||||||
Identify which question is being answered — from the user's prompt, the surrounding code, or by asking if the user is around:
|
Identify which question is being answered — from the user's prompt, the surrounding code, or by asking if the user is around:
|
||||||
|
|
||||||
- **"Does this logic / state model feel right?"** → [LOGIC.md](LOGIC.md). Build a tiny interactive terminal app that pushes the state machine through cases that are hard to reason about on paper.
|
- **"Does this logic / state model feel right?"** → [LOGIC.md](LOGIC.md).
|
||||||
- **"What should this look like?"** → [UI.md](UI.md). Generate several radically different UI variations on a single route, switchable via a URL search param and a floating bottom bar.
|
Build 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?"** → [UI.md](UI.md).
|
||||||
|
Generate several radically different UI variations on a single route, switchable via a URL search param and a floating bottom bar.
|
||||||
|
|
||||||
The two branches produce very different artifacts — getting this wrong wastes the whole prototype. If the question is genuinely ambiguous and the user isn't reachable, default to whichever branch better matches the surrounding code (a backend module → logic; a page or component → UI) and state the assumption at the top of the prototype.
|
The two branches produce very different artifacts — getting this wrong wastes the whole prototype.
|
||||||
|
If the question is genuinely ambiguous and the user isn't reachable, default to whichever branch better matches the surrounding code (a backend module → logic, a page or component → UI) and state the assumption at the top of the prototype.
|
||||||
|
|
||||||
## Rules that apply to both
|
## Rules that apply to both
|
||||||
|
|
||||||
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.
|
1. **Throwaway from day one, and clearly marked as such.**
|
||||||
2. **One command to run.** Whatever the project's existing task runner supports — `pnpm <name>`, `python <path>`, `bun <path>`, etc. The user must be able to start it without thinking.
|
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.
|
||||||
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.
|
For throwaway UI routes, obey whatever routing convention the project already uses.
|
||||||
4. **Skip the polish.** No tests, no error handling beyond what makes the prototype _runnable_, no abstractions. The point is to learn something fast.
|
Don't invent a new top-level structure.
|
||||||
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.
|
2. **One command to run.**
|
||||||
6. **Capture it when done.** When the caller permits implementation, fold any validated decision into the real code. A planning-only caller such as Wayfinder stops at the verdict. Commit the prototype itself to a throwaway branch, out of main, as a **primary source**. Write a Prototype artifact under `$(xdg-user-dir DOCUMENTS)/ai-artifacts/projects/<project>/`, where `<project>` is the lowercase basename of the current working directory, following the vault's `AGENTS.md`. Include the question, a context pointer to the branch, run instructions, and the verdict, plus screenshots and useful code snippets where they help preserve the result. The main branch keeps only a validated decision that the caller permitted the skill to fold in.
|
Whatever the project's existing task runner supports — `pnpm <name>`, `python <path>`, `bun <path>`, 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.
|
||||||
|
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.**
|
||||||
|
When the caller permits implementation, fold any validated decision into the real code.
|
||||||
|
A planning-only caller such as Wayfinder stops at the verdict.
|
||||||
|
Commit the prototype itself to a throwaway branch, out of main, as a **primary source**.
|
||||||
|
Write a Prototype artifact under `$(xdg-user-dir DOCUMENTS)/ai-artifacts/projects/<project>/`, where `<project>` is the lowercase basename of the current working directory, following the vault's `AGENTS.md`.
|
||||||
|
Include the question, a context pointer to the branch, run instructions, and the verdict, plus screenshots and useful code snippets where they help preserve the result.
|
||||||
|
The main branch keeps only a validated decision that the caller permitted the skill to fold in.
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
# UI Prototype
|
# UI Prototype
|
||||||
|
|
||||||
Generate **several radically different UI variations** on a single route, switchable from a floating bottom bar. The user flips between variants in the browser, picks one (or steals bits from each), then throws the rest away.
|
Generate **several radically different UI variations** on a single route, switchable from a floating bottom bar.
|
||||||
|
The user flips between variants in the browser, picks one (or steals bits from each), then throws the rest away.
|
||||||
|
|
||||||
If the question is about logic/state rather than what something looks like — wrong branch. Use [LOGIC.md](LOGIC.md).
|
If the question is about logic/state rather than what something looks like — wrong branch.
|
||||||
|
Use [LOGIC.md](LOGIC.md).
|
||||||
|
|
||||||
## When this is the right shape
|
## When this is the right shape
|
||||||
|
|
||||||
@@ -13,21 +15,32 @@ If the question is about logic/state rather than what something looks like — w
|
|||||||
|
|
||||||
## Two sub-shapes — strongly prefer sub-shape A
|
## Two sub-shapes — strongly prefer sub-shape A
|
||||||
|
|
||||||
A UI prototype is much easier to judge when it's **butting up against the rest of the app** — real header, real sidebar, real data, real density. A throwaway route on its own is a vacuum: every variant looks fine in isolation. Default to sub-shape A whenever there's a plausible existing page to host the variants. Only reach for sub-shape B if the prototype genuinely has no nearby home.
|
A UI prototype is much easier to judge when it's **butting up against the rest of the app** — real header, real sidebar, real data, real density.
|
||||||
|
A throwaway route on its own is a vacuum: every variant looks fine in isolation.
|
||||||
|
Default to sub-shape A whenever there's a plausible existing page to host the variants.
|
||||||
|
Only reach for sub-shape B if the prototype genuinely has no nearby home.
|
||||||
|
|
||||||
### Sub-shape A — adjustment to an existing page (preferred)
|
### Sub-shape A — adjustment to an existing page (preferred)
|
||||||
|
|
||||||
The route already exists. Variants are rendered **on the same route**, gated by a `?variant=` URL search param. The existing data fetching, params, and auth all stay — only the rendering swaps. This is the default; pick it unless there's a specific reason not to.
|
The route already exists.
|
||||||
|
Variants are rendered **on the same route**, gated by a `?variant=` URL search param.
|
||||||
|
The existing data fetching, params, and auth all stay — only the rendering swaps.
|
||||||
|
This is the default.
|
||||||
|
Pick it unless there's a specific reason not to.
|
||||||
|
|
||||||
If the prototype is for something that doesn't yet have a page but *would naturally live inside one* (a new section of the dashboard, a new card on the settings screen, a new step in an existing flow) — that's still sub-shape A. Mount the variants inside the host page.
|
If the prototype is for something that doesn't yet have a page but *would naturally live inside one* (a new section of the dashboard, a new card on the settings screen, a new step in an existing flow) — that's still sub-shape A.
|
||||||
|
Mount the variants inside the host page.
|
||||||
|
|
||||||
### Sub-shape B — a new page (last resort)
|
### Sub-shape B — a new page (last resort)
|
||||||
|
|
||||||
Only use this when the thing being prototyped genuinely has no existing page to live inside — e.g. an entirely new top-level surface, or a flow that can't be embedded anywhere sensible.
|
Only use this when the thing being prototyped genuinely has no existing page to live inside — e.g. an entirely new top-level surface, or a flow that can't be embedded anywhere sensible.
|
||||||
|
|
||||||
Create a **throwaway route** following whatever routing convention the project already uses — don't invent a new top-level structure. Name it so it's obviously a prototype (e.g. include the word `prototype` in the path or filename). Same `?variant=` pattern.
|
Create a **throwaway route** following whatever routing convention the project already uses — don't invent a new top-level structure.
|
||||||
|
Name it so it's obviously a prototype (e.g. include the word `prototype` in the path or filename).
|
||||||
|
Same `?variant=` pattern.
|
||||||
|
|
||||||
Before committing to sub-shape B, sanity-check: is there really no existing page this could be embedded in? An empty route hides design problems that a populated one would expose.
|
Before committing to sub-shape B, sanity-check: is there really no existing page this could be embedded in?
|
||||||
|
An empty route hides design problems that a populated one would expose.
|
||||||
|
|
||||||
In both sub-shapes the floating bottom bar is identical.
|
In both sub-shapes the floating bottom bar is identical.
|
||||||
|
|
||||||
@@ -35,7 +48,8 @@ In both sub-shapes the floating bottom bar is identical.
|
|||||||
|
|
||||||
### 1. State the question and pick N
|
### 1. State the question and pick N
|
||||||
|
|
||||||
Default to **3 variants**. More than 5 stops being radically different and starts being noise — cap there.
|
Default to **3 variants**.
|
||||||
|
More than 5 stops being radically different and starts being noise — cap there.
|
||||||
|
|
||||||
Write down the plan in one line, in the prototype's location or a top-of-file comment:
|
Write down the plan in one line, in the prototype's location or a top-of-file comment:
|
||||||
|
|
||||||
@@ -45,13 +59,16 @@ This works whether the user is here to push back or not.
|
|||||||
|
|
||||||
### 2. Generate radically different variants
|
### 2. Generate radically different variants
|
||||||
|
|
||||||
Draft each variant. Hold each one to:
|
Draft each variant.
|
||||||
|
Hold each one to:
|
||||||
|
|
||||||
- The page's purpose and the data it has access to.
|
- The page's purpose and the data it has access to.
|
||||||
- The project's component library / styling system (TailwindCSS, shadcn, MUI, plain CSS, whatever).
|
- The project's component library / styling system (TailwindCSS, shadcn, MUI, plain CSS, whatever).
|
||||||
- A clear exported component name, e.g. `VariantA`, `VariantB`, `VariantC`.
|
- A clear exported component name, e.g. `VariantA`, `VariantB`, `VariantC`.
|
||||||
|
|
||||||
Variants must be **structurally different** — different layout, different information hierarchy, different primary affordance, not just different colours. Three slightly-tweaked card grids isn't a UI prototype, it's wallpaper. If two drafts come out too similar, redo one with explicit "do not use a card grid" guidance.
|
Variants must be **structurally different** — different layout, different information hierarchy, different primary affordance, not just different colours.
|
||||||
|
Three slightly-tweaked card grids isn't a UI prototype, it's wallpaper.
|
||||||
|
If two drafts come out too similar, redo one with explicit "do not use a card grid" guidance.
|
||||||
|
|
||||||
### 3. Wire them together
|
### 3. Wire them together
|
||||||
|
|
||||||
@@ -70,7 +87,8 @@ return (
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
For sub-shape A (existing page): keep all the existing data fetching above the switcher; only the rendered subtree changes per variant.
|
For sub-shape A (existing page): keep all the existing data fetching above the switcher.
|
||||||
|
Only the rendered subtree changes per variant.
|
||||||
|
|
||||||
For sub-shape B (new page): the throwaway route under `/prototype/<name>` mounts the same switcher.
|
For sub-shape B (new page): the throwaway route under `/prototype/<name>` mounts the same switcher.
|
||||||
|
|
||||||
@@ -85,15 +103,19 @@ A small fixed-position bar at the bottom-centre of the screen with three pieces:
|
|||||||
Behaviour:
|
Behaviour:
|
||||||
|
|
||||||
- Clicking an arrow updates the URL search param (use the framework's router — `router.replace` on Next, `navigate` on React Router, etc) so the variant is shareable and reload-stable.
|
- Clicking an arrow updates the URL search param (use the framework's router — `router.replace` on Next, `navigate` on React Router, etc) so the variant is shareable and reload-stable.
|
||||||
- Keyboard: `←` and `→` arrow keys also cycle. Don't intercept arrow keys when an `<input>`, `<textarea>`, or `[contenteditable]` is focused.
|
- Keyboard: `←` and `→` arrow keys also cycle.
|
||||||
|
Don't intercept arrow keys when an `<input>`, `<textarea>`, or `[contenteditable]` is focused.
|
||||||
- Visually distinct from the page (e.g. high-contrast pill, subtle shadow) so it's obviously not part of the design being evaluated.
|
- Visually distinct from the page (e.g. high-contrast pill, subtle shadow) so it's obviously not part of the design being evaluated.
|
||||||
- Hidden in production builds — gate on `process.env.NODE_ENV !== 'production'` or an equivalent check, so a stray prototype merge can't ship the bar to users.
|
- Hidden in production builds — gate on `process.env.NODE_ENV !== 'production'` or an equivalent check, so a stray prototype merge can't ship the bar to users.
|
||||||
|
|
||||||
Put the switcher in a single shared component so both sub-shapes can reuse it. Locate it wherever shared UI lives in the project.
|
Put the switcher in a single shared component so both sub-shapes can reuse it.
|
||||||
|
Locate it wherever shared UI lives in the project.
|
||||||
|
|
||||||
### 5. Hand it over
|
### 5. Hand it over
|
||||||
|
|
||||||
Surface the URL (and the `?variant=` keys). The user will flip through whenever they get to it. The interesting feedback is usually **"I want the header from B with the sidebar from C"** — that's the actual design they want.
|
Surface the URL (and the `?variant=` keys).
|
||||||
|
The user will flip through whenever they get to it.
|
||||||
|
The interesting feedback is usually **"I want the header from B with the sidebar from C"** — that's the actual design they want.
|
||||||
|
|
||||||
### 6. Capture the answer and clean up
|
### 6. Capture the answer and clean up
|
||||||
|
|
||||||
@@ -108,7 +130,16 @@ The full set of variants is the primary source, so it lands on the throwaway bra
|
|||||||
|
|
||||||
## Anti-patterns
|
## Anti-patterns
|
||||||
|
|
||||||
- **Variants that differ only in colour or copy.** That's a tweak, not a prototype. Real variants disagree about structure.
|
- **Variants that differ only in colour or copy.**
|
||||||
- **Sharing too much code between variants.** A shared `<Header>` is fine; a shared `<Layout>` defeats the point. Each variant should be free to throw out the layout.
|
That's a tweak, not a prototype.
|
||||||
- **Wiring variants to real mutations.** Read-only prototypes are fine. If a variant needs to mutate, point it at a stub — the question is "what should this look like", not "does the backend work".
|
Real variants disagree about structure.
|
||||||
- **Promoting the prototype directly to production.** The variant code was written under prototype constraints (no tests, minimal error handling). Rewrite it properly when you fold it in.
|
- **Sharing too much code between variants.**
|
||||||
|
A shared `<Header>` is fine.
|
||||||
|
A shared `<Layout>` defeats the point.
|
||||||
|
Each variant should be free to throw out the layout.
|
||||||
|
- **Wiring variants to real mutations.**
|
||||||
|
Read-only prototypes are fine.
|
||||||
|
If a variant needs to mutate, point it at a stub — the question is "what should this look like", not "does the backend work".
|
||||||
|
- **Promoting the prototype directly to production.**
|
||||||
|
The variant code was written under prototype constraints (no tests, minimal error handling).
|
||||||
|
Rewrite it properly when you fold it in.
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ Spin up a **background agent** to do the research, so you keep working while it
|
|||||||
|
|
||||||
Its job:
|
Its job:
|
||||||
|
|
||||||
1. Investigate the question against **primary sources** — official docs, source code, specs, first-party APIs — not a secondary write-up of them. Follow every claim back to the source that owns it.
|
1. Investigate the question against **primary sources** — official docs, source code, specs, first-party APIs — not a secondary write-up of them.
|
||||||
|
Follow every claim back to the source that owns it.
|
||||||
2. Write the findings to a single Markdown file, citing each claim's source.
|
2. Write the findings to a single Markdown file, citing each claim's source.
|
||||||
3. Save it under `$(xdg-user-dir DOCUMENTS)/ai-artifacts/projects/<project>/`, where `<project>` is the lowercase basename of the current working directory. Read the vault's `AGENTS.md` and follow its artifact conventions.
|
3. Save it under `$(xdg-user-dir DOCUMENTS)/ai-artifacts/projects/<project>/`, where `<project>` is the lowercase basename of the current working directory.
|
||||||
|
Read the vault's `AGENTS.md` and follow its artifact conventions.
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ An effort may explicitly permit execution in its Notes, but otherwise preserve r
|
|||||||
Every ticket is either **HITL**, worked through a live exchange with the human, or **AFK**, driven by the agent.
|
Every ticket is either **HITL**, worked through a live exchange with the human, or **AFK**, driven by the agent.
|
||||||
A HITL ticket never resolves by having the agent speak for the human.
|
A HITL ticket never resolves by having the agent speak for the human.
|
||||||
|
|
||||||
- **Research** (AFK): Investigate knowledge outside the current working directory through `/research`.
|
- **Research** (AFK): Investigate knowledge outside the current working directory through the `research` skill.
|
||||||
- **Prototype** (HITL): Create concrete Logic or UI code to react to through `/prototype`.
|
- **Prototype** (HITL): Create concrete Logic or UI code to react to through the `prototype` skill.
|
||||||
Within Wayfinder, stop at the verdict rather than folding the result into production.
|
Within Wayfinder, stop at the verdict rather than folding the result into production.
|
||||||
- **Grill** (HITL): Resolve a decision through `/grill`.
|
- **Grill** (HITL): Resolve a decision through the `grill` skill.
|
||||||
This is the default ticket type.
|
This is the default ticket type.
|
||||||
- **Task** (AFK or HITL): Perform prerequisite work that must happen before a decision can be made.
|
- **Task** (AFK or HITL): Perform prerequisite work that must happen before a decision can be made.
|
||||||
The required capability is specific to the action.
|
The required capability is specific to the action.
|
||||||
@@ -56,17 +56,17 @@ Never resolve more than one non-Research ticket in a session.
|
|||||||
## Chart the map
|
## Chart the map
|
||||||
|
|
||||||
1. **Name the destination.**
|
1. **Name the destination.**
|
||||||
Invoke `/grill` to settle what reaching the end of this effort looks like.
|
Invoke `grill` to settle what reaching the end of this effort looks like.
|
||||||
Done when the destination states the spec, decision, or change the map is finding its way toward and fixes its scope.
|
Done when the destination states the spec, decision, or change the map is finding its way toward and fixes its scope.
|
||||||
2. **Map breadth-first.**
|
2. **Map breadth-first.**
|
||||||
Invoke `/grill` again to fan out across the whole space, identifying precise open questions, blocking relationships, and fog without drilling into any one answer.
|
Invoke `grill` again to fan out across the whole space, identifying precise open questions, blocking relationships, and fog without drilling into any one answer.
|
||||||
If this surfaces no fog and the route fits one session, stop and ask how the user wants to proceed instead of creating a map.
|
If this surfaces no fog and the route fits one session, stop and ask how the user wants to proceed instead of creating a map.
|
||||||
Done when every visible in-scope uncertainty is either a precise ticket question or an honest fog entry.
|
Done when every visible in-scope uncertainty is either a precise ticket question or an honest fog entry.
|
||||||
3. **Create the map and tickets.**
|
3. **Create the map and tickets.**
|
||||||
Create the map first, then every currently precise ticket, then wire `blocked-by` relationships in a second pass according to `ARTIFACTS.md`.
|
Create the map first, then every currently precise ticket, then wire `blocked-by` relationships in a second pass according to `ARTIFACTS.md`.
|
||||||
Done when the map is the effort root, every precise question has one ticket, every known blocking edge is represented, and the Frontier is current.
|
Done when the map is the effort root, every precise question has one ticket, every known blocking edge is represented, and the Frontier is current.
|
||||||
4. **Dispatch Research.**
|
4. **Dispatch Research.**
|
||||||
Invoke `/research` for each Research ticket using whatever isolation or concurrency the caller provides.
|
Invoke `research` for each Research ticket using whatever isolation or concurrency the caller provides.
|
||||||
Let the coordinating Wayfinder agent integrate returned Research artifacts according to `ARTIFACTS.md`.
|
Let the coordinating Wayfinder agent integrate returned Research artifacts according to `ARTIFACTS.md`.
|
||||||
Done when every dispatched Research result has been integrated or every Research ticket that could not run remains open with the reason visible.
|
Done when every dispatched Research result has been integrated or every Research ticket that could not run remains open with the reason visible.
|
||||||
5. Stop without resolving a HITL ticket.
|
5. Stop without resolving a HITL ticket.
|
||||||
@@ -81,7 +81,7 @@ Never resolve more than one non-Research ticket in a session.
|
|||||||
Persist the claim before doing its work.
|
Persist the claim before doing its work.
|
||||||
Done when exactly one open, unblocked ticket records this session's claim.
|
Done when exactly one open, unblocked ticket records this session's claim.
|
||||||
3. **Resolve by type.**
|
3. **Resolve by type.**
|
||||||
Invoke `/research`, `/prototype`, or `/grill` for those ticket types.
|
Invoke `research`, `prototype`, or `grill` for those ticket types.
|
||||||
Perform a Task through the capability or human checklist it requires.
|
Perform a Task through the capability or human checklist it requires.
|
||||||
Zoom into related artifacts only as needed rather than loading the whole effort.
|
Zoom into related artifacts only as needed rather than loading the whole effort.
|
||||||
Done when the ticket's question has a resolution or the prerequisite Task is complete.
|
Done when the ticket's question has a resolution or the prerequisite Task is complete.
|
||||||
|
|||||||
Reference in New Issue
Block a user