From 0d74d01cbc64ca27778a49b38599f70c534e76a0 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Wed, 1 Jul 2026 16:32:15 +0100 Subject: [PATCH 01/36] feat: add the research skill A small, model-invoked skill that spins up a background agent to investigate a question against high-trust primary sources, then leaves a single cited Markdown file wherever the repo keeps such notes. Wires it into the plugin set, both READMEs (Model-invoked), a docs page, and the ask-matt router, per the repo's promoted-skill conventions. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/research-skill.md | 5 +++++ .claude-plugin/plugin.json | 1 + README.md | 1 + docs/engineering/research.md | 29 ++++++++++++++++++++++++++++ skills/engineering/README.md | 1 + skills/engineering/ask-matt/SKILL.md | 1 + skills/engineering/research/SKILL.md | 12 ++++++++++++ 7 files changed, 50 insertions(+) create mode 100644 .changeset/research-skill.md create mode 100644 docs/engineering/research.md create mode 100644 skills/engineering/research/SKILL.md diff --git a/.changeset/research-skill.md b/.changeset/research-skill.md new file mode 100644 index 0000000..f88cda7 --- /dev/null +++ b/.changeset/research-skill.md @@ -0,0 +1,5 @@ +--- +"mattpocock-skills": minor +--- + +Add the **`research`** skill — a small, model-invoked skill that spins up a **background agent** to investigate a question against **primary sources** (official docs, source code, specs, first-party APIs), then leaves a single cited Markdown file wherever the repo keeps such notes. It's delegable reading legwork: you keep working while it reads, and get back a document to grill, plan, or design against. Listed in the top-level and Engineering READMEs (Model-invoked), added to `.claude-plugin/plugin.json`, given a docs page at `docs/engineering/research.md`, and routed as a Standalone in `ask-matt`. diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 9c26f64..3155eb9 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -11,6 +11,7 @@ "./skills/engineering/to-issues", "./skills/engineering/to-prd", "./skills/engineering/prototype", + "./skills/engineering/research", "./skills/engineering/domain-modeling", "./skills/engineering/codebase-design", "./skills/engineering/code-review", diff --git a/README.md b/README.md index d463026..fe6a0ec 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,7 @@ Skills I use daily for code work. - **[prototype](./skills/engineering/prototype/SKILL.md)** — Build a throwaway prototype to answer a design question — a runnable terminal app for state/logic questions, or several radically different UI variations toggleable from one route. - **[diagnosing-bugs](./skills/engineering/diagnosing-bugs/SKILL.md)** — Disciplined diagnosis loop for hard bugs and performance regressions: reproduce → minimise → hypothesise → instrument → fix → regression-test. +- **[research](./skills/engineering/research/SKILL.md)** — Investigate a question against high-trust primary sources and capture the findings as a cited Markdown file in the repo, run as a background agent. - **[tdd](./skills/engineering/tdd/SKILL.md)** — Test-driven development with a red-green-refactor loop. Builds features or fixes bugs one vertical slice at a time. - **[domain-modeling](./skills/engineering/domain-modeling/SKILL.md)** — Actively build and sharpen a project's domain model — challenge terms against the glossary, stress-test with edge-case scenarios, and update `CONTEXT.md` and ADRs inline. - **[codebase-design](./skills/engineering/codebase-design/SKILL.md)** — Shared discipline and vocabulary for designing deep modules: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. diff --git a/docs/engineering/research.md b/docs/engineering/research.md new file mode 100644 index 0000000..308765c --- /dev/null +++ b/docs/engineering/research.md @@ -0,0 +1,29 @@ +Quickstart: + +```bash +npx skills add mattpocock/skills --skill=research +``` + +```bash +npx skills update research +``` + +[Source](https://github.com/mattpocock/skills/tree/main/skills/engineering/research) + +## What it does + +`research` answers a question by reading the sources that own the answer and leaving a cited Markdown file behind. It works only from **primary sources** — official docs, source code, specs, first-party APIs — never a secondary write-up of them, so what it saves is traceable back to something authoritative rather than a summary of a summary. + +## When to reach for it + +Type `/research`, or the agent reaches for it automatically when a task turns into reading legwork. + +Reach for it when the next step is *finding something out* — how an API behaves, what a spec actually says, whether a claim holds — and you'd rather not stall your own thread doing the reading. For sharpening a plan by interview instead of by reading, use [grilling](https://aihero.dev/skills-grilling); for exploring what to build with throwaway code, use [prototype](https://aihero.dev/skills-prototype). + +## Delegated legwork + +The defining move is that the reading runs as a **background agent**. You keep working; it goes off, follows each claim back to its primary source, and drops a single cited Markdown file into wherever the repo keeps such notes. Research is legwork you delegate, not thinking you outsource — you get back a document to react to, with its sources attached. + +## Where it fits + +A reach-for-it-anytime standalone that feeds the thinking skills: the file it produces is something to grill, plan, or design against, so it sits upstream of work like [grilling](https://aihero.dev/skills-grilling) and [to-prd](https://aihero.dev/skills-to-prd) rather than in the build chain. For the whole map, see [ask-matt](https://aihero.dev/skills-ask-matt). diff --git a/skills/engineering/README.md b/skills/engineering/README.md index dd4e218..2c123f4 100644 --- a/skills/engineering/README.md +++ b/skills/engineering/README.md @@ -21,6 +21,7 @@ Model- or user-reachable (rich trigger phrasing so the model can reach for them) - **[prototype](./prototype/SKILL.md)** — Build a throwaway prototype to answer a design question: a runnable terminal app for state/logic, or several toggleable UI variations. - **[diagnosing-bugs](./diagnosing-bugs/SKILL.md)** — Disciplined diagnosis loop for hard bugs and performance regressions: reproduce → minimise → hypothesise → instrument → fix → regression-test. +- **[research](./research/SKILL.md)** — Investigate a question against high-trust primary sources and capture the findings as a cited Markdown file in the repo, run as a background agent. - **[tdd](./tdd/SKILL.md)** — Test-driven development with a red-green-refactor loop. Builds features or fixes bugs one vertical slice at a time. - **[domain-modeling](./domain-modeling/SKILL.md)** — Actively build and sharpen a project's domain model — challenge terms, stress-test with scenarios, update `CONTEXT.md` and ADRs inline. - **[codebase-design](./codebase-design/SKILL.md)** — Shared discipline and vocabulary for designing deep modules: small interfaces, clean seams, testable through the interface. diff --git a/skills/engineering/ask-matt/SKILL.md b/skills/engineering/ask-matt/SKILL.md index 84a0105..f19a17c 100644 --- a/skills/engineering/ask-matt/SKILL.md +++ b/skills/engineering/ask-matt/SKILL.md @@ -65,6 +65,7 @@ Off the main flow entirely. - **`/grill-me`** — the same relentless interview as `/grill-with-docs`, but for when you have **no codebase**. Stateless: it saves nothing locally, builds no `CONTEXT.md`. Reach for it to sharpen any plan or design that doesn't live in a repo. - **`/prototype`** — a small, throwaway program that answers one design question: does this state model feel right, or what should this UI look like. Throwaway from day one — keep the answer, delete the code. It's the detour in step 2 of the main flow, but reach for it any time a design question is hard to settle on paper. +- **`/research`** — delegate reading legwork to a **background agent**: it investigates a question against **primary sources**, then leaves a cited Markdown file in the repo. Keep working while it reads. The file it produces is something to take *into* the main flow at `/grill-with-docs` — research feeds the thinking, it doesn't replace it. - **`/teach`** — learn a concept over multiple sessions, using the current directory as a stateful workspace. - **`/writing-great-skills`** — reference for writing and editing skills well. diff --git a/skills/engineering/research/SKILL.md b/skills/engineering/research/SKILL.md new file mode 100644 index 0000000..0ba594a --- /dev/null +++ b/skills/engineering/research/SKILL.md @@ -0,0 +1,12 @@ +--- +name: research +description: Investigate a question against high-trust primary sources and capture the findings as a Markdown file in the repo. Use when the user wants a topic researched, docs or API facts gathered, or reading legwork delegated to a background agent. +--- + +Spin up a **background agent** to do the research, so you keep working while it reads. + +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. +2. Write the findings to a single Markdown file, citing each claim's source. +3. Save it where the repo already keeps such notes; match the existing convention, and if there is none, put it somewhere sensible and say where. From a5c124ef9cfecc39636f426cc4ff956580d6ea10 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 2 Jul 2026 11:01:48 +0100 Subject: [PATCH 02/36] Made wayfinder model-invocable --- skills/in-progress/wayfinder/SKILL.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 158a731..17b356d 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -1,7 +1,6 @@ --- name: wayfinder description: Chart a route through a foggy problem — turn a loose idea into a shared map of investigation tickets on your issue tracker, and resolve them one at a time until the way to the goal is clear. -disable-model-invocation: true --- A loose idea has arrived — too big for one agent session, and wrapped in fog: the route from here to a plan isn't visible yet. This skill charts it as a **shared map** on the repo's issue tracker, then works its tickets one at a time. The map is domain-agnostic — engineering work, course content, whatever fits the shape. @@ -12,7 +11,7 @@ The map is a single issue on this repo's issue tracker, labelled `wayfinder:map` The map is an **index**, not a store. It lists the decisions made and points at the tickets that hold their detail; a decision lives in exactly one place — its ticket — so the map never restates it, only gists it and links. -**Where the map, its child tickets, blocking, and frontier queries physically live is tracker-specific.** Consult `docs/agents/issue-tracker.md` (the "Wayfinding operations" section) for how *this* repo expresses them. If that doc is absent, default to the local-markdown tracker. +**Where the map, its child tickets, blocking, and frontier queries physically live is tracker-specific.** Consult `docs/agents/issue-tracker.md` (the "Wayfinding operations" section) for how _this_ repo expresses them. If that doc is absent, default to the local-markdown tracker. ### The map body @@ -20,13 +19,17 @@ The whole map at low resolution, loaded once per session. Open tickets are **not ```markdown ## Notes + ## Decisions so far + -- []() — + +- [](link) — ## Fog + ``` @@ -36,6 +39,7 @@ Each ticket is a **child issue** of the map; the tracker's issue id is its ident ```markdown ## Question + ``` @@ -103,11 +107,13 @@ End every session with a **Next steps** block the user can copy-paste. Two cases > **Next steps** — 3 tickets unblocked. Clear the context, then open fresh sessions. > > **One session** — resolves the next unblocked ticket: +> > ``` > Invoke /wayfinder with the map . > ``` > > **Parallel** — paste one line per window, up to all 3: +> > ``` > Invoke /wayfinder with the map , ticket . > Invoke /wayfinder with the map , ticket . From f8d12710f78752bd720e274b600d926574bb647f Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 2 Jul 2026 11:22:35 +0100 Subject: [PATCH 03/36] Add claude-handoff skill (in-progress) User-invoked skill mirroring handoff, but hands the conversation summary to a fresh background agent via `claude --bg` instead of saving a markdown document. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/claude-handoff/SKILL.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 skills/in-progress/claude-handoff/SKILL.md diff --git a/skills/in-progress/claude-handoff/SKILL.md b/skills/in-progress/claude-handoff/SKILL.md new file mode 100644 index 0000000..0e25b18 --- /dev/null +++ b/skills/in-progress/claude-handoff/SKILL.md @@ -0,0 +1,18 @@ +--- +name: claude-handoff +description: Hand off the current conversation to a fresh background agent that picks up the work immediately. +argument-hint: "What will the next session be used for?" +disable-model-invocation: true +--- + +Compose a handoff summarising the current conversation so a fresh agent can continue the work, then launch it as a background agent seeded with that summary — do not save a document. + +Launch with `claude --bg ""`, passing the summary as the prompt. It starts in the current working directory and returns immediately; the user manages it with `claude agents`. + +Include a "suggested skills" section in the summary, instructing the agent which skills to invoke. + +Do not duplicate content already captured in other artifacts (PRDs, plans, ADRs, issues, commits, diffs). Reference them by path or URL instead. + +Redact any sensitive information, such as API keys, passwords, or personally identifiable information — it becomes the agent's prompt. + +If the user passed arguments, treat them as a description of what the next session will focus on and tailor the summary accordingly. From ee014fa8b13939195e0fe4f4c6310b5737569338 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 2 Jul 2026 11:23:55 +0100 Subject: [PATCH 04/36] wayfinder: refer to maps and tickets by name, not id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a "Refer by name" convention so Wayfinder surfaces maps and tickets by their human-friendly title in everything the human reads (narration, Decisions-so-far, Handoff) rather than bare ids, numbers, or slugs — a wall of #42, #43, #44 is illegible; names read at a glance. The id/URL stays the identity and pasteable handle, riding inside the name's link. Update the Handoff example to demonstrate it: name the map in the header and annotate each parallel command with its ticket name. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/wayfinder/SKILL.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 17b356d..a70895a 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -5,6 +5,10 @@ description: Chart a route through a foggy problem — turn a loose idea into a A loose idea has arrived — too big for one agent session, and wrapped in fog: the route from here to a plan isn't visible yet. This skill charts it as a **shared map** on the repo's issue tracker, then works its tickets one at a time. The map is domain-agnostic — engineering work, course content, whatever fits the shape. +## Refer by name + +Every map and ticket is an issue, so it has a **name** — its title. In everything the human reads — narration, the map's Decisions-so-far, the Handoff — refer to it by that name, never by a bare id, number, or slug. A wall of `#42, #43, #44` is illegible at a glance; names read instantly. The id and URL stay the identity: the link a name wraps, the pasteable handle in a command — they ride *inside* the name, never stand in for it. + ## The Map The map is a single issue on this repo's issue tracker, labelled `wayfinder:map` — the canonical artifact. Its tickets are child issues of the map. @@ -104,7 +108,7 @@ End every session with a **Next steps** block the user can copy-paste. Two cases **Open tickets remain.** Query the map for the currently-unblocked children, then give two copy-paste options: a bare command for one session (you pick the next ticket), and one pinned command per unblocked ticket for running them in parallel. Paste one line per fresh window — opening one, some, or all of them. -> **Next steps** — 3 tickets unblocked. Clear the context, then open fresh sessions. +> **Next steps** — *Briefing pipeline*: 3 tickets unblocked. Clear the context, then open fresh sessions. > > **One session** — resolves the next unblocked ticket: > @@ -112,12 +116,12 @@ End every session with a **Next steps** block the user can copy-paste. Two cases > Invoke /wayfinder with the map . > ``` > -> **Parallel** — paste one line per window, up to all 3: +> **Parallel** — paste one line per window, up to all 3 (trailing name orients you; it's ignored on paste): > > ``` -> Invoke /wayfinder with the map , ticket . -> Invoke /wayfinder with the map , ticket . -> Invoke /wayfinder with the map , ticket . +> Invoke /wayfinder with the map , ticket . # Reciprocity filter +> Invoke /wayfinder with the map , ticket . # TTS chunking +> Invoke /wayfinder with the map , ticket . # Voice selection > ``` **No open tickets remain.** The fog is pushed back far enough that the way to the goal is clear — the map is done. (The initial grilling may also surface no fog at all, in which case there was never a map to chart.) Recommend implementing directly, or using `/to-prd` to schedule a multi-session implementation. From 8f3401d1a17ab65e92b18a6ad9d301e9addf135f Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 2 Jul 2026 11:24:51 +0100 Subject: [PATCH 05/36] claude-handoff: reuse original handoff wording Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/claude-handoff/SKILL.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/skills/in-progress/claude-handoff/SKILL.md b/skills/in-progress/claude-handoff/SKILL.md index 0e25b18..b326910 100644 --- a/skills/in-progress/claude-handoff/SKILL.md +++ b/skills/in-progress/claude-handoff/SKILL.md @@ -1,18 +1,16 @@ --- name: claude-handoff -description: Hand off the current conversation to a fresh background agent that picks up the work immediately. +description: Hand the current conversation off to a fresh background agent that picks up the work immediately. argument-hint: "What will the next session be used for?" disable-model-invocation: true --- -Compose a handoff summarising the current conversation so a fresh agent can continue the work, then launch it as a background agent seeded with that summary — do not save a document. +Write a handoff document summarising the current conversation so a fresh agent can continue the work. Instead of saving it, launch a background agent seeded with the document as its prompt: `claude --bg ""`. It starts in the current working directory and returns immediately; the user manages it with `claude agents`. -Launch with `claude --bg ""`, passing the summary as the prompt. It starts in the current working directory and returns immediately; the user manages it with `claude agents`. - -Include a "suggested skills" section in the summary, instructing the agent which skills to invoke. +Include a "suggested skills" section in the document, which suggests skills that the agent should invoke. Do not duplicate content already captured in other artifacts (PRDs, plans, ADRs, issues, commits, diffs). Reference them by path or URL instead. -Redact any sensitive information, such as API keys, passwords, or personally identifiable information — it becomes the agent's prompt. +Redact any sensitive information, such as API keys, passwords, or personally identifiable information — the document becomes the agent's prompt. -If the user passed arguments, treat them as a description of what the next session will focus on and tailor the summary accordingly. +If the user passed arguments, treat them as a description of what the next session will focus on and tailor the doc accordingly. From 8347a416143521d6ead6ce7d9cd35f2d1339fa0a Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 2 Jul 2026 11:25:18 +0100 Subject: [PATCH 06/36] claude-handoff: require descriptive --name Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/claude-handoff/SKILL.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/skills/in-progress/claude-handoff/SKILL.md b/skills/in-progress/claude-handoff/SKILL.md index b326910..a68e6b5 100644 --- a/skills/in-progress/claude-handoff/SKILL.md +++ b/skills/in-progress/claude-handoff/SKILL.md @@ -5,7 +5,9 @@ argument-hint: "What will the next session be used for?" disable-model-invocation: true --- -Write a handoff document summarising the current conversation so a fresh agent can continue the work. Instead of saving it, launch a background agent seeded with the document as its prompt: `claude --bg ""`. It starts in the current working directory and returns immediately; the user manages it with `claude agents`. +Write a handoff document summarising the current conversation so a fresh agent can continue the work. Instead of saving it, launch a background agent seeded with the document as its prompt: `claude --bg --name "" ""`. It starts in the current working directory and returns immediately; the user manages it with `claude agents`. + +Always pass `-n`/`--name` with a descriptive name (e.g. `--name "Fix login bug"`) — it sets the display name shown in the job list, session picker, and terminal title. Include a "suggested skills" section in the document, which suggests skills that the agent should invoke. From eb63f6e92c1458128c84c3eff32a9d72ba6a1b8c Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 2 Jul 2026 11:26:41 +0100 Subject: [PATCH 07/36] wayfinder: dedup identity claim in Refer-by-name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "id stays the identity" duplicated the Tickets section's "issue id is its identity" — single source of truth belongs there (co-located with the wiring/blocking mechanics that depend on ids). Reword to state the pasteable-handle exception (link target, Handoff URL) without re-defining identity. Trim redundant rationale wording. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/wayfinder/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index a70895a..3790a28 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -7,7 +7,7 @@ A loose idea has arrived — too big for one agent session, and wrapped in fog: ## Refer by name -Every map and ticket is an issue, so it has a **name** — its title. In everything the human reads — narration, the map's Decisions-so-far, the Handoff — refer to it by that name, never by a bare id, number, or slug. A wall of `#42, #43, #44` is illegible at a glance; names read instantly. The id and URL stay the identity: the link a name wraps, the pasteable handle in a command — they ride *inside* the name, never stand in for it. +Every map and ticket is an issue, so it has a **name** — its title. In everything the human reads — narration, the map's Decisions-so-far, the Handoff — refer to it by that name, never by a bare id, number, or slug. A wall of `#42, #43, #44` is illegible; names read at a glance. The id and URL don't vanish — a name wraps its link, and Handoff commands still paste the URL — but they ride *inside* the name, never stand in for it. ## The Map From 5a7ee93f0129794acbb2950f2e9636e49b29f71a Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 2 Jul 2026 11:26:55 +0100 Subject: [PATCH 08/36] claude-handoff: say handoff summary, not document Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/claude-handoff/SKILL.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/skills/in-progress/claude-handoff/SKILL.md b/skills/in-progress/claude-handoff/SKILL.md index a68e6b5..88ce8be 100644 --- a/skills/in-progress/claude-handoff/SKILL.md +++ b/skills/in-progress/claude-handoff/SKILL.md @@ -5,14 +5,14 @@ argument-hint: "What will the next session be used for?" disable-model-invocation: true --- -Write a handoff document summarising the current conversation so a fresh agent can continue the work. Instead of saving it, launch a background agent seeded with the document as its prompt: `claude --bg --name "" ""`. It starts in the current working directory and returns immediately; the user manages it with `claude agents`. +Write a handoff summary of the current conversation so a fresh agent can continue the work. Instead of saving it, launch a background agent seeded with the summary as its prompt: `claude --bg --name "" ""`. It starts in the current working directory and returns immediately; the user manages it with `claude agents`. Always pass `-n`/`--name` with a descriptive name (e.g. `--name "Fix login bug"`) — it sets the display name shown in the job list, session picker, and terminal title. -Include a "suggested skills" section in the document, which suggests skills that the agent should invoke. +Include a "suggested skills" section in the summary, which suggests skills that the agent should invoke. Do not duplicate content already captured in other artifacts (PRDs, plans, ADRs, issues, commits, diffs). Reference them by path or URL instead. -Redact any sensitive information, such as API keys, passwords, or personally identifiable information — the document becomes the agent's prompt. +Redact any sensitive information, such as API keys, passwords, or personally identifiable information — the summary becomes the agent's prompt. -If the user passed arguments, treat them as a description of what the next session will focus on and tailor the doc accordingly. +If the user passed arguments, treat them as a description of what the next session will focus on and tailor the summary accordingly. From a12cca62fa4e63ee7b2fb6b955600789e6dedf63 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 2 Jul 2026 11:28:42 +0100 Subject: [PATCH 09/36] wayfinder: use placeholders in Handoff example, drop no-op MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cut the "(trailing name orients you; it's ignored on paste)" gloss — a # comment is self-evident. Replace the arbitrary "Briefing pipeline" map name and specific ticket names with / placeholders, consistent with the surrounding / style so nothing reads as a real referent. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/wayfinder/SKILL.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 3790a28..7f1b8b3 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -108,7 +108,7 @@ End every session with a **Next steps** block the user can copy-paste. Two cases **Open tickets remain.** Query the map for the currently-unblocked children, then give two copy-paste options: a bare command for one session (you pick the next ticket), and one pinned command per unblocked ticket for running them in parallel. Paste one line per fresh window — opening one, some, or all of them. -> **Next steps** — *Briefing pipeline*: 3 tickets unblocked. Clear the context, then open fresh sessions. +> **Next steps** — **: 3 tickets unblocked. Clear the context, then open fresh sessions. > > **One session** — resolves the next unblocked ticket: > @@ -116,12 +116,12 @@ End every session with a **Next steps** block the user can copy-paste. Two cases > Invoke /wayfinder with the map . > ``` > -> **Parallel** — paste one line per window, up to all 3 (trailing name orients you; it's ignored on paste): +> **Parallel** — paste one line per window, up to all 3: > > ``` -> Invoke /wayfinder with the map , ticket . # Reciprocity filter -> Invoke /wayfinder with the map , ticket . # TTS chunking -> Invoke /wayfinder with the map , ticket . # Voice selection +> Invoke /wayfinder with the map , ticket . # +> Invoke /wayfinder with the map , ticket . # +> Invoke /wayfinder with the map , ticket . # > ``` **No open tickets remain.** The fog is pushed back far enough that the way to the goal is clear — the map is done. (The initial grilling may also surface no fog at all, in which case there was never a map to chart.) Recommend implementing directly, or using `/to-prd` to schedule a multi-session implementation. From b25e2b3787334a30bf0b1afbd9204db311bf426e Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 2 Jul 2026 11:32:04 +0100 Subject: [PATCH 10/36] claude-handoff: add to in-progress README index Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/skills/in-progress/README.md b/skills/in-progress/README.md index b283f5b..8b91783 100644 --- a/skills/in-progress/README.md +++ b/skills/in-progress/README.md @@ -8,3 +8,4 @@ Skills that are still being developed. They're not ready to ship — expect roug - **[writing-beats](./writing-beats/SKILL.md)** — Shape an article as a journey of beats, choose-your-own-adventure style. Pick a starting beat, write only that beat, then pivot to the next, until the article reaches a natural end. - **[writing-fragments](./writing-fragments/SKILL.md)** — Grilling session that mines you for fragments — heterogeneous nuggets of writing — and appends them to a single document as raw material for a future article. - **[writing-shape](./writing-shape/SKILL.md)** — Take a markdown file of raw material and shape it into an article paragraph by paragraph, arguing format choices at each step. +- **[claude-handoff](./claude-handoff/SKILL.md)** — Hand the current conversation off to a fresh background agent that picks up the work immediately, seeded with a handoff summary via `claude --bg`. User-invoked. From 1f16ea94999086c05c3484c897161cbcbeff2862 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 2 Jul 2026 13:48:13 +0100 Subject: [PATCH 11/36] wayfinder: remove the Handoff ceremony MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every session ended with a Handoff that queried the frontier and emitted per-ticket copy-paste commands — real token cost each session. Cut it entirely and let the natural flow carry continuation: the next /wayfinder session already loads the map and picks the next frontier ticket, so nothing is lost, just deferred to re-invocation. Reconciles the references left behind: the one-ticket-per-session rule and "charting is one session's work" constraint survive as plain lines; the Refer-by-name paragraph drops its Handoff mentions. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/wayfinder/SKILL.md | 31 +++------------------------ 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 7f1b8b3..8d234e9 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -7,7 +7,7 @@ A loose idea has arrived — too big for one agent session, and wrapped in fog: ## Refer by name -Every map and ticket is an issue, so it has a **name** — its title. In everything the human reads — narration, the map's Decisions-so-far, the Handoff — refer to it by that name, never by a bare id, number, or slug. A wall of `#42, #43, #44` is illegible; names read at a glance. The id and URL don't vanish — a name wraps its link, and Handoff commands still paste the URL — but they ride *inside* the name, never stand in for it. +Every map and ticket is an issue, so it has a **name** — its title. In everything the human reads — narration, the map's Decisions-so-far — refer to it by that name, never by a bare id, number, or slug. A wall of `#42, #43, #44` is illegible; names read at a glance. The id and URL don't vanish — a name wraps its link — but they ride *inside* the name, never stand in for it. ## The Map @@ -78,7 +78,7 @@ Fog excludes only what's already decided (that's Decisions so far) and what's al ## Invocation -Two modes. Either way, **every session ends with a [Handoff](#handoff)** — never resolve more than one ticket per session. +Two modes. Either way, **never resolve more than one ticket per session.** ### Chart the map @@ -87,7 +87,7 @@ User invokes with a loose idea. 1. Run a `/grilling` and `/domain-modeling` session to surface the open decisions. 2. **Create the map** (label `wayfinder:map`): Notes filled in, Decisions-so-far empty, Fog sketched. 3. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the Fog. -4. Handoff. Charting the map is one session's work; do not also resolve tickets. +4. Stop — charting the map is one session's work; do not also resolve tickets. ### Work through the map @@ -98,30 +98,5 @@ User invokes with a map (URL or number). A ticket is **optional** — without on 3. Resolve it — **zoom as needed**: fetch the full body of any related or closed ticket on demand; invoke the skills the `## Notes` block names. If in doubt, use `/grilling` and `/domain-modeling`. 4. Record the resolution: post the answer as a **resolution comment**, **close** the issue, and **append a context pointer** to the map's Decisions-so-far. 5. Add newly-surfaced tickets (create-then-wire); graduate any fog the answer has made specifiable, clearing each graduated patch from the Fog so it lives only as its new ticket. If the decision invalidates other parts of the map, update or delete those tickets. -6. Handoff. The user may run unblocked tickets in parallel, so expect other sessions to be editing the tracker concurrently. - -## Handoff - -End every session with a **Next steps** block the user can copy-paste. Two cases: - -**Open tickets remain.** Query the map for the currently-unblocked children, then give two copy-paste options: a bare command for one session (you pick the next ticket), and one pinned command per unblocked ticket for running them in parallel. Paste one line per fresh window — opening one, some, or all of them. - -> **Next steps** — **: 3 tickets unblocked. Clear the context, then open fresh sessions. -> -> **One session** — resolves the next unblocked ticket: -> -> ``` -> Invoke /wayfinder with the map . -> ``` -> -> **Parallel** — paste one line per window, up to all 3: -> -> ``` -> Invoke /wayfinder with the map , ticket . # -> Invoke /wayfinder with the map , ticket . # -> Invoke /wayfinder with the map , ticket . # -> ``` - -**No open tickets remain.** The fog is pushed back far enough that the way to the goal is clear — the map is done. (The initial grilling may also surface no fog at all, in which case there was never a map to chart.) Recommend implementing directly, or using `/to-prd` to schedule a multi-session implementation. From 8cc33286333d2c757c9b3dd43635ed2451aaceb1 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Thu, 2 Jul 2026 14:25:26 +0100 Subject: [PATCH 12/36] wayfinder: reframe description around planning big work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The description does the skill's invocation work, so lead with the trigger that actually reaches for Wayfinder — a huge chunk of work, more than one agent session can hold — instead of the softer "chart a route through a foggy problem". Skill body and fog-of-war mechanic unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-plan-big-work.md | 7 +++++++ skills/in-progress/wayfinder/SKILL.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .changeset/wayfinder-plan-big-work.md diff --git a/.changeset/wayfinder-plan-big-work.md b/.changeset/wayfinder-plan-big-work.md new file mode 100644 index 0000000..07e01ee --- /dev/null +++ b/.changeset/wayfinder-plan-big-work.md @@ -0,0 +1,7 @@ +--- +"mattpocock-skills": minor +--- + +Reframe **`wayfinder`**'s description around the work it's for: planning a huge chunk of work, more than one agent session can hold. + +The description does the skill's invocation work, so it now leads with the trigger that actually reaches for Wayfinder — a big effort you need to break down — instead of the softer "chart a route through a foggy problem". The skill body and fog-of-war mechanic are unchanged. diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 8d234e9..8cb6b23 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -1,6 +1,6 @@ --- name: wayfinder -description: Chart a route through a foggy problem — turn a loose idea into a shared map of investigation tickets on your issue tracker, and resolve them one at a time until the way to the goal is clear. +description: Plan a huge chunk of work — more than one agent session can hold — as a shared map of investigation tickets on your issue tracker, and resolve them one at a time until the way to the goal is clear. --- A loose idea has arrived — too big for one agent session, and wrapped in fog: the route from here to a plan isn't visible yet. This skill charts it as a **shared map** on the repo's issue tracker, then works its tickets one at a time. The map is domain-agnostic — engineering work, course content, whatever fits the shape. From 0e9a0727924c39cc2a0c7e04d04526a73bef7ac4 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Fri, 3 Jul 2026 09:47:48 +0100 Subject: [PATCH 13/36] grilling: add confirmation gate and grill leading word Add a hard stop so the agent won't enact the plan until the user confirms shared understanding is reached. Recruit the pretrained "grill" leading word in the description, and re-sync the docs page with the new gate behaviour. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/productivity/grilling.md | 2 +- skills/productivity/grilling/SKILL.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/productivity/grilling.md b/docs/productivity/grilling.md index 2384bd1..8fa5067 100644 --- a/docs/productivity/grilling.md +++ b/docs/productivity/grilling.md @@ -14,7 +14,7 @@ npx skills update grilling `grilling` is the relentless interview that stress-tests a plan or design before you build it. It walks down the design tree branch by branch, resolving the dependencies between decisions one at a time until you and the agent share the same understanding. -It asks **one question at a time** and waits for your answer before the next — never a bulk list, which is bewildering. Each question comes with the agent's own recommended answer, and any question the codebase can settle it explores instead of asking you. +It asks **one question at a time** and waits for your answer before the next — never a bulk list, which is bewildering. Each question comes with the agent's own recommended answer, and any question the codebase can settle it explores instead of asking you. It won't start enacting the plan until you confirm the shared understanding has been reached. ## When to reach for it diff --git a/skills/productivity/grilling/SKILL.md b/skills/productivity/grilling/SKILL.md index fe3569d..e220063 100644 --- a/skills/productivity/grilling/SKILL.md +++ b/skills/productivity/grilling/SKILL.md @@ -1,6 +1,6 @@ --- name: grilling -description: Interview the user relentlessly about a plan or design. Use when the user wants to stress-test a plan before building, or uses any 'grill' trigger phrases. +description: Grill the user relentlessly about a plan or design. Use when the user wants to stress-test a plan before building, or uses any 'grill' trigger phrases. --- Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer. @@ -8,3 +8,5 @@ Interview me relentlessly about every aspect of this plan until we reach a share Ask the questions one at a time, waiting for feedback on each question before continuing. Asking multiple questions at once is bewildering. If a question can be answered by exploring the codebase, explore the codebase instead. + +Do not enact the plan until I confirm we have reached a shared understanding. From e1c025eaee5b822d2cec645589f32291a88a89f7 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Fri, 3 Jul 2026 09:48:46 +0100 Subject: [PATCH 14/36] Add minor changeset for grilling gate and leading word Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/grilling-gate-and-leading-word.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/grilling-gate-and-leading-word.md diff --git a/.changeset/grilling-gate-and-leading-word.md b/.changeset/grilling-gate-and-leading-word.md new file mode 100644 index 0000000..34c8bfd --- /dev/null +++ b/.changeset/grilling-gate-and-leading-word.md @@ -0,0 +1,5 @@ +--- +"mattpocock-skills": minor +--- + +Add a confirmation gate to **`grilling`**: the agent won't enact the plan until you confirm the shared understanding has been reached, turning the skill's existing "shared understanding" completion criterion into an explicit stop-gate. The `description` also recruits the pretrained **`grill`** leading word ("Grill the user relentlessly") to sharpen invocation, and the docs page is re-synced with the new gate behaviour. From bd453a6742fb8660bf618c298f1e2b80fb9f35e3 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Fri, 3 Jul 2026 09:53:34 +0100 Subject: [PATCH 15/36] docs: fix tdd skill reference to code-review skill The tdd skill pointed at a `review` skill that no longer exists; the review skill is now named `code-review`. Update the reference. Fixes #432 Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/engineering/tdd/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/engineering/tdd/SKILL.md b/skills/engineering/tdd/SKILL.md index 4e243fb..9a2e1d2 100644 --- a/skills/engineering/tdd/SKILL.md +++ b/skills/engineering/tdd/SKILL.md @@ -33,4 +33,4 @@ Ask: "What's the public interface, and which seams should we test?" - **Red before green.** Write the failing test first, then only enough code to pass it. Don't anticipate future tests or add speculative features. - **One slice at a time.** One seam, one test, one minimal implementation per cycle. -- **Refactoring is not part of the loop.** It belongs to the review stage (see the `review` skill), not the red → green implementation cycle. +- **Refactoring is not part of the loop.** It belongs to the review stage (see the `code-review` skill), not the red → green implementation cycle. From b289481499e7b53f0618bdad754b8e784dbd773a Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Fri, 3 Jul 2026 10:39:04 +0100 Subject: [PATCH 16/36] wayfinder: prefer native blocking, and say why The blocking rule now leads with the tracker's native dependency relationship and encodes the rationale: native rendering makes the frontier visible in the tracker's own UI, so the human sees what's takeable without opening the map. Notes the body-convention fallback for trackers that lack native blocking (GitHub has it; GitLab only on paid tiers). Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-native-blocking-rationale.md | 7 +++++++ skills/in-progress/wayfinder/SKILL.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .changeset/wayfinder-native-blocking-rationale.md diff --git a/.changeset/wayfinder-native-blocking-rationale.md b/.changeset/wayfinder-native-blocking-rationale.md new file mode 100644 index 0000000..6d73798 --- /dev/null +++ b/.changeset/wayfinder-native-blocking-rationale.md @@ -0,0 +1,7 @@ +--- +"mattpocock-skills": patch +--- + +Sharpen **`wayfinder`**'s blocking rule to prefer the tracker's native dependency relationship and say why. + +Native blocking is essential rather than cosmetic: it renders the frontier visually in the tracker's own UI, so the human sees what's takeable at a glance without opening the map. The rule now states that preference explicitly, notes the body-convention fallback for trackers that lack native blocking, and ties the frontier to what the human picks from. diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 8cb6b23..b86c59e 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -52,7 +52,7 @@ Two label families: - `wayfinder:` — one of `research`, `prototype`, `grilling`, `task` (see [Ticket Types](#ticket-types)). - `wayfinder:claimed` — a session sets this **first**, before any work, so concurrent sessions skip it. -Blocking uses the tracker's native semantics. A ticket is **unblocked** when every ticket blocking it is closed. The **frontier** is the open, unblocked, unclaimed children — the edge of the known. +Blocking uses the tracker's **native** dependency relationship wherever the tracker has one. Native is essential, not cosmetic: it renders the frontier _visually_ in the tracker's own UI, so the human sees what's takeable at a glance without opening the map. Only where a tracker has no native blocking does the mechanics fall back to a body convention. A ticket is **unblocked** when every ticket blocking it is closed; the **frontier** is the open, unblocked, unclaimed children — the edge of the known, and what the human picks from. The answer isn't part of the body — it's recorded on resolution (see [Work through the map](#work-through-the-map)). Assets created while resolving a ticket are linked from the issue, not pasted in. From 8c2a4c554afaa5ec6efecc98258058ba69b72c48 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Fri, 3 Jul 2026 10:42:56 +0100 Subject: [PATCH 17/36] wayfinder: tighten blocking rule, update GH/GL templates Concision pass on the blocking rule (fold the "wherever the tracker has one" clause into the fallback sentence; drop restatements). Bring the GitHub and GitLab issue-tracker templates up to the same standard: the GitHub template now carries the native issue-dependencies recipe and frontier query; the GitLab template names the native /blocked_by link (Premium/Ultimate) with the body-convention fallback. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-native-blocking-rationale.md | 4 ++-- .../setup-matt-pocock-skills/issue-tracker-github.md | 4 ++-- .../setup-matt-pocock-skills/issue-tracker-gitlab.md | 4 ++-- skills/in-progress/wayfinder/SKILL.md | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.changeset/wayfinder-native-blocking-rationale.md b/.changeset/wayfinder-native-blocking-rationale.md index 6d73798..bba5264 100644 --- a/.changeset/wayfinder-native-blocking-rationale.md +++ b/.changeset/wayfinder-native-blocking-rationale.md @@ -2,6 +2,6 @@ "mattpocock-skills": patch --- -Sharpen **`wayfinder`**'s blocking rule to prefer the tracker's native dependency relationship and say why. +Sharpen Wayfinder's blocking rule to prefer the tracker's native dependency relationship, and update the GitHub and GitLab issue-tracker templates to match. -Native blocking is essential rather than cosmetic: it renders the frontier visually in the tracker's own UI, so the human sees what's takeable at a glance without opening the map. The rule now states that preference explicitly, notes the body-convention fallback for trackers that lack native blocking, and ties the frontier to what the human picks from. +Native blocking is essential rather than cosmetic: it renders the frontier visually in the tracker's own UI, so the human sees what's takeable at a glance without opening the map. `wayfinder`'s SKILL.md now states that preference and rationale; the GitHub template spells out the native issue-dependencies recipe (`gh api .../dependencies/blocked_by`, frontier query on `issue_dependencies_summary.blocked_by`), and the GitLab template names the native `/blocked_by` blocking link (Premium/Ultimate) with the body-convention fallback. Both keep the body fallback for trackers that lack native blocking. diff --git a/skills/engineering/setup-matt-pocock-skills/issue-tracker-github.md b/skills/engineering/setup-matt-pocock-skills/issue-tracker-github.md index bd4baa5..8930f87 100644 --- a/skills/engineering/setup-matt-pocock-skills/issue-tracker-github.md +++ b/skills/engineering/setup-matt-pocock-skills/issue-tracker-github.md @@ -39,7 +39,7 @@ Used by `/wayfinder`. The **map** is a single issue with **child** issues as tic - **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `gh issue create --label wayfinder:map`. - **Child ticket**: an issue linked to the map as a GitHub sub-issue (`gh api` on the sub-issues endpoint). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #` at the top of the child body. Labels: `wayfinder:` (`research`/`prototype`/`grilling`/`task`), plus `wayfinder:claimed` once claimed. -- **Blocking**: native issue relationships where available; otherwise a `Blocked by: #, #` line at the top of the child body. A ticket is unblocked when every issue it lists is closed. -- **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open `Blocked by` issue or the `wayfinder:claimed` label; first in map order wins. +- **Blocking**: GitHub's **native issue dependencies** — the canonical, UI-visible representation. Add an edge with `gh api --method POST repos///issues//dependencies/blocked_by -F issue_id=`, where `` is the blocker's numeric **database id** (`gh api repos///issues/ --jq .id`, _not_ the `#number` or `node_id`). GitHub reports `issue_dependencies_summary.blocked_by` (open blockers only — the live gate). Where dependencies aren't available, fall back to a `Blocked by: #, #` line at the top of the child body. A ticket is unblocked when every blocker is closed. +- **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0`, or an open issue in the `Blocked by` line) or the `wayfinder:claimed` label; first in map order wins. - **Claim**: `gh issue edit --add-label wayfinder:claimed` — the session's first write. - **Resolve**: `gh issue comment --body ""`, then `gh issue close `, then append a context pointer (gist + link) to the map's Decisions-so-far. diff --git a/skills/engineering/setup-matt-pocock-skills/issue-tracker-gitlab.md b/skills/engineering/setup-matt-pocock-skills/issue-tracker-gitlab.md index 792f5d6..2e3614b 100644 --- a/skills/engineering/setup-matt-pocock-skills/issue-tracker-gitlab.md +++ b/skills/engineering/setup-matt-pocock-skills/issue-tracker-gitlab.md @@ -40,7 +40,7 @@ Used by `/wayfinder`. The **map** is a single issue with **child** issues as tic - **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `glab issue create --label wayfinder:map`. (On GitLab tiers with native epics, an epic may hold the map instead; a labelled issue works everywhere.) - **Child ticket**: an issue carrying `Part of #` at the top of its description and labels `wayfinder:` (`research`/`prototype`/`grilling`/`task`), plus `wayfinder:claimed` once claimed. -- **Blocking**: GitLab's native `/blocked_by #` quick action (or a `Blocked by: #, #` line in the description as fallback). A ticket is unblocked when every issue it lists is closed. -- **Frontier query**: `glab issue list -F json` scoped to the map's children, drop any with an open blocker or the `wayfinder:claimed` label; first in map order wins. +- **Blocking**: GitLab's **native blocking link** — the canonical, UI-visible representation. Add it with the `/blocked_by #` quick action, posted as a note (`glab issue note --message "/blocked_by #"`). Native blocking links are a Premium/Ultimate feature; on the free tier (or where unavailable) fall back to a `Blocked by: #, #` line at the top of the description. A ticket is unblocked when every blocker is closed. +- **Frontier query**: `glab issue list -F json` scoped to the map's children, drop any with an open blocker — a native `blocked_by` link to an open issue (`glab api projects/:id/issues/:iid/links`), or an open issue in the `Blocked by` line — or the `wayfinder:claimed` label; first in map order wins. - **Claim**: `glab issue update --label wayfinder:claimed` — the session's first write. - **Resolve**: `glab issue note --message ""`, then `glab issue close `, then append a context pointer (gist + link) to the map's Decisions-so-far. diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index b86c59e..3bf78bc 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -52,7 +52,7 @@ Two label families: - `wayfinder:` — one of `research`, `prototype`, `grilling`, `task` (see [Ticket Types](#ticket-types)). - `wayfinder:claimed` — a session sets this **first**, before any work, so concurrent sessions skip it. -Blocking uses the tracker's **native** dependency relationship wherever the tracker has one. Native is essential, not cosmetic: it renders the frontier _visually_ in the tracker's own UI, so the human sees what's takeable at a glance without opening the map. Only where a tracker has no native blocking does the mechanics fall back to a body convention. A ticket is **unblocked** when every ticket blocking it is closed; the **frontier** is the open, unblocked, unclaimed children — the edge of the known, and what the human picks from. +Blocking uses the tracker's **native** dependency relationship — essential because it renders the frontier _visually_ in the tracker's own UI, so the human sees what's takeable without opening the map. Only a tracker that lacks native blocking falls back to a body convention. A ticket is **unblocked** when every ticket blocking it is closed; the **frontier** is the open, unblocked, unclaimed children — the edge of the known. The answer isn't part of the body — it's recorded on resolution (see [Work through the map](#work-through-the-map)). Assets created while resolving a ticket are linked from the issue, not pasted in. From 6f9e9956fd01235599cdba40f5b8ca3a92fc0045 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Fri, 3 Jul 2026 11:34:42 +0100 Subject: [PATCH 18/36] wayfinder: claim by assigning the ticket, not a label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A session now claims a ticket by assigning it to the dev driving the map, rather than setting a `wayfinder:claimed` label. The assignee is the claim; an open, unassigned ticket is unclaimed. Reads more naturally in the tracker's own UI and frees the label vocabulary to `wayfinder:` alone. Updates the GitHub and GitLab tracker-operations docs to the assignee mechanism (`--add-assignee @me` / `--assignee @me`). The local-markdown tracker keeps its `Status: claimed` line — a file store has no assignee. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-assign-to-claim.md | 7 +++++++ .../setup-matt-pocock-skills/issue-tracker-github.md | 6 +++--- .../setup-matt-pocock-skills/issue-tracker-gitlab.md | 6 +++--- skills/in-progress/wayfinder/SKILL.md | 7 +++---- 4 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 .changeset/wayfinder-assign-to-claim.md diff --git a/.changeset/wayfinder-assign-to-claim.md b/.changeset/wayfinder-assign-to-claim.md new file mode 100644 index 0000000..02f3697 --- /dev/null +++ b/.changeset/wayfinder-assign-to-claim.md @@ -0,0 +1,7 @@ +--- +"mattpocock-skills": minor +--- + +Change **`wayfinder`**'s claim mechanism from a label to an assignee. + +A session now **claims** a ticket by assigning it to the dev driving the map, rather than setting a `wayfinder:claimed` label. The assignee _is_ the claim — an open, unassigned ticket is unclaimed — which reads more naturally in GitHub's own UI and frees the label vocabulary to `wayfinder:` alone. The *claim* leading word and its "first, before any work" rationale are unchanged; only the physical expression moved. diff --git a/skills/engineering/setup-matt-pocock-skills/issue-tracker-github.md b/skills/engineering/setup-matt-pocock-skills/issue-tracker-github.md index 8930f87..82cfbf5 100644 --- a/skills/engineering/setup-matt-pocock-skills/issue-tracker-github.md +++ b/skills/engineering/setup-matt-pocock-skills/issue-tracker-github.md @@ -38,8 +38,8 @@ Run `gh issue view --comments`. Used by `/wayfinder`. The **map** is a single issue with **child** issues as tickets. - **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `gh issue create --label wayfinder:map`. -- **Child ticket**: an issue linked to the map as a GitHub sub-issue (`gh api` on the sub-issues endpoint). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #` at the top of the child body. Labels: `wayfinder:` (`research`/`prototype`/`grilling`/`task`), plus `wayfinder:claimed` once claimed. +- **Child ticket**: an issue linked to the map as a GitHub sub-issue (`gh api` on the sub-issues endpoint). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #` at the top of the child body. Labels: `wayfinder:` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev. - **Blocking**: GitHub's **native issue dependencies** — the canonical, UI-visible representation. Add an edge with `gh api --method POST repos///issues//dependencies/blocked_by -F issue_id=`, where `` is the blocker's numeric **database id** (`gh api repos///issues/ --jq .id`, _not_ the `#number` or `node_id`). GitHub reports `issue_dependencies_summary.blocked_by` (open blockers only — the live gate). Where dependencies aren't available, fall back to a `Blocked by: #, #` line at the top of the child body. A ticket is unblocked when every blocker is closed. -- **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0`, or an open issue in the `Blocked by` line) or the `wayfinder:claimed` label; first in map order wins. -- **Claim**: `gh issue edit --add-label wayfinder:claimed` — the session's first write. +- **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0`, or an open issue in the `Blocked by` line) or an assignee; first in map order wins. +- **Claim**: `gh issue edit --add-assignee @me` — the session's first write. - **Resolve**: `gh issue comment --body ""`, then `gh issue close `, then append a context pointer (gist + link) to the map's Decisions-so-far. diff --git a/skills/engineering/setup-matt-pocock-skills/issue-tracker-gitlab.md b/skills/engineering/setup-matt-pocock-skills/issue-tracker-gitlab.md index 2e3614b..8a54714 100644 --- a/skills/engineering/setup-matt-pocock-skills/issue-tracker-gitlab.md +++ b/skills/engineering/setup-matt-pocock-skills/issue-tracker-gitlab.md @@ -39,8 +39,8 @@ Run `glab issue view --comments`. Used by `/wayfinder`. The **map** is a single issue with **child** issues as tickets. - **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `glab issue create --label wayfinder:map`. (On GitLab tiers with native epics, an epic may hold the map instead; a labelled issue works everywhere.) -- **Child ticket**: an issue carrying `Part of #` at the top of its description and labels `wayfinder:` (`research`/`prototype`/`grilling`/`task`), plus `wayfinder:claimed` once claimed. +- **Child ticket**: an issue carrying `Part of #` at the top of its description and labels `wayfinder:` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev. - **Blocking**: GitLab's **native blocking link** — the canonical, UI-visible representation. Add it with the `/blocked_by #` quick action, posted as a note (`glab issue note --message "/blocked_by #"`). Native blocking links are a Premium/Ultimate feature; on the free tier (or where unavailable) fall back to a `Blocked by: #, #` line at the top of the description. A ticket is unblocked when every blocker is closed. -- **Frontier query**: `glab issue list -F json` scoped to the map's children, drop any with an open blocker — a native `blocked_by` link to an open issue (`glab api projects/:id/issues/:iid/links`), or an open issue in the `Blocked by` line — or the `wayfinder:claimed` label; first in map order wins. -- **Claim**: `glab issue update --label wayfinder:claimed` — the session's first write. +- **Frontier query**: `glab issue list -F json` scoped to the map's children, drop any with an open blocker — a native `blocked_by` link to an open issue (`glab api projects/:id/issues/:iid/links`), or an open issue in the `Blocked by` line — or an assignee; first in map order wins. +- **Claim**: `glab issue update --assignee @me` — the session's first write. - **Resolve**: `glab issue note --message ""`, then `glab issue close `, then append a context pointer (gist + link) to the map's Decisions-so-far. diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 3bf78bc..d8424bb 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -47,10 +47,9 @@ Each ticket is a **child issue** of the map; the tracker's issue id is its ident ``` -Two label families: +Each ticket carries a `wayfinder:` label — one of `research`, `prototype`, `grilling`, `task` (see [Ticket Types](#ticket-types)). -- `wayfinder:` — one of `research`, `prototype`, `grilling`, `task` (see [Ticket Types](#ticket-types)). -- `wayfinder:claimed` — a session sets this **first**, before any work, so concurrent sessions skip it. +A session **claims** a ticket by assigning it to the dev driving the map, **first**, before any work, so concurrent sessions skip it. That assignee _is_ the claim: an open, unassigned ticket is unclaimed. Blocking uses the tracker's **native** dependency relationship — essential because it renders the frontier _visually_ in the tracker's own UI, so the human sees what's takeable without opening the map. Only a tracker that lacks native blocking falls back to a body convention. A ticket is **unblocked** when every ticket blocking it is closed; the **frontier** is the open, unblocked, unclaimed children — the edge of the known. @@ -94,7 +93,7 @@ User invokes with a loose idea. User invokes with a map (URL or number). A ticket is **optional** — without one, you pick the next decision, not the user. 1. Load the **map** — the low-res view, not every ticket body. -2. Choose the ticket. If the user named one, use it. Otherwise take the first frontier ticket in order. **Claim it**: set `wayfinder:claimed` and save before any work. +2. Choose the ticket. If the user named one, use it. Otherwise take the first frontier ticket in order. **Claim it**: assign it to yourself before any work. 3. Resolve it — **zoom as needed**: fetch the full body of any related or closed ticket on demand; invoke the skills the `## Notes` block names. If in doubt, use `/grilling` and `/domain-modeling`. 4. Record the resolution: post the answer as a **resolution comment**, **close** the issue, and **append a context pointer** to the map's Decisions-so-far. 5. Add newly-surfaced tickets (create-then-wire); graduate any fog the answer has made specifiable, clearing each graduated patch from the Fog so it lives only as its new ticket. If the decision invalidates other parts of the map, update or delete those tickets. From 53c6219cd2a1d2746d6ee59705862f171ea09451 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Sun, 5 Jul 2026 14:57:57 +0100 Subject: [PATCH 19/36] Reframe wayfinder around "destination" as the leading word Wayfinding finds the way to a destination rather than building it. The destination varies per effort and is named first, since it shapes every ticket. Adds a Destination map-body field, makes it triage step 1, and unifies the stray "goal" mentions onto "destination". Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-destination-purpose.md | 7 +++++++ skills/in-progress/wayfinder/SKILL.md | 16 +++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 .changeset/wayfinder-destination-purpose.md diff --git a/.changeset/wayfinder-destination-purpose.md b/.changeset/wayfinder-destination-purpose.md new file mode 100644 index 0000000..5bbe265 --- /dev/null +++ b/.changeset/wayfinder-destination-purpose.md @@ -0,0 +1,7 @@ +--- +"mattpocock-skills": minor +--- + +Sharpen **`wayfinder`**'s top-level purpose around **destination** as the leading word: wayfinding finds the *way* to a destination, it doesn't charge at building it. + +The opening now states that the destination varies per effort — a spec to hand off and iterate, a decision to lock before planning, or a change made in place like a data-structure migration — and that naming it is the first act of charting, because it shapes every ticket. The map body gains a `## Destination` field that every session orients to before choosing a ticket, and triage's first step now pins the destination before any ticket exists. The stray `goal` mentions in the description and Fog section are unified onto `destination`. diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index d8424bb..4031ff4 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -1,9 +1,11 @@ --- name: wayfinder -description: Plan a huge chunk of work — more than one agent session can hold — as a shared map of investigation tickets on your issue tracker, and resolve them one at a time until the way to the goal is clear. +description: Plan a huge chunk of work — more than one agent session can hold — as a shared map of investigation tickets on your issue tracker, and resolve them one at a time until the way to the destination is clear. --- -A loose idea has arrived — too big for one agent session, and wrapped in fog: the route from here to a plan isn't visible yet. This skill charts it as a **shared map** on the repo's issue tracker, then works its tickets one at a time. The map is domain-agnostic — engineering work, course content, whatever fits the shape. +A loose idea has arrived — too big for one agent session, and wrapped in fog: the way from here to the **destination** isn't visible yet. Wayfinding is about finding that way, not charging at the destination. This skill charts the way as a **shared map** on the repo's issue tracker, then works its tickets one at a time until the route is clear. + +The destination varies per effort, and naming it is the first act of charting — it shapes every ticket. It might be a spec to hand off and iterate on, a decision to lock before planning starts, or a change made in place like a data-structure migration. The map is domain-agnostic — engineering work, course content, whatever fits the shape. ## Refer by name @@ -22,6 +24,10 @@ The map is an **index**, not a store. It lists the decisions made and points at The whole map at low resolution, loaded once per session. Open tickets are **not** listed — they are open child issues, found by query. ```markdown +## Destination + + + ## Notes @@ -64,7 +70,7 @@ The answer isn't part of the body — it's recorded on resolution (see [Work thr ## Fog of war -The map is _deliberately_ incomplete: don't chart what you can't yet see. Beyond the tickets lies fog — the dim view of decisions and investigations you can tell are coming but can't yet pin down, because they hang on questions still open. Resolving a ticket clears the fog ahead of it, graduating whatever's now specifiable into fresh tickets — one at a time, until the way to the goal is clear and no tickets remain. +The map is _deliberately_ incomplete: don't chart what you can't yet see. Beyond the tickets lies fog — the dim view of decisions and investigations you can tell are coming but can't yet pin down, because they hang on questions still open. Resolving a ticket clears the fog ahead of it, graduating whatever's now specifiable into fresh tickets — one at a time, until the way to the destination is clear and no tickets remain. The map's **Fog** section is where that dim view is written down: the suspected question, the area to revisit later, the risk you're deferring. Write as loosely or as fully as the view allows; it doubles as a signpost for collaborators reading where the effort is headed. @@ -83,8 +89,8 @@ Two modes. Either way, **never resolve more than one ticket per session.** User invokes with a loose idea. -1. Run a `/grilling` and `/domain-modeling` session to surface the open decisions. -2. **Create the map** (label `wayfinder:map`): Notes filled in, Decisions-so-far empty, Fog sketched. +1. **Name the destination first.** Run a `/grilling` and `/domain-modeling` session to pin down what this map is finding its way to — the spec, decision, or change — and the open decisions between here and there. The destination shapes every ticket, so it's settled before any ticket exists. +2. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, Fog sketched. 3. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the Fog. 4. Stop — charting the map is one session's work; do not also resolve tickets. From c808f64f92688e324770f8088160a26d96c959a0 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Sun, 5 Jul 2026 15:00:34 +0100 Subject: [PATCH 20/36] Make triage step 1 breadth-first: fix scope, then find the frontier Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/wayfinder/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 4031ff4..b769250 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -89,7 +89,7 @@ Two modes. Either way, **never resolve more than one ticket per session.** User invokes with a loose idea. -1. **Name the destination first.** Run a `/grilling` and `/domain-modeling` session to pin down what this map is finding its way to — the spec, decision, or change — and the open decisions between here and there. The destination shapes every ticket, so it's settled before any ticket exists. +1. **Name the destination, then map the frontier.** Run a **breadth-first** `/grilling` and `/domain-modeling` session: first pin down what this map is finding its way to — the spec, decision, or change — then fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. The destination fixes the scope; the breadth-first pass finds the frontier. Both are settled before any ticket exists. 2. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, Fog sketched. 3. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the Fog. 4. Stop — charting the map is one session's work; do not also resolve tickets. From 913a1058816257f4720b82bd5b11d0cee7602582 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Sun, 5 Jul 2026 15:02:39 +0100 Subject: [PATCH 21/36] Split charting triage into two grilling steps: destination, then frontier Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/wayfinder/SKILL.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index b769250..1b72ca0 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -89,10 +89,11 @@ Two modes. Either way, **never resolve more than one ticket per session.** User invokes with a loose idea. -1. **Name the destination, then map the frontier.** Run a **breadth-first** `/grilling` and `/domain-modeling` session: first pin down what this map is finding its way to — the spec, decision, or change — then fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. The destination fixes the scope; the breadth-first pass finds the frontier. Both are settled before any ticket exists. -2. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, Fog sketched. -3. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the Fog. -4. Stop — charting the map is one session's work; do not also resolve tickets. +1. **Name the destination.** Run a `/grilling` and `/domain-modeling` session to pin down what this map is finding its way to — the spec, decision, or change. The destination fixes the scope, so it's settled first. +2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. +3. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, Fog sketched. +4. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the Fog. +5. Stop — charting the map is one session's work; do not also resolve tickets. ### Work through the map From 299eb0c0171c06ee1d9a16a9235912ba6893fd57 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Sun, 5 Jul 2026 15:08:48 +0100 Subject: [PATCH 22/36] Give wayfinder a distinct Deferred section for beyond-destination work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fog is the undiscovered frontier *toward* the destination — in scope, just not yet sharp — so it graduates into tickets as the frontier advances. Work ruled out of *this* effort's scope was being parked in Fog too, where it read as takeable frontier (an unblocked, unclaimed ticket is indistinguishable from a live one). Add a dedicated `## Deferred` section for beyond-the-destination work: it never graduates (the frontier stops at the destination) and returns only as a fresh effort if the destination is redrawn. The "Fog or ticket?" test becomes "Fog, ticket, or deferred?", gated on scope as well as sharpness, and both charting and working-the-map now defer a mis-scoped ticket (close it, one line in Deferred) rather than leaving it on the frontier or logging it in Decisions so far. Builds on #455 (destination as the leading word / destination fixes scope). Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-deferred-section.md | 7 +++++++ skills/in-progress/wayfinder/SKILL.md | 21 +++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 .changeset/wayfinder-deferred-section.md diff --git a/.changeset/wayfinder-deferred-section.md b/.changeset/wayfinder-deferred-section.md new file mode 100644 index 0000000..070b140 --- /dev/null +++ b/.changeset/wayfinder-deferred-section.md @@ -0,0 +1,7 @@ +--- +"mattpocock-skills": minor +--- + +Give **`wayfinder`** a distinct **`## Deferred`** section for work that lies _beyond_ the destination, separating it from Fog. + +Fog is the undiscovered frontier _toward_ the destination — in scope, just not yet sharp — so it graduates into tickets as the frontier advances. Work ruled out of _this_ effort's scope was being parked in Fog too, where it read as takeable frontier. It now has its own home: the `## Deferred` section, which never graduates (the frontier stops at the destination) and returns only as a fresh effort if the destination is redrawn. The "Fog or ticket?" test becomes "Fog, ticket, or deferred?" — gated on scope as well as sharpness — and both charting and working-the-map now defer a ticket found beyond the destination (close it, record one line in Deferred) rather than leaving it on the frontier or logging it in Decisions so far. diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 1b72ca0..7342783 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -41,6 +41,10 @@ The whole map at low resolution, loaded once per session. Open tickets are **not ## Fog + +## Deferred + + ``` ### Tickets @@ -72,14 +76,19 @@ The answer isn't part of the body — it's recorded on resolution (see [Work thr The map is _deliberately_ incomplete: don't chart what you can't yet see. Beyond the tickets lies fog — the dim view of decisions and investigations you can tell are coming but can't yet pin down, because they hang on questions still open. Resolving a ticket clears the fog ahead of it, graduating whatever's now specifiable into fresh tickets — one at a time, until the way to the destination is clear and no tickets remain. -The map's **Fog** section is where that dim view is written down: the suspected question, the area to revisit later, the risk you're deferring. Write as loosely or as fully as the view allows; it doubles as a signpost for collaborators reading where the effort is headed. +The map's **Fog** section is where that dim view is written down: the suspected question, the area to revisit later. It's the undiscovered frontier _toward_ the destination — everything here is in scope, just not yet sharp. Write as loosely or as fully as the view allows; it doubles as a signpost for collaborators reading where the effort is headed. -**Fog or ticket?** The test is whether you can state the question precisely now — _not_ whether you can answer it now. +**Beyond the destination is not fog.** The destination fixes the scope, so anything past it is out of scope no matter how clearly you can see it — and fog, by its nature, points _toward_ the destination, so out-of-scope work doesn't belong there. It goes in the map's **Deferred** section: work you've consciously ruled out of _this_ effort. Fog graduates into tickets as the frontier advances; Deferred never does, because the frontier stops at the destination. -- **Ticket when** the question is already sharp — even if it's blocked and you can't act on it yet. -- **Fog when** you can't yet phrase it that sharply. Don't pre-slice fog into ticket-sized pieces: it's coarser than a ticket, and one patch may graduate into several tickets, or none, once the frontier reaches it. +**Fog, ticket, or deferred?** Two questions: is it _within_ the destination's scope, and can you _state_ it sharply now? -Fog excludes only what's already decided (that's Decisions so far) and what's already a ticket. +- **Ticket when** it's in scope and the question is already sharp — even if it's blocked and you can't act on it yet. +- **Fog when** it's in scope but you can't yet phrase it that sharply. Don't pre-slice fog into ticket-sized pieces: it's coarser than a ticket, and one patch may graduate into several tickets, or none, once the frontier reaches it. +- **Deferred when** it lies _beyond_ the destination — however sharply you can phrase it. Scope, not sharpness, lands it here. + +Deferring is a scoping act, not a step on the route. When a ticket that already exists turns out to sit past the destination — mis-scoped in while charting, or exposed by a resolution — **close it** (a closed ticket is unambiguously off the frontier) and leave one line in the **Deferred** section: the gist plus why it's out of scope, linking the closed ticket. It stays out of **Decisions so far**, which records the route actually walked — a scope boundary isn't a step on it. If the destination is ever redrawn to include it, it returns as a fresh effort, not a resumption. + +Fog excludes what's already decided (Decisions so far), what's already a ticket, and what lies beyond the destination (Deferred). ## Invocation @@ -103,6 +112,6 @@ User invokes with a map (URL or number). A ticket is **optional** — without on 2. Choose the ticket. If the user named one, use it. Otherwise take the first frontier ticket in order. **Claim it**: assign it to yourself before any work. 3. Resolve it — **zoom as needed**: fetch the full body of any related or closed ticket on demand; invoke the skills the `## Notes` block names. If in doubt, use `/grilling` and `/domain-modeling`. 4. Record the resolution: post the answer as a **resolution comment**, **close** the issue, and **append a context pointer** to the map's Decisions-so-far. -5. Add newly-surfaced tickets (create-then-wire); graduate any fog the answer has made specifiable, clearing each graduated patch from the Fog so it lives only as its new ticket. If the decision invalidates other parts of the map, update or delete those tickets. +5. Add newly-surfaced tickets (create-then-wire); graduate any fog the answer has made specifiable, clearing each graduated patch from the Fog so it lives only as its new ticket. If the answer reveals a ticket — this one or another — sits beyond the destination, **defer** it instead of resolving it on the route: close it and record one line in Deferred. If the decision invalidates other parts of the map, update or delete those tickets. The user may run unblocked tickets in parallel, so expect other sessions to be editing the tracker concurrently. From 3ea01314c16e374230be29cd8b067924f000ea6e Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Sun, 5 Jul 2026 17:35:50 +0100 Subject: [PATCH 23/36] Rename the two buckets to plain map headings: Not yet specified / Out of scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following review: the map-body headings a cold reader sees should be self-evident without having read the skill, so drop the metaphor from the headings — `## Not yet specified` (in-scope, unripe) and `## Out of scope` (beyond the destination). Keep **fog of war** as the leading word: it still titles the explanatory section and drives the "clears the fog" / "graduate the fog" behavior in the prose. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-deferred-section.md | 6 +++-- skills/in-progress/wayfinder/SKILL.md | 30 ++++++++++++------------ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/.changeset/wayfinder-deferred-section.md b/.changeset/wayfinder-deferred-section.md index 070b140..327ffff 100644 --- a/.changeset/wayfinder-deferred-section.md +++ b/.changeset/wayfinder-deferred-section.md @@ -2,6 +2,8 @@ "mattpocock-skills": minor --- -Give **`wayfinder`** a distinct **`## Deferred`** section for work that lies _beyond_ the destination, separating it from Fog. +Split **`wayfinder`**'s map-body catch-all into two plainly-named sections — **`## Not yet specified`** and **`## Out of scope`** — so a cold reader can tell in-scope-but-unripe work from work ruled beyond the destination. -Fog is the undiscovered frontier _toward_ the destination — in scope, just not yet sharp — so it graduates into tickets as the frontier advances. Work ruled out of _this_ effort's scope was being parked in Fog too, where it read as takeable frontier. It now has its own home: the `## Deferred` section, which never graduates (the frontier stops at the destination) and returns only as a fresh effort if the destination is redrawn. The "Fog or ticket?" test becomes "Fog, ticket, or deferred?" — gated on scope as well as sharpness — and both charting and working-the-map now defer a ticket found beyond the destination (close it, record one line in Deferred) rather than leaving it on the frontier or logging it in Decisions so far. +Previously both lived under one `## Fog` heading, where out-of-scope work read as takeable frontier (an unblocked, unclaimed item is indistinguishable from a live ticket). Now: *Not yet specified* is the in-scope frontier that graduates into tickets as decisions resolve; *Out of scope* is beyond the destination, closed and never graduating, returning only as a fresh effort if the destination is redrawn. The "Fog or ticket?" test becomes "Ticket, not-yet-specified, or out of scope?", gated on scope as well as sharpness, and both charting and working-the-map now rule a beyond-destination ticket out of scope (close it, one line in *Out of scope*) rather than leaving it on the frontier or logging it in *Decisions so far*. + +The **fog of war** leading word is retained — it still names the concept and drives the graduate-the-fog behavior in the skill's prose; only the human-facing map headings go to plain language. diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 7342783..2aff9f7 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -38,13 +38,13 @@ The whole map at low resolution, loaded once per session. Open tickets are **not - [](link) — -## Fog +## Not yet specified - + -## Deferred +## Out of scope - + ``` ### Tickets @@ -74,21 +74,21 @@ The answer isn't part of the body — it's recorded on resolution (see [Work thr ## Fog of war -The map is _deliberately_ incomplete: don't chart what you can't yet see. Beyond the tickets lies fog — the dim view of decisions and investigations you can tell are coming but can't yet pin down, because they hang on questions still open. Resolving a ticket clears the fog ahead of it, graduating whatever's now specifiable into fresh tickets — one at a time, until the way to the destination is clear and no tickets remain. +The map is _deliberately_ incomplete: don't chart what you can't yet see. Beyond the live tickets lies the **fog of war** — the dim view of decisions and investigations you can tell are coming but can't yet pin down, because they hang on questions still open. Resolving a ticket clears the fog ahead of it, graduating whatever's now specifiable into fresh tickets — one at a time, until the way to the destination is clear and no tickets remain. -The map's **Fog** section is where that dim view is written down: the suspected question, the area to revisit later. It's the undiscovered frontier _toward_ the destination — everything here is in scope, just not yet sharp. Write as loosely or as fully as the view allows; it doubles as a signpost for collaborators reading where the effort is headed. +The map's **Not yet specified** section is where that dim view is written down: the suspected question, the area to revisit later. It's the undiscovered frontier _toward_ the destination — everything here is in scope, just not sharp enough to ticket. Write as loosely or as fully as the view allows; it doubles as a signpost for collaborators reading where the effort is headed. -**Beyond the destination is not fog.** The destination fixes the scope, so anything past it is out of scope no matter how clearly you can see it — and fog, by its nature, points _toward_ the destination, so out-of-scope work doesn't belong there. It goes in the map's **Deferred** section: work you've consciously ruled out of _this_ effort. Fog graduates into tickets as the frontier advances; Deferred never does, because the frontier stops at the destination. +**Beyond the destination is a different thing.** The destination fixes the scope, so anything past it is out of scope no matter how clearly you can see it — the fog only ever gathers _toward_ the destination, never past it. Out-of-scope work goes in the map's **Out of scope** section: work you've consciously ruled out of _this_ effort. Not-yet-specified work graduates into tickets as the frontier advances; out-of-scope work never does, because the frontier stops at the destination. -**Fog, ticket, or deferred?** Two questions: is it _within_ the destination's scope, and can you _state_ it sharply now? +**Ticket, not-yet-specified, or out of scope?** Two questions: is it _within_ the destination's scope, and can you _state_ it sharply now? - **Ticket when** it's in scope and the question is already sharp — even if it's blocked and you can't act on it yet. -- **Fog when** it's in scope but you can't yet phrase it that sharply. Don't pre-slice fog into ticket-sized pieces: it's coarser than a ticket, and one patch may graduate into several tickets, or none, once the frontier reaches it. -- **Deferred when** it lies _beyond_ the destination — however sharply you can phrase it. Scope, not sharpness, lands it here. +- **Not yet specified when** it's in scope but you can't yet phrase it that sharply. Don't pre-slice it into ticket-sized pieces: it's coarser than a ticket, and one patch may graduate into several tickets, or none, once the frontier reaches it. +- **Out of scope when** it lies _beyond_ the destination — however sharply you can phrase it. Scope, not sharpness, lands it here. -Deferring is a scoping act, not a step on the route. When a ticket that already exists turns out to sit past the destination — mis-scoped in while charting, or exposed by a resolution — **close it** (a closed ticket is unambiguously off the frontier) and leave one line in the **Deferred** section: the gist plus why it's out of scope, linking the closed ticket. It stays out of **Decisions so far**, which records the route actually walked — a scope boundary isn't a step on it. If the destination is ever redrawn to include it, it returns as a fresh effort, not a resumption. +Ruling something out of scope is a scoping act, not a step on the route. When a ticket that already exists turns out to sit past the destination — mis-scoped in while charting, or exposed by a resolution — **close it** (a closed ticket is unambiguously off the frontier) and leave one line in the **Out of scope** section: the gist plus why it's out of scope, linking the closed ticket. It stays out of **Decisions so far**, which records the route actually walked — a scope boundary isn't a step on it. If the destination is ever redrawn to include it, it comes back as a fresh effort, not a resumption. -Fog excludes what's already decided (Decisions so far), what's already a ticket, and what lies beyond the destination (Deferred). +**Not yet specified** excludes what's already decided (Decisions so far), what's already a live ticket, and what's out of scope (its own section). ## Invocation @@ -100,8 +100,8 @@ User invokes with a loose idea. 1. **Name the destination.** Run a `/grilling` and `/domain-modeling` session to pin down what this map is finding its way to — the spec, decision, or change. The destination fixes the scope, so it's settled first. 2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. -3. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, Fog sketched. -4. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the Fog. +3. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, the fog sketched into **Not yet specified**. +4. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the fog — the **Not yet specified** section. 5. Stop — charting the map is one session's work; do not also resolve tickets. ### Work through the map @@ -112,6 +112,6 @@ User invokes with a map (URL or number). A ticket is **optional** — without on 2. Choose the ticket. If the user named one, use it. Otherwise take the first frontier ticket in order. **Claim it**: assign it to yourself before any work. 3. Resolve it — **zoom as needed**: fetch the full body of any related or closed ticket on demand; invoke the skills the `## Notes` block names. If in doubt, use `/grilling` and `/domain-modeling`. 4. Record the resolution: post the answer as a **resolution comment**, **close** the issue, and **append a context pointer** to the map's Decisions-so-far. -5. Add newly-surfaced tickets (create-then-wire); graduate any fog the answer has made specifiable, clearing each graduated patch from the Fog so it lives only as its new ticket. If the answer reveals a ticket — this one or another — sits beyond the destination, **defer** it instead of resolving it on the route: close it and record one line in Deferred. If the decision invalidates other parts of the map, update or delete those tickets. +5. Add newly-surfaced tickets (create-then-wire); graduate any fog the answer has made specifiable, clearing each graduated patch from **Not yet specified** so it lives only as its new ticket. If the answer reveals a ticket — this one or another — sits beyond the destination, **rule it out of scope** instead of resolving it on the route: close it and record one line in **Out of scope**. If the decision invalidates other parts of the map, update or delete those tickets. The user may run unblocked tickets in parallel, so expect other sessions to be editing the tracker concurrently. From 7d34a8dc38bdb34dadb69109aa2173aad69d8514 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Sun, 5 Jul 2026 17:44:13 +0100 Subject: [PATCH 24/36] Split fog and out-of-scope into separate explanatory sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QA follow-up: the Fog of war section was teaching both concepts, which muddies the leading word — fog should point only *toward* the destination. Now Fog of war teaches only the not-yet-specified bucket (with the two-way fog-or-ticket sharpness test restored), and a new Out of scope section owns the scope axis: beyond the destination, closed not graduating, kept out of Decisions so far. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-deferred-section.md | 8 +++++--- skills/in-progress/wayfinder/SKILL.md | 19 +++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/.changeset/wayfinder-deferred-section.md b/.changeset/wayfinder-deferred-section.md index 327ffff..457c64c 100644 --- a/.changeset/wayfinder-deferred-section.md +++ b/.changeset/wayfinder-deferred-section.md @@ -2,8 +2,10 @@ "mattpocock-skills": minor --- -Split **`wayfinder`**'s map-body catch-all into two plainly-named sections — **`## Not yet specified`** and **`## Out of scope`** — so a cold reader can tell in-scope-but-unripe work from work ruled beyond the destination. +Give **`wayfinder`** a first-class notion of **out of scope**, separate from fog. -Previously both lived under one `## Fog` heading, where out-of-scope work read as takeable frontier (an unblocked, unclaimed item is indistinguishable from a live ticket). Now: *Not yet specified* is the in-scope frontier that graduates into tickets as decisions resolve; *Out of scope* is beyond the destination, closed and never graduating, returning only as a fresh effort if the destination is redrawn. The "Fog or ticket?" test becomes "Ticket, not-yet-specified, or out of scope?", gated on scope as well as sharpness, and both charting and working-the-map now rule a beyond-destination ticket out of scope (close it, one line in *Out of scope*) rather than leaving it on the frontier or logging it in *Decisions so far*. +Fog and out-of-scope were conflated under one `## Fog` map section, gated by different things: fog by *knowledge* (can't specify it yet — in scope, unripe, graduates as the frontier advances), out-of-scope by *scope* (beyond the destination — never graduates). Cramming both under "Fog" made out-of-scope work read as takeable frontier (an unblocked, unclaimed item is indistinguishable from a live ticket). -The **fog of war** leading word is retained — it still names the concept and drives the graduate-the-fog behavior in the skill's prose; only the human-facing map headings go to plain language. +Now the map body has two plainly-named sections — **`## Not yet specified`** and **`## Out of scope`** — and the skill's prose splits to match: the **Fog of war** section teaches only the not-yet-specified bucket and keeps the two-way *fog-or-ticket* sharpness test, while a new **Out of scope** section owns the scope axis (beyond the destination, closed not graduating, returns only as a fresh effort if the destination is redrawn). Charting and working-the-map now rule a beyond-destination ticket out of scope — close it, one line in *Out of scope* — rather than leaving it on the frontier or logging it in *Decisions so far*. + +The **fog of war** leading word is retained: it names the concept and drives the graduate-the-fog behavior in the prose; only the human-facing map headings go to plain language. diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 2aff9f7..6376ab5 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -44,7 +44,7 @@ The whole map at low resolution, loaded once per session. Open tickets are **not ## Out of scope - + ``` ### Tickets @@ -78,17 +78,20 @@ The map is _deliberately_ incomplete: don't chart what you can't yet see. Beyond The map's **Not yet specified** section is where that dim view is written down: the suspected question, the area to revisit later. It's the undiscovered frontier _toward_ the destination — everything here is in scope, just not sharp enough to ticket. Write as loosely or as fully as the view allows; it doubles as a signpost for collaborators reading where the effort is headed. -**Beyond the destination is a different thing.** The destination fixes the scope, so anything past it is out of scope no matter how clearly you can see it — the fog only ever gathers _toward_ the destination, never past it. Out-of-scope work goes in the map's **Out of scope** section: work you've consciously ruled out of _this_ effort. Not-yet-specified work graduates into tickets as the frontier advances; out-of-scope work never does, because the frontier stops at the destination. +**Fog or ticket?** The test is whether you can state the question precisely now — _not_ whether you can answer it now. -**Ticket, not-yet-specified, or out of scope?** Two questions: is it _within_ the destination's scope, and can you _state_ it sharply now? +- **Ticket when** the question is already sharp — even if it's blocked and you can't act on it yet. +- **Not yet specified when** you can't yet phrase it that sharply. Don't pre-slice the fog into ticket-sized pieces: it's coarser than a ticket, and one patch may graduate into several tickets, or none, once the frontier reaches it. -- **Ticket when** it's in scope and the question is already sharp — even if it's blocked and you can't act on it yet. -- **Not yet specified when** it's in scope but you can't yet phrase it that sharply. Don't pre-slice it into ticket-sized pieces: it's coarser than a ticket, and one patch may graduate into several tickets, or none, once the frontier reaches it. -- **Out of scope when** it lies _beyond_ the destination — however sharply you can phrase it. Scope, not sharpness, lands it here. +**Not yet specified** excludes what's already decided (Decisions so far), what's already a live ticket, and what's out of scope (the next section). -Ruling something out of scope is a scoping act, not a step on the route. When a ticket that already exists turns out to sit past the destination — mis-scoped in while charting, or exposed by a resolution — **close it** (a closed ticket is unambiguously off the frontier) and leave one line in the **Out of scope** section: the gist plus why it's out of scope, linking the closed ticket. It stays out of **Decisions so far**, which records the route actually walked — a scope boundary isn't a step on it. If the destination is ever redrawn to include it, it comes back as a fresh effort, not a resumption. +## Out of scope -**Not yet specified** excludes what's already decided (Decisions so far), what's already a live ticket, and what's out of scope (its own section). +Fog only ever gathers _toward_ the destination. The destination fixes the scope, so work beyond it is **out of scope** — however sharply you can see it, it isn't fog, and it doesn't belong in **Not yet specified**. It gets its own **Out of scope** section on the map: work you've consciously ruled out of _this_ effort. Scope, not sharpness, lands it here. + +Out-of-scope work never graduates — the frontier stops at the destination — so it returns only if the destination is redrawn, and then as a fresh effort, not a resumption. + +Ruling something out of scope is a scoping act, not a step on the route. When a ticket that already exists turns out to sit past the destination — mis-scoped in while charting, or exposed by a resolution — **close it** (a closed ticket is unambiguously off the frontier) and leave one line in the **Out of scope** section: the gist plus why it's out of scope, linking the closed ticket. It stays out of **Decisions so far**, which records the route actually walked — a scope boundary isn't a step on it. ## Invocation From 97dca07b64b3656061f485733e818a412af7764b Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Sun, 5 Jul 2026 17:48:56 +0100 Subject: [PATCH 25/36] Duplication pass: collapse restated out-of-scope mechanics - Out of scope section: drop embedded 'however sharply you can see it' duplicate; the 'Scope, not sharpness, lands it here' punchline carries the claim once. - Work-through step 5: delegate close+one-line mechanics to the Out of scope section via the 'rule it out of scope' leading phrase instead of restating them. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/wayfinder/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 6376ab5..0c5e652 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -87,7 +87,7 @@ The map's **Not yet specified** section is where that dim view is written down: ## Out of scope -Fog only ever gathers _toward_ the destination. The destination fixes the scope, so work beyond it is **out of scope** — however sharply you can see it, it isn't fog, and it doesn't belong in **Not yet specified**. It gets its own **Out of scope** section on the map: work you've consciously ruled out of _this_ effort. Scope, not sharpness, lands it here. +Fog only ever gathers _toward_ the destination. The destination fixes the scope, so work beyond it is **out of scope** — it isn't fog, and it doesn't belong in **Not yet specified**. It gets its own **Out of scope** section on the map: work you've consciously ruled out of _this_ effort. Scope, not sharpness, lands it here. Out-of-scope work never graduates — the frontier stops at the destination — so it returns only if the destination is redrawn, and then as a fresh effort, not a resumption. @@ -115,6 +115,6 @@ User invokes with a map (URL or number). A ticket is **optional** — without on 2. Choose the ticket. If the user named one, use it. Otherwise take the first frontier ticket in order. **Claim it**: assign it to yourself before any work. 3. Resolve it — **zoom as needed**: fetch the full body of any related or closed ticket on demand; invoke the skills the `## Notes` block names. If in doubt, use `/grilling` and `/domain-modeling`. 4. Record the resolution: post the answer as a **resolution comment**, **close** the issue, and **append a context pointer** to the map's Decisions-so-far. -5. Add newly-surfaced tickets (create-then-wire); graduate any fog the answer has made specifiable, clearing each graduated patch from **Not yet specified** so it lives only as its new ticket. If the answer reveals a ticket — this one or another — sits beyond the destination, **rule it out of scope** instead of resolving it on the route: close it and record one line in **Out of scope**. If the decision invalidates other parts of the map, update or delete those tickets. +5. Add newly-surfaced tickets (create-then-wire); graduate any fog the answer has made specifiable, clearing each graduated patch from **Not yet specified** so it lives only as its new ticket. If the answer reveals a ticket — this one or another — sits beyond the destination, **rule it out of scope** rather than resolving it on the route. If the decision invalidates other parts of the map, update or delete those tickets. The user may run unblocked tickets in parallel, so expect other sessions to be editing the tracker concurrently. From 0172e61e57c9cae07955e8e30a0f010cee3dbe54 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 6 Jul 2026 13:23:00 +0100 Subject: [PATCH 26/36] to-issues: prefer native sub-issues; reference /prototype code explicitly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two minimal edits to the to-issues skill: - The "What to build" template now points explicitly at the `/prototype` skill's code as the source of an inlined decision snippet, rather than gesturing at "a prototype". - Publishing now prefers the tracker's native sub-issues (parent → slice) and native blocking edges (Blocked by) where supported — mechanics already documented in the issue-tracker doc — keeping the `## Parent` and `## Blocked by` body sections as the fallback. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/to-issues-sub-issues-and-prototype.md | 5 +++++ skills/engineering/to-issues/SKILL.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/to-issues-sub-issues-and-prototype.md diff --git a/.changeset/to-issues-sub-issues-and-prototype.md b/.changeset/to-issues-sub-issues-and-prototype.md new file mode 100644 index 0000000..273605c --- /dev/null +++ b/.changeset/to-issues-sub-issues-and-prototype.md @@ -0,0 +1,5 @@ +--- +"mattpocock-skills": minor +--- + +Sharpen how the **`to-issues`** skill records structure. The "What to build" template now adds a context pointer to where the **`/prototype`** skill's code lives, rather than inlining a snippet from it. And publishing now prefers the tracker's **native sub-issues** for parent → slice and **native blocking edges** for `Blocked by` where the tracker supports them (mechanics already live in the issue-tracker doc), keeping the `## Parent` / `## Blocked by` body sections as the fallback. diff --git a/skills/engineering/to-issues/SKILL.md b/skills/engineering/to-issues/SKILL.md index 333f1ee..4a79f28 100644 --- a/skills/engineering/to-issues/SKILL.md +++ b/skills/engineering/to-issues/SKILL.md @@ -54,7 +54,7 @@ Iterate until the user approves the breakdown. For each approved slice, publish a new issue to the issue tracker. Use the issue body template below. These issues are considered ready for AFK agents, so publish them with the correct triage label unless instructed otherwise. -Publish issues in dependency order (blockers first) so you can reference real issue identifiers in the "Blocked by" field. +Publish issues in dependency order (blockers first) so you can reference real issue identifiers. Where the tracker supports it, link each slice to its parent as a native **sub-issue** and wire each blocker as a native **blocking edge** (mechanics in the issue-tracker doc); the `## Parent` and `## Blocked by` body sections are the fallback otherwise. ## Parent @@ -65,7 +65,7 @@ A reference to the parent issue on the issue tracker (if the source was an exist A concise description of this vertical slice. Describe the end-to-end behavior, not layer-by-layer implementation. -Avoid specific file paths or code snippets — they go stale fast. Exception: if a prototype produced a snippet that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), inline it here and note briefly that it came from a prototype. Trim to the decision-rich parts — not a working demo, just the important bits. +Avoid specific file paths or code snippets — they go stale fast. Exception: if the `/prototype` skill produced code that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), add a context pointer to where that prototype code lives rather than inlining it. ## Acceptance criteria From 55511cea24e163655a8cb7f9e463acb0913b7fdc Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 6 Jul 2026 13:36:44 +0100 Subject: [PATCH 27/36] wayfinder: restore no-fog early exit Bring back the "skip the map when there's no fog" branch that was collateral-deleted with the Handoff section. Co-located in Chart the map step 2, where the fog/no-fog outcome is determined: if breadth-first grilling surfaces no fog, offer to skip the map and implement directly. The offer (ask, don't auto-skip) is preserved from the original. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-no-fog-early-exit.md | 9 +++++++++ skills/in-progress/wayfinder/SKILL.md | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 .changeset/wayfinder-no-fog-early-exit.md diff --git a/.changeset/wayfinder-no-fog-early-exit.md b/.changeset/wayfinder-no-fog-early-exit.md new file mode 100644 index 0000000..aa881c7 --- /dev/null +++ b/.changeset/wayfinder-no-fog-early-exit.md @@ -0,0 +1,9 @@ +--- +"mattpocock-skills": patch +--- + +Restore **`wayfinder`**'s early exit when the frontier grilling turns up no fog. + +The skill used to have a **Skipping The Decision Map** section: if the opening grilling surfaced no fog of war, there was no map to build, so it offered to skip straight to implementing. That clause was demoted to a parenthetical inside the Handoff section, then deleted as collateral when Handoff was removed — never an intentional cut. + +It's back, co-located in **Chart the map** step 2 (Map the frontier), where the fog/no-fog outcome is actually determined: if breadth-first grilling surfaces no fog, tell the user and offer to skip the map, implementing directly instead. The offer — asking rather than auto-skipping — is preserved from the original. diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 0c5e652..a76d018 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -102,7 +102,7 @@ Two modes. Either way, **never resolve more than one ticket per session.** User invokes with a loose idea. 1. **Name the destination.** Run a `/grilling` and `/domain-modeling` session to pin down what this map is finding its way to — the spec, decision, or change. The destination fixes the scope, so it's settled first. -2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. +2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. **If this surfaces no fog** — every decision already takeable, the way to the destination clear — there's nothing to chart: tell the user and offer to skip the map, implementing directly instead. 3. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, the fog sketched into **Not yet specified**. 4. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the fog — the **Not yet specified** section. 5. Stop — charting the map is one session's work; do not also resolve tickets. From ad99c73a2d28e9642118137d2f2f672a9b56bb52 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 6 Jul 2026 13:38:59 +0100 Subject: [PATCH 28/36] wayfinder: reframe no-fog exit as too-small-for-a-map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not "implement directly" — the point is the journey fits one session and doesn't justify a map. Stop and ask the user how to proceed. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-no-fog-early-exit.md | 2 +- skills/in-progress/wayfinder/SKILL.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/wayfinder-no-fog-early-exit.md b/.changeset/wayfinder-no-fog-early-exit.md index aa881c7..4e9ccde 100644 --- a/.changeset/wayfinder-no-fog-early-exit.md +++ b/.changeset/wayfinder-no-fog-early-exit.md @@ -6,4 +6,4 @@ Restore **`wayfinder`**'s early exit when the frontier grilling turns up no fog. The skill used to have a **Skipping The Decision Map** section: if the opening grilling surfaced no fog of war, there was no map to build, so it offered to skip straight to implementing. That clause was demoted to a parenthetical inside the Handoff section, then deleted as collateral when Handoff was removed — never an intentional cut. -It's back, co-located in **Chart the map** step 2 (Map the frontier), where the fog/no-fog outcome is actually determined: if breadth-first grilling surfaces no fog, tell the user and offer to skip the map, implementing directly instead. The offer — asking rather than auto-skipping — is preserved from the original. +It's back, co-located in **Chart the map** step 2 (Map the frontier), where the fog/no-fog outcome is actually determined: if breadth-first grilling surfaces no fog — the journey is small enough for one session — there's no map to justify, so stop and ask the user how they'd like to proceed. The ask, rather than an auto-skip, is preserved from the original. diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index a76d018..abf8054 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -102,7 +102,7 @@ Two modes. Either way, **never resolve more than one ticket per session.** User invokes with a loose idea. 1. **Name the destination.** Run a `/grilling` and `/domain-modeling` session to pin down what this map is finding its way to — the spec, decision, or change. The destination fixes the scope, so it's settled first. -2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. **If this surfaces no fog** — every decision already takeable, the way to the destination clear — there's nothing to chart: tell the user and offer to skip the map, implementing directly instead. +2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. **If this surfaces no fog** — the way to the destination is already clear, the whole journey small enough for one session — there's no map to justify. Stop and ask the user how they'd like to proceed. 3. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, the fog sketched into **Not yet specified**. 4. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the fog — the **Not yet specified** section. 5. Stop — charting the map is one session's work; do not also resolve tickets. From 9b43c3359b1600c6ac47857f5834a39a371235c1 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 6 Jul 2026 13:40:26 +0100 Subject: [PATCH 29/36] =?UTF-8?q?wayfinder:=20simpler=20no-fog=20wording?= =?UTF-8?q?=20=E2=80=94=20'you=20don't=20need=20a=20map'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-no-fog-early-exit.md | 2 +- skills/in-progress/wayfinder/SKILL.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/wayfinder-no-fog-early-exit.md b/.changeset/wayfinder-no-fog-early-exit.md index 4e9ccde..f8e685a 100644 --- a/.changeset/wayfinder-no-fog-early-exit.md +++ b/.changeset/wayfinder-no-fog-early-exit.md @@ -6,4 +6,4 @@ Restore **`wayfinder`**'s early exit when the frontier grilling turns up no fog. The skill used to have a **Skipping The Decision Map** section: if the opening grilling surfaced no fog of war, there was no map to build, so it offered to skip straight to implementing. That clause was demoted to a parenthetical inside the Handoff section, then deleted as collateral when Handoff was removed — never an intentional cut. -It's back, co-located in **Chart the map** step 2 (Map the frontier), where the fog/no-fog outcome is actually determined: if breadth-first grilling surfaces no fog — the journey is small enough for one session — there's no map to justify, so stop and ask the user how they'd like to proceed. The ask, rather than an auto-skip, is preserved from the original. +It's back, co-located in **Chart the map** step 2 (Map the frontier), where the fog/no-fog outcome is actually determined: if breadth-first grilling surfaces no fog — the journey is small enough for one session — you don't need a map, so stop and ask the user how they'd like to proceed. The ask, rather than an auto-skip, is preserved from the original. diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index abf8054..5e1b6cb 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -102,7 +102,7 @@ Two modes. Either way, **never resolve more than one ticket per session.** User invokes with a loose idea. 1. **Name the destination.** Run a `/grilling` and `/domain-modeling` session to pin down what this map is finding its way to — the spec, decision, or change. The destination fixes the scope, so it's settled first. -2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. **If this surfaces no fog** — the way to the destination is already clear, the whole journey small enough for one session — there's no map to justify. Stop and ask the user how they'd like to proceed. +2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. **If this surfaces no fog** — the way to the destination is already clear, the whole journey small enough for one session — you don't need a map. Stop and ask the user how they'd like to proceed. 3. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, the fog sketched into **Not yet specified**. 4. **Create the tickets you can specify now** as child issues of the map — then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the fog — the **Not yet specified** section. 5. Stop — charting the map is one session's work; do not also resolve tickets. From 80f29a4f29a6df088020916f30453d5e1a9cf6f5 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 6 Jul 2026 13:49:33 +0100 Subject: [PATCH 30/36] wayfinder: reassert planning-only purpose with a leading-word section Add a "Plan, don't do" section as the single source of truth for the plan/execute boundary, and bring two passages into line with it: - Destination is always a set of resolved decisions, never the executed change itself (the migration example previously read as execution). - The Task ticket type now earns its place only by unblocking a decision, pointing back to the new section rather than restating the principle. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/wayfinder/SKILL.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 5e1b6cb..3c08745 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -5,7 +5,13 @@ description: Plan a huge chunk of work — more than one agent session can hold A loose idea has arrived — too big for one agent session, and wrapped in fog: the way from here to the **destination** isn't visible yet. Wayfinding is about finding that way, not charging at the destination. This skill charts the way as a **shared map** on the repo's issue tracker, then works its tickets one at a time until the route is clear. -The destination varies per effort, and naming it is the first act of charting — it shapes every ticket. It might be a spec to hand off and iterate on, a decision to lock before planning starts, or a change made in place like a data-structure migration. The map is domain-agnostic — engineering work, course content, whatever fits the shape. +The destination varies per effort, and naming it is the first act of charting — it shapes every ticket. It might be a spec to hand off and iterate on, a single decision locked before planning starts, or a plan of attack for a change like a data-structure migration — but always a set of **resolved decisions**, never the executed change itself. The map is domain-agnostic — engineering work, course content, whatever fits the shape. + +## Plan, don't do + +Wayfinder is **planning**, not **execution**. Every ticket resolves a decision; the map is done when the way is clear — the point where someone could *go and do the thing* with nothing left to decide. The doing is a separate act, after the map closes. A session that starts building the destination — writing the migration, shipping the feature — has stopped wayfinding, and should stop. + +So the map's output is decisions, not deliverables. When you feel the pull to just do the work, that pull is the signal you've reached the edge of the map: the way is clear, and it's time to hand off. ## Refer by name @@ -70,7 +76,7 @@ The answer isn't part of the body — it's recorded on resolution (see [Work thr - **Research**: Reading documentation, third-party APIs, or local resources like knowledge bases. Creates a markdown summary as a linked asset. Use when knowledge outside the current working directory is required. - **Prototype**: Raise the fidelity of the discussion by making a cheap, rough, concrete artifact to react to — an outline, a rough take, a stub, or UI/logic code via the /prototype skill. Links the prototype as an asset. Use when "how should it look" or "how should it behave" is the key question. - **Grilling**: Conversation with the agent. Uses the /grilling and /domain-modeling skills. Asks one question at a time. The default case. -- **Task**: Literal manual work that must be done before the discussion can move forward — nothing to decide, prototype, or research. Moving data, signing up for a service, provisioning access. The agent automates it where it can; otherwise it hands the human a precise checklist. Resolved when the work is done; the answer records what was done and any resulting facts (credentials location, new URLs, row counts) later tickets depend on. +- **Task**: Manual work that must happen before a *decision* can be made — nothing to decide, prototype, or research, but the discussion is blocked until it's done. Signing up for a service so its API can be judged, provisioning access, moving data so its shape can be seen. This is the one type that *does* rather than decides, and it earns its place only by unblocking a decision — never by delivering the destination (that's execution; see [Plan, don't do](#plan-dont-do)). The agent automates it where it can; otherwise it hands the human a precise checklist. Resolved when the work is done; the answer records what was done and any resulting facts (credentials location, new URLs, row counts) later tickets depend on. ## Fog of war From 7be28cf5e64a7c990e42db44ea97665df2adfa75 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 6 Jul 2026 13:53:59 +0100 Subject: [PATCH 31/36] wayfinder: planning by default, overridable via Notes; shrink section Address review: don't preclude execution. Wayfinder is planning by default, but an effort's Notes can carry execution into the map. Collapse the section to one paragraph, revert the destination sentence to its original (which already allowed an executed change), and drop the Task cross-reference to match. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/wayfinder/SKILL.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index 3c08745..d7854ef 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -5,13 +5,11 @@ description: Plan a huge chunk of work — more than one agent session can hold A loose idea has arrived — too big for one agent session, and wrapped in fog: the way from here to the **destination** isn't visible yet. Wayfinding is about finding that way, not charging at the destination. This skill charts the way as a **shared map** on the repo's issue tracker, then works its tickets one at a time until the route is clear. -The destination varies per effort, and naming it is the first act of charting — it shapes every ticket. It might be a spec to hand off and iterate on, a single decision locked before planning starts, or a plan of attack for a change like a data-structure migration — but always a set of **resolved decisions**, never the executed change itself. The map is domain-agnostic — engineering work, course content, whatever fits the shape. +The destination varies per effort, and naming it is the first act of charting — it shapes every ticket. It might be a spec to hand off and iterate on, a decision to lock before planning starts, or a change made in place like a data-structure migration. The map is domain-agnostic — engineering work, course content, whatever fits the shape. ## Plan, don't do -Wayfinder is **planning**, not **execution**. Every ticket resolves a decision; the map is done when the way is clear — the point where someone could *go and do the thing* with nothing left to decide. The doing is a separate act, after the map closes. A session that starts building the destination — writing the migration, shipping the feature — has stopped wayfinding, and should stop. - -So the map's output is decisions, not deliverables. When you feel the pull to just do the work, that pull is the signal you've reached the edge of the map: the way is clear, and it's time to hand off. +Wayfinder is **planning** by default: each ticket resolves a decision, and the map is done when the way is clear — nothing left to decide before someone goes and does the thing. The pull to just do the work is usually the signal you've reached the edge of the map and it's time to hand off. An effort can override this in its **Notes** — carrying execution into the map itself — but absent that, produce decisions, not deliverables. ## Refer by name @@ -76,7 +74,7 @@ The answer isn't part of the body — it's recorded on resolution (see [Work thr - **Research**: Reading documentation, third-party APIs, or local resources like knowledge bases. Creates a markdown summary as a linked asset. Use when knowledge outside the current working directory is required. - **Prototype**: Raise the fidelity of the discussion by making a cheap, rough, concrete artifact to react to — an outline, a rough take, a stub, or UI/logic code via the /prototype skill. Links the prototype as an asset. Use when "how should it look" or "how should it behave" is the key question. - **Grilling**: Conversation with the agent. Uses the /grilling and /domain-modeling skills. Asks one question at a time. The default case. -- **Task**: Manual work that must happen before a *decision* can be made — nothing to decide, prototype, or research, but the discussion is blocked until it's done. Signing up for a service so its API can be judged, provisioning access, moving data so its shape can be seen. This is the one type that *does* rather than decides, and it earns its place only by unblocking a decision — never by delivering the destination (that's execution; see [Plan, don't do](#plan-dont-do)). The agent automates it where it can; otherwise it hands the human a precise checklist. Resolved when the work is done; the answer records what was done and any resulting facts (credentials location, new URLs, row counts) later tickets depend on. +- **Task**: Manual work that must happen before a *decision* can be made — nothing to decide, prototype, or research, but the discussion is blocked until it's done. Signing up for a service so its API can be judged, provisioning access, moving data so its shape can be seen. This is the one type that *does* rather than decides — and it earns its place by unblocking a decision, not by delivering the destination. The agent automates it where it can; otherwise it hands the human a precise checklist. Resolved when the work is done; the answer records what was done and any resulting facts (credentials location, new URLs, row counts) later tickets depend on. ## Fog of war From 0847bb31bcdc97bc28792adb1069d4e4b845976f Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 6 Jul 2026 13:54:46 +0100 Subject: [PATCH 32/36] writing-great-skills: add Negation and Negative Space failure modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two adjacent Steering failure modes about how language you think of as "off" still steers: - Negation — a prohibition names the forbidden behaviour and makes it more available, not less (don't-think-of-an-elephant). Cure: prompt the positive. - Negative Space — what you omit is delegated to the agent's priors, not left neutral. Cure: read a draft for what it's silent on and decide each omission deliberately. Each carried as a full GLOSSARY entry plus a SKILL.md failure-mode bullet, matching every other failure mode. Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/productivity/writing-great-skills/GLOSSARY.md | 12 ++++++++++++ skills/productivity/writing-great-skills/SKILL.md | 2 ++ 2 files changed, 14 insertions(+) diff --git a/skills/productivity/writing-great-skills/GLOSSARY.md b/skills/productivity/writing-great-skills/GLOSSARY.md index 969c699..59b4137 100644 --- a/skills/productivity/writing-great-skills/GLOSSARY.md +++ b/skills/productivity/writing-great-skills/GLOSSARY.md @@ -158,6 +158,18 @@ _Failure mode._ Ending the current step before it is genuinely done, because the _Avoid_: premature closure, the rush, rushing, shortcutting +### Negation + +_Failure mode._ Steering by prohibition — telling the agent what _not_ to do — which drags the forbidden behaviour into context and makes it _more_ available, not less. _Don't think of an elephant_, and the elephant is all there is; _never write verbose comments_, and verbosity is the pattern the agent has just read. The negation is a weak modifier the strongly-activated concept overruns, so the ban half-reads as an instruction to do the thing. Its **leading word** is the _elephant_: whatever a prohibition names into the frame. Cure: prompt the **positive** — describe the target behaviour ("write one-line comments") so the banned one is never spoken. A prohibition earns its place only as a hard guardrail on a behaviour you cannot phrase positively; even then, pair it with the positive target so attention lands on what to do. + +_Avoid_: ironic rebound, don't-prompting, the pink elephant + +### Negative Space + +_Failure mode._ Blindness to the steering done by what you leave _out_. Every decision a skill declines to make, the agent makes from its priors — the unsaid is not neutral, it is delegated. Say nothing about comment length and you have not left length open, you have handed it to the default. The art sense is exact: the shape is carved as much by the space around the subject as by the subject, and here the space is the omission the author never notices leaving. Distinct from **Negation**, which _names_ the wrong thing; Negative Space names nothing and lets the priors choose. Cure: read a draft for the decisions it is silent on, then decide each — fill the space with an explicit target where the default is wrong, and leave it open (a real **branch**) only where any reasonable default will do. + +_Avoid_: the void, omission, silent default + ## Pruning Keeping a skill lean — each remedy paired with the failure it cures. diff --git a/skills/productivity/writing-great-skills/SKILL.md b/skills/productivity/writing-great-skills/SKILL.md index 61abad4..6250d2a 100644 --- a/skills/productivity/writing-great-skills/SKILL.md +++ b/skills/productivity/writing-great-skills/SKILL.md @@ -80,3 +80,5 @@ Use these to diagnose issues the user may be having with the skill. - **Sediment** — stale layers that settle because adding feels safe and removing feels risky. The default fate of any skill without a pruning discipline. - **Sprawl** — a skill simply too long, even when every line is live and unique. Hurts readability and maintainability and wastes tokens. The cure is the ladder: disclose **reference** behind pointers, and split by **branch** or sequence so each path carries only what it needs. - **No-op** — a line the model already obeys by default, so you pay load to say nothing. The test: does it change behaviour versus the default? A weak leading word (_be thorough_ when the agent is already thorough-ish) is a no-op; the fix is a stronger word (_relentless_), not a different technique. +- **Negation** — steering by prohibition backfires: _don't think of an elephant_ names the elephant and makes it more available, not less. Prompt the **positive** — state the target behaviour so the banned one is never spoken; keep a prohibition only as a hard guardrail you can't phrase positively, and even then pair it with what to do instead. +- **Negative space** — what you leave _out_ steers too: every decision the skill declines, the agent makes from its priors, so the unsaid is delegated, not neutral. Read a draft for what it's silent on, then fill the space with an explicit target where the default is wrong — and leave it open only where any reasonable default does. From 30afefecc996f126ca0837c460323309e5b43931 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 6 Jul 2026 13:56:16 +0100 Subject: [PATCH 33/36] changeset for Negation and Negative Space failure modes Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/negation-and-negative-space.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/negation-and-negative-space.md diff --git a/.changeset/negation-and-negative-space.md b/.changeset/negation-and-negative-space.md new file mode 100644 index 0000000..a33ed93 --- /dev/null +++ b/.changeset/negation-and-negative-space.md @@ -0,0 +1,5 @@ +--- +"mattpocock-skills": minor +--- + +Add two adjacent Steering failure modes to **`writing-great-skills`**, both about how language you think of as "off" still steers the agent. **Negation** — the _elephant_ — is steering by prohibition: naming what _not_ to do drags the forbidden behaviour into context and makes it _more_ available, not less (_don't think of an elephant_), so the cure is to prompt the **positive**. **Negative Space** — the void — is blindness to the steering done by what you leave _out_: every decision a skill declines is delegated to the agent's priors rather than left neutral, so the cure is to read a draft for its silences and decide each omission deliberately (fill it, or leave it open as a real **branch**). Kept as two entries, not one — they carry different diagnostics and different cures — each a full `GLOSSARY.md` entry plus a `SKILL.md` failure-mode bullet, matching how every other failure mode is carried. From af6d6922c3e2b5288eef155346cbe319e4ed3bd0 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 6 Jul 2026 13:57:05 +0100 Subject: [PATCH 34/36] Drop Negative Space; keep Negation only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Negative Space read as clever but not actionable — "notice your silences" is fuzzy legwork the agent can't reliably act on. Negation stays: a checkable authoring failure with a positive-instruction cure. Co-Authored-By: Claude Opus 4.8 (1M context) --- ...ation-and-negative-space.md => negation-failure-mode.md} | 0 skills/productivity/writing-great-skills/GLOSSARY.md | 6 ------ skills/productivity/writing-great-skills/SKILL.md | 1 - 3 files changed, 7 deletions(-) rename .changeset/{negation-and-negative-space.md => negation-failure-mode.md} (100%) diff --git a/.changeset/negation-and-negative-space.md b/.changeset/negation-failure-mode.md similarity index 100% rename from .changeset/negation-and-negative-space.md rename to .changeset/negation-failure-mode.md diff --git a/skills/productivity/writing-great-skills/GLOSSARY.md b/skills/productivity/writing-great-skills/GLOSSARY.md index 59b4137..0269ca8 100644 --- a/skills/productivity/writing-great-skills/GLOSSARY.md +++ b/skills/productivity/writing-great-skills/GLOSSARY.md @@ -164,12 +164,6 @@ _Failure mode._ Steering by prohibition — telling the agent what _not_ to do _Avoid_: ironic rebound, don't-prompting, the pink elephant -### Negative Space - -_Failure mode._ Blindness to the steering done by what you leave _out_. Every decision a skill declines to make, the agent makes from its priors — the unsaid is not neutral, it is delegated. Say nothing about comment length and you have not left length open, you have handed it to the default. The art sense is exact: the shape is carved as much by the space around the subject as by the subject, and here the space is the omission the author never notices leaving. Distinct from **Negation**, which _names_ the wrong thing; Negative Space names nothing and lets the priors choose. Cure: read a draft for the decisions it is silent on, then decide each — fill the space with an explicit target where the default is wrong, and leave it open (a real **branch**) only where any reasonable default will do. - -_Avoid_: the void, omission, silent default - ## Pruning Keeping a skill lean — each remedy paired with the failure it cures. diff --git a/skills/productivity/writing-great-skills/SKILL.md b/skills/productivity/writing-great-skills/SKILL.md index 6250d2a..82abd0d 100644 --- a/skills/productivity/writing-great-skills/SKILL.md +++ b/skills/productivity/writing-great-skills/SKILL.md @@ -81,4 +81,3 @@ Use these to diagnose issues the user may be having with the skill. - **Sprawl** — a skill simply too long, even when every line is live and unique. Hurts readability and maintainability and wastes tokens. The cure is the ladder: disclose **reference** behind pointers, and split by **branch** or sequence so each path carries only what it needs. - **No-op** — a line the model already obeys by default, so you pay load to say nothing. The test: does it change behaviour versus the default? A weak leading word (_be thorough_ when the agent is already thorough-ish) is a no-op; the fix is a stronger word (_relentless_), not a different technique. - **Negation** — steering by prohibition backfires: _don't think of an elephant_ names the elephant and makes it more available, not less. Prompt the **positive** — state the target behaviour so the banned one is never spoken; keep a prohibition only as a hard guardrail you can't phrase positively, and even then pair it with what to do instead. -- **Negative space** — what you leave _out_ steers too: every decision the skill declines, the agent makes from its priors, so the unsaid is delegated, not neutral. Read a draft for what it's silent on, then fill the space with an explicit target where the default is wrong — and leave it open only where any reasonable default does. From e5932a7a47e5cae312c1b814ce6194b09aa27be1 Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 6 Jul 2026 13:48:56 +0100 Subject: [PATCH 35/36] wayfinder/grilling: stop the agent grilling itself Students reported /wayfinder picking a grilling ticket and grilling itself instead of turning to the human (confirmed by @_noshit / @maudova; Matt: "that sounds like a bug"). Root cause: a grilling line written for the live-human case ("explore the codebase instead") reads as license to answer questions autonomously once wayfinder runs it in a resolve-the-ticket frame. Fix with affirmative framing (no negative-space "don't"): - grilling: split facts (look up) from decisions (put to the human, wait) - wayfinder Grilling ticket type: a back-and-forth with the human, who answers each question - wayfinder Invocation: grilling always runs with the human in the loop Co-Authored-By: Claude Opus 4.8 (1M context) --- skills/in-progress/wayfinder/SKILL.md | 10 ++++++---- skills/productivity/grilling/SKILL.md | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/skills/in-progress/wayfinder/SKILL.md b/skills/in-progress/wayfinder/SKILL.md index d7854ef..6549dd3 100644 --- a/skills/in-progress/wayfinder/SKILL.md +++ b/skills/in-progress/wayfinder/SKILL.md @@ -71,10 +71,12 @@ The answer isn't part of the body — it's recorded on resolution (see [Work thr ## Ticket Types -- **Research**: Reading documentation, third-party APIs, or local resources like knowledge bases. Creates a markdown summary as a linked asset. Use when knowledge outside the current working directory is required. -- **Prototype**: Raise the fidelity of the discussion by making a cheap, rough, concrete artifact to react to — an outline, a rough take, a stub, or UI/logic code via the /prototype skill. Links the prototype as an asset. Use when "how should it look" or "how should it behave" is the key question. -- **Grilling**: Conversation with the agent. Uses the /grilling and /domain-modeling skills. Asks one question at a time. The default case. -- **Task**: Manual work that must happen before a *decision* can be made — nothing to decide, prototype, or research, but the discussion is blocked until it's done. Signing up for a service so its API can be judged, provisioning access, moving data so its shape can be seen. This is the one type that *does* rather than decides — and it earns its place by unblocking a decision, not by delivering the destination. The agent automates it where it can; otherwise it hands the human a precise checklist. Resolved when the work is done; the answer records what was done and any resulting facts (credentials location, new URLs, row counts) later tickets depend on. +Every ticket is either **HITL** — human in the loop, worked *with* a human who speaks for themselves — or **AFK**, driven by the agent alone. A HITL ticket only resolves through that live exchange; the agent never stands in for the human's side of it (a grilling agent that answers its own questions has broken this). + +- **Research** (AFK): Reading documentation, third-party APIs, or local resources like knowledge bases. Creates a markdown summary as a linked asset. Use when knowledge outside the current working directory is required. +- **Prototype** (HITL): Raise the fidelity of the discussion by making a cheap, rough, concrete artifact to react to — an outline, a rough take, a stub, or UI/logic code via the /prototype skill. Links the prototype as an asset. Use when "how should it look" or "how should it behave" is the key question. +- **Grilling** (HITL): Conversation via the /grilling and /domain-modeling skills, one question at a time. The default case. +- **Task** (HITL or AFK): Manual work that must happen before a *decision* can be made — nothing to decide, prototype, or research, but the discussion is blocked until it's done. Signing up for a service so its API can be judged, provisioning access, moving data so its shape can be seen. This is the one type that *does* rather than decides — and it earns its place by unblocking a decision, not by delivering the destination. The agent drives it alone where it can (AFK); otherwise it hands the human a precise checklist (HITL). Resolved when the work is done; the answer records what was done and any resulting facts (credentials location, new URLs, row counts) later tickets depend on. ## Fog of war diff --git a/skills/productivity/grilling/SKILL.md b/skills/productivity/grilling/SKILL.md index e220063..219930f 100644 --- a/skills/productivity/grilling/SKILL.md +++ b/skills/productivity/grilling/SKILL.md @@ -7,6 +7,6 @@ Interview me relentlessly about every aspect of this plan until we reach a share Ask the questions one at a time, waiting for feedback on each question before continuing. Asking multiple questions at once is bewildering. -If a question can be answered by exploring the codebase, explore the codebase instead. +If a *fact* can be found by exploring the codebase, look it up rather than asking me. The *decisions*, though, are mine — put each one to me and wait for my answer. Do not enact the plan until I confirm we have reached a shared understanding. From ce908a622007e2c290415e25bdaed70198afc30b Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Mon, 6 Jul 2026 13:52:20 +0100 Subject: [PATCH 36/36] Add changeset for the self-grilling fix Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/wayfinder-grilling-not-self.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .changeset/wayfinder-grilling-not-self.md diff --git a/.changeset/wayfinder-grilling-not-self.md b/.changeset/wayfinder-grilling-not-self.md new file mode 100644 index 0000000..8dbdd75 --- /dev/null +++ b/.changeset/wayfinder-grilling-not-self.md @@ -0,0 +1,12 @@ +--- +"mattpocock-skills": patch +--- + +Stop **`wayfinder`** grilling *itself* instead of the human, and classify ticket types by **HITL** / **AFK**. + +Students reported `/wayfinder` picking a **grilling** ticket and answering its own questions rather than turning to the human. Root cause: **`grilling`** carried a line written for the live-human case — "If a question can be answered by exploring the codebase, explore the codebase instead" — which, once `wayfinder` runs grilling inside a resolve-the-ticket frame, reads as license to answer questions autonomously and race the ticket to "resolved". + +Two changes: + +- **`grilling`** now splits *facts* (look them up) from *decisions* (put each one to the human and wait for their answer). +- **`wayfinder`** labels every ticket type **HITL** (human in the loop — Prototype, Grilling) or **AFK** (agent alone — Research; Task is either). A HITL ticket only resolves through the live exchange, so the "wait for the human" behaviour falls out of the label instead of being spelled out per type — a grilling agent that answers its own questions has, by definition, broken HITL.