Compare commits

...
Author SHA1 Message Date
Matt PocockandClaude Opus 4.8 d869d45afc fix(wayfinder): resolve issue-tracker doc via the CLAUDE.md pointer, not a hardcoded path
Wayfinder pinned the literal docs/agents/issue-tracker.md, breaking the
indirection to-issues/to-prd/triage rely on: they resolve the tracker
through the ### Issue tracker block setup writes into CLAUDE.md / AGENTS.md.
In repos that keep agent docs elsewhere, wayfinder silently fell back to
local-markdown. It now follows the same pointer and reads the doc's
"Wayfinding operations" section by name.

Closes #471

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 11:17:29 +01:00
Matt PocockandGitHub 8515a080a7 Merge pull request #469 from mattpocock/to-issues/wide-refactor-expand-contract
to-issues: slice wide refactors by expand–contract
2026-07-07 16:37:10 +01:00
Matt PocockandClaude Opus 4.8 f219e66379 to-issues: wrap issue template in XML tags
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 16:35:57 +01:00
Matt PocockandClaude Opus 4.8 aa591116bf to-issues: split into Process + Reference tiers
Revert the description change and keep the wide-refactor material in
one place. Reshape the skill into a lean Process (steps) and a
Reference section holding the vertical-slice rules, the wide-refactor
expand–contract rules, and the issue body template as co-located
blocks the steps point to.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 16:35:39 +01:00
Matt PocockandClaude Opus 4.8 a0329ba957 to-issues: slice wide refactors by expand–contract
Add a wide-refactor exception to the tracer-bullet rule: a single
mechanical change whose blast radius fans across the codebase can't
land as one green vertical slice. Seed "wide refactor" / "blast radius"
across the description, the explore step (detection), and the drafting
step (strategy), and give the expand–contract sequence in prose.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 16:32:47 +01:00
Matt PocockandGitHub 16a2a5cd00 Merge pull request #461 from mattpocock/fix/wayfinder-self-grilling
wayfinder/grilling: stop the agent grilling itself
2026-07-06 14:01:24 +01:00
Matt PocockandClaude Opus 4.8 ce908a6220 Add changeset for the self-grilling fix
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 13:59:13 +01:00
Matt PocockandGitHub d05f2fb5b5 Merge pull request #463 from mattpocock/negative-space-prompting
writing-great-skills: add Negation failure mode
2026-07-06 13:58:22 +01:00
Matt PocockandClaude Opus 4.8 e5932a7a47 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) <noreply@anthropic.com>
2026-07-06 13:57:47 +01:00
Matt PocockandClaude Opus 4.8 af6d6922c3 Drop Negative Space; keep Negation only
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) <noreply@anthropic.com>
2026-07-06 13:57:05 +01:00
Matt PocockandClaude Opus 4.8 30afefecc9 changeset for Negation and Negative Space failure modes
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 13:56:16 +01:00
Matt PocockandGitHub acf55d88b7 Merge pull request #462 from mattpocock/wayfinder/plan-not-execute
wayfinder: reassert planning-only purpose
2026-07-06 13:55:01 +01:00
Matt PocockandClaude Opus 4.8 0847bb31bc writing-great-skills: add Negation and Negative Space failure modes
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) <noreply@anthropic.com>
2026-07-06 13:54:46 +01:00
Matt PocockandClaude Opus 4.8 7be28cf5e6 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) <noreply@anthropic.com>
2026-07-06 13:53:59 +01:00
Matt PocockandClaude Opus 4.8 80f29a4f29 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) <noreply@anthropic.com>
2026-07-06 13:49:33 +01:00
Matt PocockandGitHub 5a7f7e5c2a Merge pull request #460 from mattpocock/wayfinder-no-fog-early-exit
wayfinder: restore no-fog early exit
2026-07-06 13:42:16 +01:00
Matt PocockandGitHub d11147daaf Merge pull request #459 from mattpocock/to-issues-sub-issues-and-prototype
to-issues: prefer native sub-issues; reference /prototype code explicitly
2026-07-06 13:35:18 +01:00
Matt PocockandClaude Opus 4.8 0172e61e57 to-issues: prefer native sub-issues; reference /prototype code explicitly
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) <noreply@anthropic.com>
2026-07-06 13:33:44 +01:00
11 changed files with 80 additions and 22 deletions
+5
View File
@@ -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.
@@ -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.
+5
View File
@@ -0,0 +1,5 @@
---
"mattpocock-skills": minor
---
Split the **`to-issues`** skill into a lean **Process** and a **Reference** section, and teach it to handle a **wide refactor** — a single mechanical change (like renaming a column) whose **blast radius** fans across the whole codebase, breaking thousands of call sites at once so no vertical slice can land green. The drafting step now points at two co-located reference blocks: the **Vertical slice rules** for ordinary tracer bullets, and **Wide refactors**, which slices the change by **expandcontract** (expand the new form beside the old, migrate call sites in batches sized by blast radius, then contract the old form away) so CI stays green batch to batch — or, when it can't, only at a final integrate-and-verify issue. The issue body template moves into Reference too.
+12
View File
@@ -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.
@@ -0,0 +1,7 @@
---
"mattpocock-skills": patch
---
Fix **`wayfinder`** hardcoding the issue-tracker doc path, which broke the indirection the rest of the suite relies on.
`to-issues`, `to-prd`, and `triage` never name a path — they resolve the tracker through the `### Issue tracker` block that `setup-matt-pocock-skills` writes into `CLAUDE.md` / `AGENTS.md`, which points at the tracker doc wherever it lives. Wayfinder instead pinned the literal `docs/agents/issue-tracker.md`, so in a repo that keeps its agent docs elsewhere it silently fell back to the local-markdown tracker — even one whose `CLAUDE.md` clearly declares GitHub issues. It now resolves the doc via that same pointer and reads its "Wayfinding operations" section by name, keeping the indirection consistent across the suite.
+4
View File
@@ -32,6 +32,10 @@ The whole skill turns on one distinction. A **horizontal** slice ships one layer
Before slicing, `to-issues` looks for prefactoring — "make the change easy, then make the easy change" — and orders that work first. It then quizzes you on the breakdown (granularity, dependencies, what to merge or split) before writing anything, and publishes blockers first so each issue's "Blocked by" field can reference a real ticket.
## The wide-refactor exception
One shape breaks the tracer-bullet rule: a **wide refactor** — a single mechanical change (rename a column, retype a shared symbol) whose **blast radius** fans across the whole codebase, so one edit breaks thousands of call sites at once and no vertical slice can land green. `to-issues` slices it as **expandcontract** instead: expand (add the new form beside the old so nothing breaks), migrate (move call sites over in batches sized by blast radius, one issue per batch, CI green throughout because the old form still exists), then contract (delete the old form once no caller remains). When even the batches can't stay green alone, they share an integration branch that all block a final integrate-and-verify issue, and green is promised only there.
## Where it fits
`to-issues` is a step in the main build chain:
+23 -16
View File
@@ -22,17 +22,9 @@ If you have not already explored the codebase, do so to understand the current s
Look for opportunities to prefactor the code to make the implementation easier. "Make the change easy, then make the easy change."
### 3. Draft vertical slices
### 3. Draft the issues
Break the plan into **tracer bullet** issues. Each issue is a thin vertical slice that cuts through ALL integration layers end-to-end, NOT a horizontal slice of one layer.
<vertical-slice-rules>
- Each slice delivers a narrow but COMPLETE path through every layer (schema, API, UI, tests)
- A completed slice is demoable or verifiable on its own
- Any prefactoring should be done first
</vertical-slice-rules>
Break the plan into **tracer bullet** issues, following the **Vertical slice rules**. A **wide refactor** is the exception to that rule — slice it by **expandcontract** instead (see **Wide refactors**).
### 4. Quiz the user
@@ -52,9 +44,27 @@ Iterate until the user approves the breakdown.
### 5. Publish the issues to the issue tracker
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.
For each approved slice, publish a new issue to the issue tracker using the **Issue body template**. 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.
Do NOT close or modify any parent issue.
## Reference
### Vertical slice rules
Each issue is a thin vertical slice that cuts through ALL integration layers end-to-end, NOT a horizontal slice of one layer.
- Each slice delivers a narrow but COMPLETE path through every layer (schema, API, UI, tests)
- A completed slice is demoable or verifiable on its own
- Any prefactoring should be done first
### Wide refactors
A **wide refactor** is one mechanical change — rename a column, retype a shared symbol — whose **blast radius** fans across the whole codebase, so a single edit breaks thousands of call sites at once and no vertical slice can land green. Don't force it into a tracer bullet; sequence it as **expandcontract**. First expand: add the new form beside the old so nothing breaks. Then migrate the call sites over in batches sized by blast radius (per package, per directory), each batch its own issue blocked by the expand, keeping CI green batch to batch because the old form still exists. Finally contract: delete the old form once no caller remains, in an issue blocked by every migrate batch. When even the batches can't stay green alone, keep the sequence but let them share an integration branch that all block a final integrate-and-verify issue — green is promised only there.
### Issue body template
<issue-template>
## Parent
@@ -65,7 +75,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
@@ -78,7 +88,4 @@ Avoid specific file paths or code snippets — they go stale fast. Exception: if
- A reference to the blocking ticket (if any)
Or "None - can start immediately" if no blockers.
</issue-template>
Do NOT close or modify any parent issue.
+11 -5
View File
@@ -7,6 +7,10 @@ A loose idea has arrived — too big for one agent session, and wrapped in fog:
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** 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
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.
@@ -17,7 +21,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.** The issue tracker should have been provided to you — run `/setup-matt-pocock-skills` if not. Consult the tracker doc's "Wayfinding operations" section for how _this_ repo expresses them. If no tracker has been provided, default to the local-markdown tracker.
### The map body
@@ -67,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**: 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.
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
+1 -1
View File
@@ -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.
@@ -158,6 +158,12 @@ _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
## Pruning
Keeping a skill lean — each remedy paired with the failure it cures.
@@ -80,3 +80,4 @@ 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.