chore: drop the flat content mirror and native install support (ADR-0024)

apm becomes the only supported install path. The flat mirror at each plugin
root existed solely so Claude Code's native `claude plugin install` could
convention-scan plugin content (ADR-0017). With no native consumers, it cost
~20,000 tracked lines plus ~2,100 lines of sync tooling and ~88s of every
push to guard content apm never reads — and its only automated gate,
`claude plugin validate --strict`, passes on a plugin with zero content, so
it could not detect the defect ADR-0017 was created to fix.

Removes the mirror (213 files), the six per-plugin manifest pairs,
sync-plugin-content.sh, its 1,289-line test, the orphaned
marketplace-plugins.sh, and the check-plugin-content-sync and
validate-plugins pre-push hooks. The root `marketplace:` block and
.claude-plugin/ catalogue stay: apm's own marketplace consumers read that
same file, so `<name>@holocron` short names keep working.

tests/run-bats.sh now excludes .claude/skills/. apm installs from .apm/,
which carries the tests/ dirs the mirror stripped, so deployed .bats files
would otherwise be discovered and double-run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YR2CjVumUbEGWcMikcoXBD
This commit is contained in:
2026-09-14 16:59:42 +00:00
parent 0dffff3c21
commit 718c79af70
245 changed files with 298 additions and 22602 deletions

View File

@@ -1,30 +0,0 @@
{
"name": "bin",
"version": "1.1.7",
"description": "Skills for everyday AI-assisted development work that is not tied to a single tool, forge or language, and has not yet been split into a focused plugin.",
"author": {
"name": "Defame1297",
"email": "defame1297@rkdr.net",
"url": "https://git.dev.rkdr.net/Defame1297/"
},
"license": "MIT",
"homepage": "https://git.dev.rkdr.net/Defame1297/holocron/src/branch/main/plugins/bin",
"repository": "https://git.dev.rkdr.net/Defame1297/holocron/src/branch/main/plugins/bin",
"keywords": [
"utility",
"diagnostics",
"prototyping",
"tdd",
"research"
],
"mcpServers": {
"obsidian": {
"args": [
"@bitbonsai/mcpvault@0.15.0",
"docs/"
],
"command": "npx",
"type": "stdio"
}
}
}

View File

@@ -1,21 +0,0 @@
{
"name": "bin",
"version": "1.1.7",
"description": "Skills for everyday AI-assisted development work that is not tied to a single tool, forge or language, and has not yet been split into a focused plugin.",
"author": {
"name": "Defame1297",
"email": "defame1297@rkdr.net",
"url": "https://git.dev.rkdr.net/Defame1297/"
},
"license": "MIT",
"homepage": "https://git.dev.rkdr.net/Defame1297/holocron/src/branch/main/plugins/bin",
"repository": "https://git.dev.rkdr.net/Defame1297/holocron/src/branch/main/plugins/bin",
"keywords": [
"utility",
"diagnostics",
"prototyping",
"tdd",
"research"
],
"mcpServers": ".mcp.json"
}

View File

@@ -1,50 +0,0 @@
---
name: caveman
disable-model-invocation: true
description: >
Ultra-compressed output mode that drops articles, filler and pleasantries while
keeping technical substance exact, cutting token usage by roughly 75%.
metadata:
version: "1.0.0"
---
Respond terse like smart caveman. All technical substance stay. Only fluff die.
## Persistence
ACTIVE EVERY RESPONSE once user type `/caveman`. No revert after many turns. No filler drift. Still active if unsure. Off only when user says "stop caveman" or "normal mode".
## Rules
Drop: articles (a/an/the), filler (just/really/basically/actually/simply), pleasantries (sure/certainly/of course/happy to), hedging. Fragments OK. Short synonyms (big not extensive, fix not "implement a solution for"). Abbreviate common terms (DB/auth/config/req/res/fn/impl). Strip conjunctions. Use arrows for causality (X -> Y). One word when one word enough.
Technical terms stay exact. Code blocks unchanged. Errors quoted exact.
Pattern: `[thing] [action] [reason]. [next step].`
Not: "Sure! I'd be happy to help you with that. The issue you're experiencing is likely caused by..."
Yes: "Bug in auth middleware. Token expiry check use `<` not `<=`. Fix:"
### Examples
**"Why React component re-render?"**
> Inline obj prop -> new ref -> re-render. `useMemo`.
**"Explain database connection pooling."**
> Pool = reuse DB conn. Skip handshake -> fast under load.
## Auto-Clarity Exception
Drop caveman temporarily for: security warnings, irreversible action confirmations, multi-step sequences where fragment order risks misread, user asks to clarify or repeats question. Resume caveman after clear part done.
Example -- destructive op:
> **Warning:** This will permanently delete all rows in the `users` table and cannot be undone.
>
> ```sql
> DROP TABLE users;
> ```
>
> Caveman resume. Verify backup exist first.

View File

@@ -1,91 +0,0 @@
---
name: diagnose
description: >
Use when the user says "diagnose this" or "debug this", reports something
broken, throwing, or failing, or says something got slow. Not filing or
triaging a reported bug -> `triage`. Not test-first feature work -> `tdd`.
metadata:
version: "1.0.1"
---
# Diagnose
A discipline for hard bugs. Skip phases only when explicitly justified.
When exploring the codebase, use the domain glossary for a clear mental model of the relevant modules, and check ADRs in the area.
## Phase 1 — Build a feedback loop
**This is the skill.** Everything else is mechanical. If you have a fast, deterministic, agent-runnable pass/fail signal for the bug, you will find the cause — bisection, hypothesis-testing, and instrumentation all just consume that signal. If you don't have one, no amount of staring at code will save you.
Spend disproportionate effort here. **Be aggressive. Be creative. Refuse to give up.**
**If you do not yet have such a signal, read `references/feedback-loops.md`** — ten ways to build one ordered by cost, and what to ask the user for when the bug resists reproduction entirely.
**If you do have one, it is probably not sharp enough yet.** Make it faster and more deterministic, and make it assert on the exact symptom rather than "didn't crash" — a 30-second flaky loop is barely better than no loop. If it stays slow or intermittent after that, read that file's "Iterate on the loop itself" and "Intermittent bugs" sections.
Do not proceed to Phase 2 until you have a loop you believe in. If you cannot build one, stop and say so explicitly, listing what you tried — never hypothesise without a signal.
## Phase 2 — Reproduce
Run the loop. Watch the bug appear.
Confirm:
- [ ] The loop produces the failure mode the **user** described — not a different failure that happens to be nearby. Wrong bug = wrong fix.
- [ ] The failure is reproducible across multiple runs. If it is intermittent, `references/feedback-loops.md` defines the rate high enough to debug against — go back to Phase 1 and raise it.
- [ ] You have captured the exact symptom (error message, wrong output, slow timing) so later phases can verify the fix actually addresses it.
Do not proceed until you reproduce the bug.
## Phase 3 — Hypothesise
Generate **3–5 ranked hypotheses** before testing any of them. Single-hypothesis generation anchors on the first plausible idea.
Each hypothesis must be **falsifiable**: state the prediction it makes.
> Format: "If <X> is the cause, then <changing Y> will make the bug disappear / <changing Z> will make it worse."
If you cannot state the prediction, the hypothesis is a vibe — discard or sharpen it.
**Show the ranked list to the user before testing.** They often have domain knowledge that re-ranks instantly ("we just deployed a change to #3"), or know hypotheses they've already ruled out. Cheap checkpoint, big time saver. Don't block on it — proceed with your ranking if the user is AFK.
## Phase 4 — Instrument
Each probe must map to a specific prediction from Phase 3. **Change one variable at a time.**
Tool preference:
1. **Debugger / REPL inspection** if the env supports it. One breakpoint beats ten logs.
2. **Targeted logs** at the boundaries that distinguish hypotheses.
3. Never "log everything and grep".
**Tag every debug log** with a unique prefix, e.g. `[DEBUG-a4f2]`. Cleanup at the end becomes a single grep. Untagged logs survive; tagged logs die.
**Perf branch.** For performance regressions, logs are usually wrong. Instead: establish a baseline measurement (timing harness, `performance.now()`, profiler, query plan), then bisect. Measure first, fix second.
## Phase 5 — Fix + regression test
Write the regression test **before the fix** — but only at a **correct seam**: one where the test exercises the real bug pattern as it occurs at the call site. If the available seam looks too shallow, or you cannot tell whether it is, read `references/regression-seams.md`.
**If no correct seam exists, that itself is the finding.** Note it and carry it into Phase 6 — the architecture is preventing the bug from being locked down.
At a correct seam:
1. Turn the Phase 1 loop into a failing test at that seam, narrowed to the symptom captured in Phase 2.
2. Watch it fail.
3. Apply the fix.
4. Watch it pass.
5. Re-run the Phase 1 feedback loop against the original, un-narrowed scenario.
## Phase 6 — Cleanup + post-mortem
Required before declaring done:
- [ ] Original repro no longer reproduces (re-run the Phase 1 loop)
- [ ] Regression test passes (or absence of seam is documented)
- [ ] All `[DEBUG-...]` instrumentation removed (`grep` the prefix)
- [ ] Throwaway prototypes deleted (or moved to a clearly-marked debug location)
- [ ] The hypothesis that turned out correct is stated in the commit / PR message — so the next debugger learns
**Then ask: what would have prevented this bug?** If the answer involves architectural change (no good test seam, tangled callers, hidden coupling) hand off to the `/improve-codebase-architecture` skill with the specifics. Make the recommendation **after** the fix is in, not before — you have more information now than when you started.

View File

@@ -1,41 +0,0 @@
#!/usr/bin/env bash
# Human-in-the-loop reproduction loop.
# Copy this file, edit the steps below, and run it.
# The agent runs the script; the user follows prompts in their terminal.
#
# Usage:
# bash hitl-loop.template.sh
#
# Two helpers:
# step "<instruction>" → show instruction, wait for Enter
# capture VAR "<question>" → show question, read response into VAR
#
# At the end, captured values are printed as KEY=VALUE for the agent to parse.
set -euo pipefail
step() {
printf '\n>>> %s\n' "$1"
read -r -p " [Enter when done] " _
}
capture() {
local var="$1" question="$2" answer
printf '\n>>> %s\n' "$question"
read -r -p " > " answer
printf -v "$var" '%s' "$answer"
}
# --- edit below ---------------------------------------------------------
step "Open the app at http://localhost:3000 and sign in."
capture ERRORED "Click the 'Export' button. Did it throw an error? (y/n)"
capture ERROR_MSG "Paste the error message (or 'none'):"
# --- edit above ---------------------------------------------------------
printf '\n--- Captured ---\n'
printf 'ERRORED=%s\n' "$ERRORED"
printf 'ERROR_MSG=%s\n' "$ERROR_MSG"

View File

@@ -1,40 +0,0 @@
# Constructing and sharpening a feedback loop
A feedback loop is a fast, deterministic, agent-runnable pass/fail signal for the bug. Build the right one and the bug is 90% fixed. This file covers the whole arc: building a loop, sharpening one you already have, and escalating when the bug resists reproduction.
## Ways to construct one — try them in roughly this order
1. **Failing test** at whatever seam reaches the bug — unit, integration, e2e.
2. **Curl / HTTP script** against a running dev server.
3. **CLI invocation** with a fixture input, diffing stdout against a known-good snapshot.
4. **Headless browser script** (Playwright / Puppeteer) — drives the UI, asserts on DOM/console/network.
5. **Replay a captured trace.** Save a real network request / payload / event log to disk; replay it through the code path in isolation.
6. **Throwaway harness.** Spin up a minimal subset of the system (one service, mocked deps) that exercises the bug code path with a single function call.
7. **Property / fuzz loop.** If the bug is "sometimes wrong output", run 1000 random inputs and look for the failure mode.
8. **Bisection harness.** If the bug appeared between two known states (commit, dataset, version), automate "boot at state X, check, repeat" so you can `git bisect run` it.
9. **Differential loop.** Run the same input through old-version vs new-version (or two configs) and diff outputs.
10. **HITL bash script.** Last resort. If a human must click, drive _them_ with `assets/hitl-loop.template.sh` so the loop is still structured. Captured output feeds back to you.
## Iterate on the loop itself
Treat the loop as a product. Once you have _a_ loop, ask:
- Can I make it faster? (Cache setup, skip unrelated init, narrow the test scope.)
- Can I make the signal sharper? (Assert on the specific symptom, not "didn't crash".)
- Can I make it more deterministic? (Pin time, seed RNG, isolate filesystem, freeze network.)
A 30-second flaky loop is barely better than no loop. A 2-second deterministic loop is a debugging superpower.
## Intermittent bugs — raise the reproduction rate
If the loop only sometimes fails, the goal is not a clean repro but a **higher reproduction rate**. Loop the trigger 100×, parallelise, add stress, narrow timing windows, inject sleeps. A 50%-flake bug is debuggable; 1% is not — keep raising the rate until it's debuggable.
## When you genuinely cannot build a loop
Stop and say so explicitly. List what you tried. Ask the user for:
- access to whatever environment reproduces it,
- a captured artifact (HAR file, log dump, core dump, screen recording with timestamps), or
- permission to add temporary production instrumentation.
Do **not** proceed to hypothesise without a loop. A hypothesis you cannot falsify against a signal is a guess, and the fix that follows it is unverifiable.

View File

@@ -1,24 +0,0 @@
# Judging a regression-test seam
Read this when Phase 5 leaves you unsure whether the seam available for the regression test is the correct one — either because the obvious seam looks shallow, or because there appears to be no seam at all.
## What makes a seam correct
A correct seam is one where the test exercises the **real bug pattern** as it occurs at the call site: the same entry point, the same participants, the same ordering, and the same state the real caller holds when it goes wrong.
## Seams that are too shallow
- A single-caller test when the bug only appears with multiple callers.
- A unit test that cannot replicate the chain of calls that triggered the bug.
- A test that reproduces the symptom by construction — asserting on a value the test itself set — rather than by driving the code path that produces it.
- A test that mocks out the collaborator the bug actually lives in.
A regression test at a shallow seam gives false confidence. It passes forever, including after a change reintroduces the bug at the real call site, and it will be read by the next maintainer as proof the bug is locked down.
## When there is no correct seam
Do not force one, and do not settle for a shallow seam to have something green. Instead:
1. Apply the fix and verify it against the Phase 1 loop directly.
2. Write down which seams you considered and why each was too shallow.
3. Carry that into Phase 6's "what would have prevented this bug" question. A missing seam is an architecture finding — tangled callers, hidden coupling, or a module with no testable boundary — and the handoff is the `improve-codebase-architecture` skill, with those specifics attached.

View File

@@ -1,16 +0,0 @@
---
name: grill-me
description: >
Use when the user says "grill me" or wants a plan or design stress-tested by
relentless interview — one question at a time, down each branch of the
decision tree. Not a plan to challenge against `CONTEXT.md` and ADRs ->
`grill-with-docs`.
metadata:
version: "1.0.0"
---
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.
Ask the questions one at a time.
If a question can be answered by exploring the codebase, explore the codebase instead.

View File

@@ -1,93 +0,0 @@
---
name: grill-with-docs
description: >
Use when a plan should be stress-tested against the project's domain model —
the interview challenges terms against `CONTEXT.md` and writes decisions into
it and into ADRs as they land. Not a plain interview -> `grill-me`.
metadata:
version: "1.0.0"
---
<what-to-do>
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.
Ask the questions one at a time, waiting for feedback on each question before continuing.
If a question can be answered by exploring the codebase, explore the codebase instead.
</what-to-do>
<supporting-info>
## Domain awareness
During codebase exploration, also look for existing documentation:
### File structure
Most repos have a single context:
```
/
├── CONTEXT.md
├── docs/
│ └── adr/
│ ├── 0001-event-sourced-orders.md
│ └── 0002-postgres-for-write-model.md
└── src/
```
If a `CONTEXT-MAP.md` exists at the root, the repo has multiple contexts. The map points to where each one lives:
```
/
├── CONTEXT-MAP.md
├── docs/
│ └── adr/ ← system-wide decisions
├── src/
│ ├── ordering/
│ │ ├── CONTEXT.md
│ │ └── docs/adr/ ← context-specific decisions
│ └── billing/
│ ├── CONTEXT.md
│ └── docs/adr/
```
Create files lazily — only when you have something to write. If no `CONTEXT.md` exists, create one when the first term is resolved. If no `docs/adr/` exists, create it when the first ADR is needed.
## During the session
### Challenge against the glossary
When the user uses a term that conflicts with the existing language in `CONTEXT.md`, call it out immediately. "Your glossary defines 'cancellation' as X, but you seem to mean Y — which is it?"
### Sharpen fuzzy language
When the user uses vague or overloaded terms, propose a precise canonical term. "You're saying 'account' — do you mean the Customer or the User? Those are different things."
### Discuss concrete scenarios
When domain relationships are being discussed, stress-test them with specific scenarios. Invent scenarios that probe edge cases and force the user to be precise about the boundaries between concepts.
### Cross-reference with code
When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: "Your code cancels entire Orders, but you just said partial cancellation is possible — which is right?"
### Update CONTEXT.md inline
When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [context-format.md](references/context-format.md).
Don't couple `CONTEXT.md` to implementation details. Only include terms that are meaningful to domain experts.
### Offer ADRs sparingly
Only offer to create an ADR when all three are true:
1. **Hard to reverse** — the cost of changing your mind later is meaningful
2. **Surprising without context** — a future reader will wonder "why did they do it this way?"
3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons
If any of the three is missing, skip the ADR. Use the format in [adr-format.md](references/adr-format.md).
</supporting-info>

View File

@@ -1,47 +0,0 @@
# ADR Format
ADRs live in `docs/adr/` and use sequential numbering: `0001-slug.md`, `0002-slug.md`, etc.
Create the `docs/adr/` directory lazily — only when the first ADR is needed.
## Template
```md
# {Short title of the decision}
{1-3 sentences: what's the context, what did we decide, and why.}
```
That's it. An ADR can be a single paragraph. The value is in recording *that* a decision was made and *why* — not in filling out sections.
## Optional sections
Only include these when they add genuine value. Most ADRs won't need them.
- **Status** frontmatter (`proposed | accepted | deprecated | superseded by ADR-NNNN`) — useful when decisions are revisited
- **Considered Options** — only when the rejected alternatives are worth remembering
- **Consequences** — only when non-obvious downstream effects need to be called out
## Numbering
Scan `docs/adr/` for the highest existing number and increment by one.
## When to offer an ADR
All three of these must be true:
1. **Hard to reverse** — the cost of changing your mind later is meaningful
2. **Surprising without context** — a future reader will look at the code and wonder "why on earth did they do it this way?"
3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons
If a decision is easy to reverse, skip it — you'll just reverse it. If it's not surprising, nobody will wonder why. If there was no real alternative, there's nothing to record beyond "we did the obvious thing."
### What qualifies
- **Architectural shape.** "We're using a monorepo." "The write model is event-sourced, the read model is projected into Postgres."
- **Integration patterns between contexts.** "Ordering and Billing communicate via domain events, not synchronous HTTP."
- **Technology choices that carry lock-in.** Database, message bus, auth provider, deployment target. Not every library — just the ones that would take a quarter to swap out.
- **Boundary and scope decisions.** "Customer data is owned by the Customer context; other contexts reference it by ID only." The explicit no-s are as valuable as the yes-s.
- **Deliberate deviations from the obvious path.** "We're using manual SQL instead of an ORM because X." Anything where a reasonable reader would assume the opposite. These stop the next engineer from "fixing" something that was deliberate.
- **Constraints not visible in the code.** "We can't use AWS because of compliance requirements." "Response times must be under 200ms because of the partner API contract."
- **Rejected alternatives when the rejection is non-obvious.** If you considered GraphQL and picked REST for subtle reasons, record it — otherwise someone will suggest GraphQL again in six months.

View File

@@ -1,77 +0,0 @@
# CONTEXT.md Format
## Structure
```md
# {Context Name}
{One or two sentence description of what this context is and why it exists.}
## Language
**Order**:
{A concise description of the term}
_Avoid_: Purchase, transaction
**Invoice**:
A request for payment sent to a customer after delivery.
_Avoid_: Bill, payment request
**Customer**:
A person or organization that places orders.
_Avoid_: Client, buyer, account
## Relationships
- An **Order** produces one or more **Invoices**
- An **Invoice** belongs to exactly one **Customer**
## Example dialogue
> **Dev:** "When a **Customer** places an **Order**, do we create the **Invoice** immediately?"
> **Domain expert:** "No — an **Invoice** is only generated once a **Fulfillment** is confirmed."
## Flagged ambiguities
- "account" was used to mean both **Customer** and **User** — resolved: these are distinct concepts.
```
## Rules
- **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others as aliases to avoid.
- **Flag conflicts explicitly.** If a term is used ambiguously, call it out in "Flagged ambiguities" with a clear resolution.
- **Keep definitions tight.** One sentence max. Define what it IS, not what it does.
- **Show relationships.** Use bold term names and express cardinality where obvious.
- **Only include terms specific to this project's context.** General programming concepts (timeouts, error types, utility patterns) don't belong even if the project uses them extensively. Before adding a term, ask: is this a concept unique to this context, or a general programming concept? Only the former belongs.
- **Group terms under subheadings** when natural clusters emerge. If all terms belong to a single cohesive area, a flat list is fine.
- **Write an example dialogue.** A conversation between a dev and a domain expert that demonstrates how the terms interact naturally and clarifies boundaries between related concepts.
## Single vs multi-context repos
**Single context (most repos):** One `CONTEXT.md` at the repo root.
**Multiple contexts:** A `CONTEXT-MAP.md` at the repo root lists the contexts, where they live, and how they relate to each other:
```md
# Context Map
## Contexts
- [Ordering](./src/ordering/CONTEXT.md) — receives and tracks customer orders
- [Billing](./src/billing/CONTEXT.md) — generates invoices and processes payments
- [Fulfillment](./src/fulfillment/CONTEXT.md) — manages warehouse picking and shipping
## Relationships
- **Ordering → Fulfillment**: Ordering emits `OrderPlaced` events; Fulfillment consumes them to start picking
- **Fulfillment → Billing**: Fulfillment emits `ShipmentDispatched` events; Billing consumes them to generate invoices
- **Ordering ↔ Billing**: Shared types for `CustomerId` and `Money`
```
The skill infers which structure applies:
- If `CONTEXT-MAP.md` exists, read it to find contexts
- If only a root `CONTEXT.md` exists, single context
- If neither exists, create a root `CONTEXT.md` lazily when the first term is resolved
When multiple contexts exist, infer which one the current topic relates to. If unclear, ask.

View File

@@ -1,80 +0,0 @@
---
name: improve-codebase-architecture
description: >
Use when the user wants to improve architecture, find refactoring
opportunities, consolidate tightly-coupled modules, or make a codebase more
testable and AI-navigable — deepening opportunities that turn shallow modules
into deep ones, informed by `CONTEXT.md` and `docs/adr/`. Not debugging a
failure -> `diagnose`.
metadata:
version: "1.0.1"
---
# Improve Codebase Architecture
Surface architectural friction and propose **deepening opportunities** — refactors that turn shallow modules into deep ones. The aim is testability and AI-navigability.
## Glossary
Use these terms exactly in every suggestion. Consistent language is the point — don't drift into "component," "service," "API," or "boundary."
- **Module** — anything with an interface and an implementation (function, class, package, slice).
- **Interface** — everything a caller must know to use the module: types, invariants, error modes, ordering, config. Not just the type signature.
- **Implementation** — the code inside.
- **Depth** — leverage at the interface: a lot of behaviour behind a small interface. **Deep** = high leverage. **Shallow** = interface nearly as complex as the implementation.
- **Seam** — where an interface lives; a place behaviour can be altered without editing in place. (Use this, not "boundary.")
- **Adapter** — a concrete thing satisfying an interface at a seam.
- **Leverage** — what callers get from depth.
- **Locality** — what maintainers get from depth: change, bugs, knowledge concentrated in one place.
Key principles:
- **Deletion test**: imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
- **The interface is the test surface.**
- **One adapter = hypothetical seam. Two adapters = real seam.**
If a term or principle above is ambiguous in the case in front of you, or you need the definitions and the principles the two lists leave out, read `references/language.md`.
This skill is _informed_ by the project's domain model. The domain language gives names to good seams; ADRs record decisions the skill should not re-litigate.
## Process
### 1. Explore
Read the domain glossary and any ADRs in the area first.
Then use the Agent tool with `subagent_type=Explore` to walk the codebase. Don't follow rigid heuristics — explore organically and note where you experience friction:
- Where does understanding one concept require bouncing between many small modules?
- Where are modules **shallow** — interface nearly as complex as the implementation?
- Where have pure functions been extracted just for testability, but the real bugs hide in how they're called (no **locality**)?
- Where do tightly-coupled modules leak across their seams?
- Which parts of the codebase are untested, or hard to test through their current interface?
Apply the **deletion test** to anything you suspect is shallow: would deleting it concentrate complexity, or just move it? A "yes, concentrates" is the signal you want.
### 2. Present candidates
Present a numbered list of deepening opportunities. For each candidate:
- **Files** — which files/modules are involved
- **Problem** — why the current architecture is causing friction
- **Solution** — plain English description of what would change
- **Benefits** — explained in terms of locality and leverage, and also in how tests would improve
**Use CONTEXT.md vocabulary for the domain, and the architecture glossary above for the architecture.** If `CONTEXT.md` defines "Order," talk about "the Order intake module" — not "the FooBarHandler," and not "the Order service."
**ADR conflicts**: if a candidate contradicts an existing ADR, only surface it when the friction is real enough to warrant revisiting the ADR. Mark it clearly (e.g. _"contradicts ADR-0007 — but worth reopening because…"_). Don't list every theoretical refactor an ADR forbids.
Do NOT propose interfaces yet. Ask the user: "Which of these would you like to explore?"
### 3. Grilling loop
Once the user picks a candidate, drop into a grilling conversation. Walk the design tree with them — constraints, dependencies, the shape of the deepened module, what sits behind the seam, what tests survive.
Side effects happen inline as decisions crystallize:
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as `grill-with-docs`, in the format `grill-with-docs`'s `references/context-format.md` defines. Create the file lazily if it doesn't exist.
- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there.
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See `grill-with-docs`'s `references/adr-format.md`.
- **Want to explore alternative interfaces for the deepened module?** Read `references/interface-design.md`.

View File

@@ -1,37 +0,0 @@
# Deepening
How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [language.md](language.md) — **module**, **interface**, **seam**, **adapter**.
## Dependency categories
When assessing a candidate for deepening, classify its dependencies. The category determines how the deepened module is tested across its seam.
### 1. In-process
Pure computation, in-memory state, no I/O. Always deepenable — merge the modules and test through the new interface directly. No adapter needed.
### 2. Local-substitutable
Dependencies that have local test stand-ins (PGLite for Postgres, in-memory filesystem). Deepenable if the stand-in exists. The deepened module is tested with the stand-in running in the test suite. The seam is internal; no port at the module's external interface.
### 3. Remote but owned (Ports & Adapters)
Your own services across a network boundary (microservices, internal APIs). Define a **port** (interface) at the seam. The deep module owns the logic; the transport is injected as an **adapter**. Tests use an in-memory adapter. Production uses an HTTP/gRPC/queue adapter.
Recommendation shape: *"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network."*
### 4. True external (Mock)
Third-party services (Stripe, Twilio, etc.) you don't control. The deepened module takes the external dependency as an injected port; tests provide a mock adapter.
## Seam discipline
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection.
- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them.
## Testing strategy: replace, don't layer
- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist — delete them.
- Write new tests at the deepened module's interface. The **interface is the test surface**.
- Tests assert on observable outcomes through the interface, not internal state.
- Tests should survive internal refactors — they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface.

View File

@@ -1,44 +0,0 @@
# Interface Design
When the user wants to explore alternative interfaces for a chosen deepening candidate, use this parallel sub-agent pattern. Based on "Design It Twice" (Ousterhout) — your first idea is unlikely to be the best.
Uses the vocabulary in [language.md](language.md) — **module**, **interface**, **seam**, **adapter**, **leverage**.
## Process
### 1. Frame the problem space
Before spawning sub-agents, write a user-facing explanation of the problem space for the chosen candidate:
- The constraints any new interface would need to satisfy
- The dependencies it would rely on, and which category they fall into (see [deepening.md](deepening.md))
- A rough illustrative code sketch to ground the constraints — not a proposal, just a way to make the constraints concrete
Show this to the user, then immediately proceed to Step 2. The user reads and thinks while the sub-agents work in parallel.
### 2. Spawn sub-agents
Spawn 3+ sub-agents in parallel using the Agent tool. Each must produce a **radically different** interface for the deepened module.
Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [deepening.md](deepening.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint:
- Agent 1: "Minimize the interface — aim for 1–3 entry points max. Maximise leverage per entry point."
- Agent 2: "Maximise flexibility — support many use cases and extension."
- Agent 3: "Optimise for the most common caller — make the default case trivial."
- Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies."
Include both [language.md](language.md) vocabulary and CONTEXT.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language.
Each sub-agent outputs:
1. Interface (types, methods, params — plus invariants, ordering, error modes)
2. Usage example showing how callers use it
3. What the implementation hides behind the seam
4. Dependency strategy and adapters (see [deepening.md](deepening.md))
5. Trade-offs — where leverage is high, where it's thin
### 3. Present and compare
Present designs sequentially so the user can absorb each one, then compare them in prose. Contrast by **depth** (leverage at the interface), **locality** (where change concentrates), and **seam placement**.
After comparing, give your own recommendation: which design you think is strongest and why. If elements from different designs would combine well, propose a hybrid. Be opinionated — the user wants a strong read, not a menu.

View File

@@ -1,53 +0,0 @@
# Language
Shared vocabulary for every suggestion this skill makes. Use these terms exactly — don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point.
## Terms
**Module**
Anything with an interface and an implementation. Deliberately scale-agnostic — applies equally to a function, class, package, or tier-spanning slice.
_Avoid_: unit, component, service.
**Interface**
Everything a caller must know to use the module correctly. Includes the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics.
_Avoid_: API, signature (too narrow — those refer only to the type-level surface).
**Implementation**
What's inside a module — its body of code. Distinct from **Adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise.
**Depth**
Leverage at the interface — the amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is **deep** when a large amount of behaviour sits behind a small interface. A module is **shallow** when the interface is nearly as complex as the implementation.
**Seam** _(from Michael Feathers)_
A place where you can alter behaviour without editing in that place. The *location* at which a module's interface lives. Choosing where to put the seam is its own design decision, distinct from what goes behind it.
_Avoid_: boundary (overloaded with DDD's bounded context).
**Adapter**
A concrete thing that satisfies an interface at a seam. Describes *role* (what slot it fills), not substance (what's inside).
**Leverage**
What callers get from depth. More capability per unit of interface they have to learn. One implementation pays back across N call sites and M tests.
**Locality**
What maintainers get from depth. Change, bugs, knowledge, and verification concentrate at one place rather than spreading across callers. Fix once, fixed everywhere.
## Principles
- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface.
- **The deletion test.** Imagine deleting the module. If complexity vanishes, the module wasn't hiding anything (it was a pass-through). If complexity reappears across N callers, the module was earning its keep.
- **The interface is the test surface.** Callers and tests cross the same seam. If you want to test *past* the interface, the module is probably the wrong shape.
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it.
## Relationships
- A **Module** has exactly one **Interface** (the surface it presents to callers and tests).
- **Depth** is a property of a **Module**, measured against its **Interface**.
- A **Seam** is where a **Module**'s **Interface** lives.
- An **Adapter** sits at a **Seam** and satisfies the **Interface**.
- **Depth** produces **Leverage** for callers and **Locality** for maintainers.
## Rejected framings
- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead.
- **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow — interface here includes every fact a caller must know.
- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**.

View File

@@ -1,38 +0,0 @@
---
name: prototype
description: >
Use when the user wants a throwaway prototype to answer a design question about
a data model, state machine or business logic, or to mock up a UI in several
variations. Not production code -> `tdd`. Not talking a design through ->
`grill-me`.
metadata:
version: "1.0.0"
---
# Prototype
A prototype is **throwaway code that answers a question**. The question decides the shape.
## Pick a branch
| Question being answered | Build | Reference |
|---|---|---|
| "Does this logic / state model feel right?" | A tiny interactive terminal app that pushes the state machine through cases that are hard to reason about on paper | `references/logic.md` |
| "What should this look like?" | Several radically different UI variations on one route, switchable via a URL search param and a floating bottom bar | `references/ui.md` |
Resolve the row from the user's prompt, the surrounding code, or by asking if the user is around, then read only that reference — each is self-contained.
The two branches produce fundamentally different artifacts — getting this wrong wastes the whole prototype. If the question is genuinely ambiguous and the user isn't reachable, default to whichever branch better matches the surrounding code (a backend module → logic; a page or component → UI) and state the assumption at the top of the prototype.
## Rules that apply to both
1. **Throwaway from day one, and clearly marked as such.** Locate the prototype code close to where it will actually be used (next to the module or page it's prototyping for) so context is obvious — but name it so a casual reader can see it's a prototype, not production. For throwaway UI routes, obey whatever routing convention the project already uses; don't invent a new top-level structure.
2. **One command to run.** Whatever the project's existing task runner supports — `pnpm <name>`, `python <path>`, `bun <path>`, etc. The user must be able to start it without thinking.
3. **No persistence by default.** State lives in memory. Persistence is the thing the prototype is *checking*, not something it should depend on. If the question explicitly involves a database, hit a scratch DB or a local file with a clear "PROTOTYPE — wipe me" name.
4. **Skip the polish.** No tests, no error handling beyond what makes the prototype *runnable*, no abstractions. The point is to learn something fast and then delete it.
5. **Surface the state.** After every action (logic) or on every variant switch (UI), print or render the full relevant state so the user can see what changed.
6. **Delete or absorb when done.** When the prototype has answered its question, either delete it or fold the validated decision into the real code — don't leave it rotting in the repo.
## When done
The *answer* is the only thing worth keeping from a prototype. Capture it somewhere durable (commit message, ADR, issue, or a `NOTES.md` next to the prototype) along with the question it was answering. If the user is around, that capture is a quick conversation; if not, leave the placeholder so they (or you, on the next pass) can fill in the verdict before deleting the prototype.

View File

@@ -1,79 +0,0 @@
# Logic Prototype
A tiny interactive terminal app that lets the user drive a state model by hand. Use this when the question is about **business logic, state transitions, or data shape** — the kind of thing that looks reasonable on paper but only feels wrong once you push it through real cases.
## When this is the right shape
- "I'm not sure if this state machine handles the edge case where X then Y."
- "Does this data model actually let me represent the case where..."
- "I want to feel out what the API should look like before writing it."
- Anything where the user wants to **press buttons and watch state change**.
If the question is "what should this look like" — wrong branch. Read `references/ui.md`.
## Process
### 1. State the question
Before writing code, write down what state model and what question you're prototyping. One paragraph, in the prototype's README or a comment at the top of the file. A logic prototype that answers the wrong question is pure waste — make the question explicit so it can be checked later, whether the user is watching now or returning to it AFK.
### 2. Pick the language
Use whatever the host project uses. If the project has no obvious runtime (e.g. a docs repo), ask.
Match the project's existing conventions for tooling — don't add a new package manager or runtime just for the prototype.
### 3. Isolate the logic in a portable module
Put the actual logic — the bit that's answering the question — behind a small, pure interface that could be lifted out and dropped into the real codebase later. The TUI around it is throwaway; the logic module shouldn't be.
The right shape depends on the question:
- **A pure reducer** — `(state, action) => state`. Good when actions are discrete events and state is a single value.
- **A state machine** — explicit states and transitions. Good when "which actions are even legal right now" is part of the question.
- **A small set of pure functions** over a plain data type. Good when there's no implicit current state — just transformations.
- **A class or module with a clear method surface** when the logic genuinely owns ongoing internal state.
Pick whichever shape best fits the question being asked, *not* whichever is easiest to wire to a TUI. Keep it pure: no I/O, no terminal code, no `console.log` for control flow. The TUI imports it and calls into it; nothing flows the other direction.
This is what makes the prototype useful past its own lifetime. When the question's been answered, the validated reducer / machine / function set can be lifted into the real module — the TUI shell gets deleted.
### 4. Build the smallest TUI that exposes the state
Build it as a **lightweight TUI** — on every tick, clear the screen (`console.clear()` / `print("\033[2J\033[H")` / equivalent) and re-render the whole frame. The user should always see one stable view, not an ever-growing scrollback.
Each frame has two parts, in this order:
1. **Current state**, pretty-printed and diff-friendly (one field per line, or formatted JSON). Use **bold** for field names or section headers and **dim** for less important context (timestamps, IDs, derived values). Native ANSI escape codes are fine — `\x1b[1m` bold, `\x1b[2m` dim, `\x1b[0m` reset. No need to pull in a styling library unless one is already in the project.
2. **Keyboard shortcuts**, listed at the bottom: `[a] add user [d] delete user [t] tick clock [q] quit`. Bold the key, dim the description, or vice-versa — whatever reads cleanly.
Behaviour:
1. **Initialise state** — a single in-memory object/struct. Render the first frame on start.
2. **Read one keystroke (or one line)** at a time, dispatch to a handler that mutates state.
3. **Re-render** the full frame after every action — don't append, replace.
4. **Loop until quit.**
The whole frame should fit on one screen.
### 5. Make it runnable in one command
Add a script to the project's existing task runner (`package.json` scripts, `Makefile`, `justfile`, `pyproject.toml`). The user should run `pnpm run <prototype-name>` or equivalent — never need to remember a path.
If the host project has no task runner, just put the command at the top of the prototype's README.
### 6. Hand it over
Give the user the run command. They'll drive it themselves; the interesting moments are when they say "wait, that shouldn't be possible" or "huh, I assumed X would be different" — those are the bugs in the _idea_, which is the whole point. If they want new actions added, add them. Prototypes evolve.
### 7. Capture the answer
When the prototype has done its job, the answer to the question is the only thing worth keeping. If the user is around, ask what it taught them. If not, leave a `NOTES.md` next to the prototype so the answer can be filled in (or filled in by you, if you've watched the session) before the prototype gets deleted.
## Anti-patterns
- **Don't add tests.** A prototype that needs tests is no longer a prototype.
- **Don't wire it to the real database.** Use an in-memory store unless the question is specifically about persistence.
- **Don't generalise.** No "what if we wanted to support X later." The prototype answers one question.
- **Don't blur the logic and the TUI together.** If the reducer / state machine references `console.log`, prompts, or terminal escape codes, it's no longer portable. Keep the TUI as a thin shell over a pure module.
- **Don't ship the TUI shell into production.** The shell is optimised for being driven by hand from a terminal. The logic module behind it is the bit worth keeping.

View File

@@ -1,112 +0,0 @@
# UI Prototype
Generate **several radically different UI variations** on a single route, switchable from a floating bottom bar. The user flips between variants in the browser, picks one (or steals bits from each), then throws the rest away.
If the question is about logic/state rather than what something looks like — wrong branch. Read `references/logic.md`.
## When this is the right shape
- "What should this page look like?"
- "I want to see a few options for this dashboard before committing."
- "Try a different layout for the settings screen."
- Any time the user would otherwise spend a day picking between three vague mockups in their head.
## Two sub-shapes — strongly prefer sub-shape A
A UI prototype is much easier to judge when it's **butting up against the rest of the app** — real header, real sidebar, real data, real density. A throwaway route on its own is a vacuum: every variant looks fine in isolation. Default to sub-shape A whenever there's a plausible existing page to host the variants. Only reach for sub-shape B if the prototype genuinely has no nearby home.
### Sub-shape A — adjustment to an existing page (preferred)
The route already exists. Variants are rendered **on the same route**, gated by a `?variant=` URL search param. The existing data fetching, params, and auth all stay — only the rendering swaps. This is the default; pick it unless there's a specific reason not to.
If the prototype is for something that doesn't yet have a page but *would naturally live inside one* (a new section of the dashboard, a new card on the settings screen, a new step in an existing flow) — that's still sub-shape A. Mount the variants inside the host page.
### Sub-shape B — a new page (last resort)
Only use this when the thing being prototyped genuinely has no existing page to live inside — e.g. an entirely new top-level surface, or a flow that can't be embedded anywhere sensible.
Create a **throwaway route** following whatever routing convention the project already uses — don't invent a new top-level structure. Name it so it's obviously a prototype (e.g. include the word `prototype` in the path or filename). Same `?variant=` pattern.
Before committing to sub-shape B, sanity-check: is there really no existing page this could be embedded in? An empty route hides design problems that a populated one would expose.
In both sub-shapes the floating bottom bar is identical.
## Process
### 1. State the question and pick N
Default to **3 variants**. More than 5 stops being radically different and starts being noise — cap there.
Write down the plan in one line, in the prototype's location or a top-of-file comment:
> "Three variants of the settings page, switchable via `?variant=`, on the existing `/settings` route."
This works whether the user is here to push back or not.
### 2. Generate radically different variants
Draft each variant. Hold each one to:
- The page's purpose and the data it has access to.
- The project's component library / styling system (TailwindCSS, shadcn, MUI, plain CSS, whatever).
- A clear exported component name, e.g. `VariantA`, `VariantB`, `VariantC`.
Variants must be **structurally different** — different layout, different information hierarchy, different primary affordance, not just different colours. Three slightly-tweaked card grids isn't a UI prototype, it's wallpaper. If two drafts come out too similar, redo one with explicit "do not use a card grid" guidance.
### 3. Wire them together
Create a single switcher component on the route:
```tsx
// pseudo-code — adapt to the project's framework
const variant = searchParams.get('variant') ?? 'A';
return (
<>
{variant === 'A' && <VariantA {...data} />}
{variant === 'B' && <VariantB {...data} />}
{variant === 'C' && <VariantC {...data} />}
<PrototypeSwitcher variants={['A','B','C']} current={variant} />
</>
);
```
For sub-shape A (existing page): keep all the existing data fetching above the switcher; only the rendered subtree changes per variant.
For sub-shape B (new page): the throwaway route under `/prototype/<name>` mounts the same switcher.
### 4. Build the floating switcher
A small fixed-position bar at the bottom-centre of the screen with three pieces:
- **Left arrow** — cycles to the previous variant (wraps around).
- **Variant label** — shows the current variant key and, if the variant exports a name, that name too. e.g. `B — Sidebar layout`.
- **Right arrow** — cycles forward (wraps around).
Behaviour:
- Clicking an arrow updates the URL search param (use the framework's router — `router.replace` on Next, `navigate` on React Router, etc) so the variant is shareable and reload-stable.
- Keyboard: `←` and `→` arrow keys also cycle. Don't intercept arrow keys when an `<input>`, `<textarea>`, or `[contenteditable]` is focused.
- Visually distinct from the page (e.g. high-contrast pill, subtle shadow) so it's obviously not part of the design being evaluated.
- Hidden in production builds — gate on `process.env.NODE_ENV !== 'production'` or an equivalent check, so a stray prototype merge can't ship the bar to users.
Put the switcher in a single shared component so both sub-shapes can reuse it. Locate it wherever shared UI lives in the project.
### 5. Hand it over
Surface the URL (and the `?variant=` keys). The user will flip through whenever they get to it. The interesting feedback is usually **"I want the header from B with the sidebar from C"** — that's the actual design they want.
### 6. Capture the answer and clean up
Once a variant has won, write down which one and why (commit message, ADR, issue, or a `NOTES.md` next to the prototype if running AFK and the user hasn't responded yet). Then:
- **Sub-shape A** — delete the losing variants and the switcher; fold the winner into the existing page.
- **Sub-shape B** — promote the winning variant to a real route, delete the throwaway route and the switcher.
Don't leave variant components or the switcher lying around. They rot fast and confuse the next reader.
## Anti-patterns
- **Variants that differ only in colour or copy.** That's a tweak, not a prototype. Real variants disagree about structure.
- **Sharing too much code between variants.** A shared `<Header>` is fine; a shared `<Layout>` defeats the point. Each variant should be free to throw out the layout.
- **Wiring variants to real mutations.** Read-only prototypes are fine. If a variant needs to mutate, point it at a stub — the question is "what should this look like", not "does the backend work".
- **Promoting the prototype directly to production.** The variant code was written under prototype constraints (no tests, minimal error handling). Rewrite it properly when you fold it in.

View File

@@ -1,79 +0,0 @@
---
name: research
description: >-
Use when the user wants a tool, library, or API researched from canonical
documentation into structured per-topic reference markdown files. Not
documentation written from existing code or specs -> `write-docs`. Not a bug
or incident -> `diagnose`.
metadata:
version: "1.0.0"
category: research
allowed-tools:
- Grep
- Glob
- Read
- Write
- WebSearch
- WebFetch
- mcp__context7__resolve-library-id
- mcp__context7__query-docs
model: sonnet
---
## Gotchas
- Never infer the output path. A run writes a directory's worth of files, and a guessed destination scatters them through someone's source tree. If the user named no path, stop and ask.
- Write nothing outside the given output path. A file placed beside the agreed directory is one the user never asked for and will not think to look for.
- Never write an empty topic file. A stub `troubleshooting.md` reads downstream as researched and closed.
- A Context7 response that is a "no results" message, a redirect notice, or header-only boilerplate is not coverage. A topic area counts as covered only when the response carries at least one substantive paragraph.
## Step 1 — Scope against the working directory
Search for existing use of the topic — imports, config files, version pins, reference files already written — and narrow the research to what is missing: the version actually in use, the topics not yet documented.
The default topic areas are `overview`, `installation`, `configuration`, `cli-reference`,
`api-reference`, `examples` and `troubleshooting` — one file each, and only where content exists.
If what belongs in one of them is unclear, or the topic needs a file outside that set, read
`references/topics.md` for the per-topic coverage table and the custom-topic naming rule.
## Step 2 — Resolve against Context7
If the topic is a library, framework, or API and the user gave no starting URLs, call `resolve-library-id` with the topic name and the user's full question — match quality depends on the question, not the bare name — then `query-docs` once per default topic area. Record each response as a source with slug `context7-<library-slug>`, and mark which topic areas it covered — those skip the web reads at step 4.
If the library does not resolve, or the user gave starting URLs, go to step 3. Explicit URLs are a source choice; do not second-guess them with a resolution attempt.
## Step 3 — Discover sources
If the user gave starting URLs, skip discovery: those URLs are the source list and go straight to step 4.
Otherwise, for every topic area Context7 did not cover, websearch for canonical documentation — `llms.txt`, official developer docs, and API references ahead of tutorials or blog posts. Collect three to five candidate URLs before reading any of them.
If nothing usable comes back, stop and report what was searched, then ask for starting URLs rather than settling for tutorials.
## Step 4 — Read the sources
`WebFetch` each URL in turn. No subagent tool is granted here, so the reads are serial and every fetched page lands in this context: reduce each page to notes by topic area, plus the links worth deepening, before fetching the next one.
## Step 5 — Deepen
`WebFetch` the links worth following, still one at a time and still reducing each page to notes. Stop a branch once its content turns repetitive or leaves the topic, and cap the whole step at roughly ten additional pages — serial reads make that cap a real budget, not a formality.
## Step 6 — Write
Merge every set of notes, Context7 and web alike, by topic area, then write, in the output path:
- `<topic>.md` for each topic area that has content, default or custom. Frontmatter carries `topic:` (the filename without `.md`) and `source_keys:` (kebab-case slugs matching `sources.md`); the body is prose in `##` sections, with no inline URLs.
- `sources.md`, always, one `##` section per source — including sources that yielded nothing — with exactly these four fields:
```markdown
- **URL:** <full URL>
- **Description:** <one-line summary>
- **Contributing files:** <topic files this source contributed to>
- **Status:** `extracted` | `no content extracted`
```
Spell those four field names exactly as given. The downstream provenance validator matches them literally; prose in their place parses as nothing, and the check passes having verified nothing.
Read `references/file-format.md` when the four fields above do not settle the case: what a slug should be, the `context7-<library-slug>` slug and `context7:<library-id>` URL convention for a Context7 source, or what belongs in a topic body versus a verbatim copy of the source.
If no topic area has content, write nothing at all, `sources.md` included, and report what was searched.

View File

@@ -1,39 +0,0 @@
# Reference file format
Every topic file follows this structure.
## Frontmatter
```yaml
---
topic: <topic-slug> # matches the filename without .md (e.g. "api-reference")
source_keys: # kebab-case slugs of sources that contributed; must match sources.md entries
- <slug>
- <slug>
---
```
## Body
Plain prose organized into markdown sections (`##`, `###`). Extract the content most relevant to skill authoring or implementation — not a verbatim copy of the source. Focus on:
- Decisions that affect how to call the API or tool
- Options, flags, or parameters with non-obvious behavior
- Constraints, rate limits, or gotchas
- Canonical patterns the skill should follow
No inline URLs in the body — all source traceability lives in `sources.md` via `source_keys`.
## sources.md format
```markdown
# Sources
## <slug>
- **URL:** <full URL>
- **Description:** <one-line summary of what this source covers>
- **Contributing files:** <comma-separated list of topic files this source contributed to>
- **Status:** `extracted` | `no content extracted`
```
Use one `##` section per source. Slugs are kebab-case derived from the domain or page title (e.g. `stripe-api-docs`, `openai-python-sdk-readme`). For Context7 sources, use the slug `context7-<library-slug>` (e.g. `context7-vercel-next-js`) and set **URL** to `context7:<library-id>` (e.g. `context7:/vercel/next.js`).

View File

@@ -1,17 +0,0 @@
# Default topic list
Create one file per topic when relevant content is found. Skip topics with no content. Add custom topics when content warrants it.
| File | Covers |
|---|---|
| `overview.md` | What it is, key concepts, mental model, architecture summary |
| `installation.md` | Setup, dependencies, prerequisites, version requirements |
| `configuration.md` | Config files, options, environment variables, defaults |
| `cli-reference.md` | Commands, subcommands, flags, exit codes |
| `api-reference.md` | Endpoints, SDK methods, types, request/response shapes |
| `examples.md` | Common usage patterns, recipes, quickstart walkthroughs |
| `troubleshooting.md` | Known issues, error codes, gotchas, workarounds |
## Custom topics
Create additional topic files when content doesn't fit the defaults. Examples: `webhooks.md`, `rate-limits.md`, `authentication.md`, `migrations.md`, `security.md`. Use kebab-case filenames.

View File

@@ -1,114 +0,0 @@
---
name: tdd
description: >
Use when the user wants a feature built or a bug fixed test-first, in a strict
red-green-refactor loop, one behaviour at a time. Not diagnosing an existing
bug -> `diagnose`. Not throwaway exploratory code -> `prototype`.
metadata:
version: "1.0.1"
---
# Test-Driven Development
## Philosophy
**Core principle**: Tests should verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't.
**Good tests** are integration-style: they exercise real code paths through public APIs. They describe _what_ the system does, not _how_ it does it. A good test reads like a specification - "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure.
**Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior.
If you need worked examples of the difference — a behaviour-level test beside the implementation-coupled version of the same check — read `references/tests.md`. If a test needs a collaborator faked, read `references/mocking.md` before reaching for a mock.
## Anti-Pattern: Horizontal Slices
**DO NOT write all tests first, then all implementation.** This is "horizontal slicing" - treating RED as "write all tests" and GREEN as "write all code."
This produces **crap tests**:
- Tests written in bulk test _imagined_ behavior, not _actual_ behavior
- You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior
- Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine
- You outrun your headlights, committing to test structure before understanding the implementation
**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it.
```
WRONG (horizontal):
RED: test1, test2, test3, test4, test5
GREEN: impl1, impl2, impl3, impl4, impl5
RIGHT (vertical):
RED→GREEN: test1→impl1
RED→GREEN: test2→impl2
RED→GREEN: test3→impl3
...
```
## Workflow
### 1. Planning
When exploring the codebase, use the domain glossary so test names and interface vocabulary match the project's language, and respect ADRs in the area.
Before writing any code:
- [ ] Confirm with user what interface changes are needed
- [ ] Confirm with user which behaviors to test (prioritize)
- [ ] Identify opportunities for [deep modules](references/deep-modules.md) (small interface, deep implementation)
- [ ] Design interfaces for [testability](references/interface-design.md)
- [ ] List the behaviors to test (not implementation steps)
- [ ] Get user approval on the plan
Ask: "What should the public interface look like? Which behaviors are most important to test?"
**You can't test everything.** Confirm with the user exactly which behaviors matter most. Focus testing effort on critical paths and complex logic, not every possible edge case.
### 2. Tracer Bullet
Write ONE test that confirms ONE thing about the system:
```
RED: Write test for first behavior → test fails
GREEN: Write minimal code to pass → test passes
```
This is your tracer bullet - proves the path works end-to-end.
### 3. Incremental Loop
For each remaining behavior:
```
RED: Write next test → fails
GREEN: Minimal code to pass → passes
```
Rules:
- One test at a time
- Only enough code to pass current test
- Don't anticipate future tests
- Keep tests focused on observable behavior
### 4. Refactor
After all tests pass, look for [refactor candidates](references/refactoring.md):
- [ ] Extract duplication
- [ ] Deepen modules (move complexity behind simple interfaces)
- [ ] Apply SOLID principles where natural
- [ ] Consider what new code reveals about existing code
- [ ] Run tests after each refactor step
**Never refactor while RED.** Get to GREEN first.
## Checklist Per Cycle
```
[ ] Test describes behavior, not implementation
[ ] Test uses public interface only
[ ] Test would survive internal refactor
[ ] Code is minimal for this test
[ ] No speculative features added
```

View File

@@ -1,33 +0,0 @@
# Deep Modules
From "A Philosophy of Software Design":
**Deep module** = small interface + lots of implementation
```
┌─────────────────────┐
│ Small Interface │ ← Few methods, simple params
├─────────────────────┤
│ │
│ │
│ Deep Implementation│ ← Complex logic hidden
│ │
│ │
└─────────────────────┘
```
**Shallow module** = large interface + little implementation (avoid)
```
┌─────────────────────────────────┐
│ Large Interface │ ← Many methods, complex params
├─────────────────────────────────┤
│ Thin Implementation │ ← Just passes through
└─────────────────────────────────┘
```
When designing interfaces, ask:
- Can I reduce the number of methods?
- Can I simplify the parameters?
- Can I hide more complexity inside?

View File

@@ -1,31 +0,0 @@
# Interface Design for Testability
Good interfaces make testing natural:
1. **Accept dependencies, don't create them**
```typescript
// Testable
function processOrder(order, paymentGateway) {}
// Hard to test
function processOrder(order) {
const gateway = new StripeGateway();
}
```
2. **Return results, don't produce side effects**
```typescript
// Testable
function calculateDiscount(cart): Discount {}
// Hard to test
function applyDiscount(cart): void {
cart.total -= discount;
}
```
3. **Small surface area**
- Fewer methods = fewer tests needed
- Fewer params = simpler test setup

View File

@@ -1,59 +0,0 @@
# When to Mock
Mock at **system boundaries** only:
- External APIs (payment, email, etc.)
- Databases (sometimes - prefer test DB)
- Time/randomness
- File system (sometimes)
Don't mock:
- Your own classes/modules
- Internal collaborators
- Anything you control
## Designing for Mockability
At system boundaries, design interfaces that are easy to mock:
**1. Use dependency injection**
Pass external dependencies in rather than creating them internally:
```typescript
// Easy to mock
function processPayment(order, paymentClient) {
return paymentClient.charge(order.total);
}
// Hard to mock
function processPayment(order) {
const client = new StripeClient(process.env.STRIPE_KEY);
return client.charge(order.total);
}
```
**2. Prefer SDK-style interfaces over generic fetchers**
Create specific functions for each external operation instead of one generic function with conditional logic:
```typescript
// GOOD: Each function is independently mockable
const api = {
getUser: (id) => fetch(`/users/${id}`),
getOrders: (userId) => fetch(`/users/${userId}/orders`),
createOrder: (data) => fetch('/orders', { method: 'POST', body: data }),
};
// BAD: Mocking requires conditional logic inside the mock
const api = {
fetch: (endpoint, options) => fetch(endpoint, options),
};
```
The SDK approach means:
- Each mock returns one specific shape
- No conditional logic in test setup
- Easier to see which endpoints a test exercises
- Type safety per endpoint

View File

@@ -1,10 +0,0 @@
# Refactor Candidates
After TDD cycle, look for:
- **Duplication** → Extract function/class
- **Long methods** → Break into private helpers (keep tests on public interface)
- **Shallow modules** → Combine or deepen
- **Feature envy** → Move logic to where data lives
- **Primitive obsession** → Introduce value objects
- **Existing code** the new code reveals as problematic

View File

@@ -1,61 +0,0 @@
# Good and Bad Tests
## Good Tests
**Integration-style**: Test through real interfaces, not mocks of internal parts.
```typescript
// GOOD: Tests observable behavior
test("user can checkout with valid cart", async () => {
const cart = createCart();
cart.add(product);
const result = await checkout(cart, paymentMethod);
expect(result.status).toBe("confirmed");
});
```
Characteristics:
- Tests behavior users/callers care about
- Uses public API only
- Survives internal refactors
- Describes WHAT, not HOW
- One logical assertion per test
## Bad Tests
**Implementation-detail tests**: Coupled to internal structure.
```typescript
// BAD: Tests implementation details
test("checkout calls paymentService.process", async () => {
const mockPayment = jest.mock(paymentService);
await checkout(cart, payment);
expect(mockPayment.process).toHaveBeenCalledWith(cart.total);
});
```
Red flags:
- Mocking internal collaborators
- Testing private methods
- Asserting on call counts/order
- Test breaks when refactoring without behavior change
- Test name describes HOW not WHAT
- Verifying through external means instead of interface
```typescript
// BAD: Bypasses interface to verify
test("createUser saves to database", async () => {
await createUser({ name: "Alice" });
const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);
expect(row).toBeDefined();
});
// GOOD: Verifies through interface
test("createUser makes user retrievable", async () => {
const user = await createUser({ name: "Alice" });
const retrieved = await getUser(user.id);
expect(retrieved.name).toBe("Alice");
});
```

View File

@@ -1,108 +0,0 @@
---
name: triage
description: >
Use when the user wants an issue created, triaged, or moved through the
tracker's triage states, or an issue prepared for an AFK agent. Not debugging
the bug itself -> `diagnose`. Not fleshing out a design -> `grill-with-docs`.
metadata:
version: "1.0.1"
---
# Triage
Move issues on the project issue tracker through a small state machine of triage roles.
Every comment or issue posted to the issue tracker during triage **must** start with this disclaimer:
```
> *This was generated by AI during triage.*
```
## Reference docs
- [agent-brief.md](references/agent-brief.md) — how to write durable agent briefs
- [out-of-scope.md](references/out-of-scope.md) — how the `.out-of-scope/` knowledge base works
## Roles
Two **category** roles:
- `bug` — something is broken
- `enhancement` — new feature or improvement
Five **state** roles:
- `needs-triage` — maintainer needs to evaluate
- `needs-info` — waiting on reporter for more information
- `ready-for-agent` — fully specified, ready for an AFK agent
- `ready-for-human` — needs human implementation
- `wontfix` — will not be actioned
Every triaged issue should carry exactly one category role and one state role. If state roles conflict, flag it and ask the maintainer before doing anything else.
These are canonical role names — the actual label strings used in the issue tracker may differ. Resolve each canonical name against the tracker's live label set before applying it, using whichever tracker skill this install provides. If a name has no counterpart there, report the gap and ask the maintainer for the mapping — never substitute a guess.
State transitions: an unlabeled issue normally goes to `needs-triage` first; from there it moves to `needs-info`, `ready-for-agent`, `ready-for-human`, or `wontfix`. `needs-info` returns to `needs-triage` once the reporter replies. The maintainer can override at any time — flag transitions that look unusual and ask before proceeding.
## Invocation
The maintainer invokes `/triage` and describes what they want in natural language. Interpret the request and act. Examples:
- "Show me anything that needs my attention"
- "Let's look at #42"
- "Move #42 to ready-for-agent"
- "What's ready for agents to pick up?"
## Show what needs attention
Query the issue tracker and present three buckets, oldest first:
1. **Unlabeled** — never triaged.
2. **`needs-triage`** — evaluation in progress.
3. **`needs-info` with reporter activity since the last triage notes** — needs re-evaluation.
Show counts and a one-line summary per issue. Let the maintainer pick.
## Triage a specific issue
1. **Gather context.** Read the full issue (body, comments, labels, reporter, dates). Parse any prior triage notes so you don't re-ask resolved questions. Explore the codebase using the domain glossary, respecting ADRs in the area. Read `.out-of-scope/*.md` and surface any prior rejection that resembles this issue.
2. **Recommend.** Tell the maintainer your category and state recommendation with reasoning, plus a brief codebase summary relevant to the issue. Wait for direction.
3. **Reproduce (bugs only).** Before any grilling, attempt reproduction: read the reporter's steps, trace the relevant code, run tests or commands. Report what happened — successful repro with code path, failed repro, or insufficient detail (a strong `needs-info` signal). A confirmed repro makes a much stronger agent brief.
4. **Grill (if needed).** If the issue needs fleshing out, run a `/grill-with-docs` session.
5. **Apply the outcome:**
- `ready-for-agent` — post an agent brief comment ([agent-brief.md](references/agent-brief.md)).
- `ready-for-human` — same structure as an agent brief, but note why it can't be delegated (judgment calls, external access, design decisions, manual testing).
- `needs-info` — post triage notes (template below).
- `wontfix` (bug) — polite explanation, then close.
- `wontfix` (enhancement) — write to `.out-of-scope/`, link to it from a comment, then close ([out-of-scope.md](references/out-of-scope.md)).
- `needs-triage` — apply the role. Optional comment if there's partial progress.
## Quick state override
If the maintainer says "move #42 to ready-for-agent", trust them and apply the role directly. Confirm what you're about to do (role changes, comment, close), then act. Skip grilling. If moving to `ready-for-agent` without a grilling session, ask whether they want to write an agent brief.
## Needs-info template
```markdown
## Triage Notes
**What we've established so far:**
- point 1
- point 2
**What we still need from you (@reporter):**
- question 1
- question 2
```
Capture everything resolved during grilling under "established so far" so the work isn't lost. Questions must be specific and actionable, not "please provide more info".
## Resuming a previous session
If prior triage notes exist on the issue, read them, check whether the reporter has answered any outstanding questions, and present an updated picture before continuing. Don't re-ask resolved questions.

View File

@@ -1,168 +0,0 @@
# Writing Agent Briefs
An agent brief is a structured comment posted on an issue in the issue tracker when it moves to `ready-for-agent`. It is the authoritative specification that an AFK agent will work from. The original issue body and discussion are context — the agent brief is the contract.
## Principles
### Durability over precision
The issue may sit in `ready-for-agent` for days or weeks. The codebase will change in the meantime. Write the brief so it stays useful even as files are renamed, moved, or refactored.
- **Do** describe interfaces, types, and behavioral contracts
- **Do** name specific types, function signatures, or config shapes that the agent should look for or modify
- **Don't** reference file paths — they go stale
- **Don't** reference line numbers
- **Don't** assume the current implementation structure will remain the same
### Behavioral, not procedural
Describe **what** the system should do, not **how** to implement it. The agent will explore the codebase fresh and make its own implementation decisions.
- **Good:** "The `SkillConfig` type should accept an optional `schedule` field of type `CronExpression`"
- **Bad:** "Open src/types/skill.ts and add a schedule field on line 42"
- **Good:** "When a user runs `/triage` with no arguments, they should see a summary of issues needing attention"
- **Bad:** "Add a switch statement in the main handler function"
### Complete acceptance criteria
The agent needs to know when it's done. Every agent brief must have concrete, testable acceptance criteria. Each criterion should be independently verifiable.
- **Good:** "Querying the issue tracker for the `needs-triage` label returns issues that have been through initial classification"
- **Bad:** "Triage should work correctly"
### Explicit scope boundaries
State what is out of scope. This prevents the agent from gold-plating or making assumptions about adjacent features.
## Template
```markdown
## Agent Brief
**Category:** bug / enhancement
**Summary:** one-line description of what needs to happen
**Current behavior:**
Describe what happens now. For bugs, this is the broken behavior.
For enhancements, this is the status quo the feature builds on.
**Desired behavior:**
Describe what should happen after the agent's work is complete.
Be specific about edge cases and error conditions.
**Key interfaces:**
- `TypeName` — what needs to change and why
- `functionName()` return type — what it currently returns vs what it should return
- Config shape — any new configuration options needed
**Acceptance criteria:**
- [ ] Specific, testable criterion 1
- [ ] Specific, testable criterion 2
- [ ] Specific, testable criterion 3
**Out of scope:**
- Thing that should NOT be changed or addressed in this issue
- Adjacent feature that might seem related but is separate
```
## Examples
### Good agent brief (bug)
```markdown
## Agent Brief
**Category:** bug
**Summary:** Skill description truncation drops mid-word, producing broken output
**Current behavior:**
When a skill description exceeds 1024 characters, it is truncated at exactly
1024 characters regardless of word boundaries. This produces descriptions
that end mid-word (e.g. "Use when the user wants to confi").
**Desired behavior:**
Truncation should break at the last word boundary before 1024 characters
and append "..." to indicate truncation.
**Key interfaces:**
- The `SkillMetadata` type's `description` field — no type change needed,
but the validation/processing logic that populates it needs to respect
word boundaries
- Any function that reads SKILL.md frontmatter and extracts the description
**Acceptance criteria:**
- [ ] Descriptions under 1024 chars are unchanged
- [ ] Descriptions over 1024 chars are truncated at the last word boundary
before 1024 chars
- [ ] Truncated descriptions end with "..."
- [ ] The total length including "..." does not exceed 1024 chars
**Out of scope:**
- Changing the 1024 char limit itself
- Multi-line description support
```
### Good agent brief (enhancement)
```markdown
## Agent Brief
**Category:** enhancement
**Summary:** Add `.out-of-scope/` directory support for tracking rejected feature requests
**Current behavior:**
When a feature request is rejected, the issue is closed with a `wontfix` label
and a comment. There is no persistent record of the decision or reasoning.
Future similar requests require the maintainer to recall or search for the
prior discussion.
**Desired behavior:**
Rejected feature requests should be documented in `.out-of-scope/<concept>.md`
files that capture the decision, reasoning, and links to all issues that
requested the feature. When triaging new issues, these files should be
checked for matches.
**Key interfaces:**
- Markdown file format in `.out-of-scope/` — each file should have a
`# Concept Name` heading, a `**Decision:**` line, a `**Reason:**` line,
and a `**Prior requests:**` list with issue links
- The triage workflow should read all `.out-of-scope/*.md` files early
and match incoming issues against them by concept similarity
**Acceptance criteria:**
- [ ] Closing a feature as wontfix creates/updates a file in `.out-of-scope/`
- [ ] The file includes the decision, reasoning, and link to the closed issue
- [ ] If a matching `.out-of-scope/` file already exists, the new issue is
appended to its "Prior requests" list rather than creating a duplicate
- [ ] During triage, existing `.out-of-scope/` files are checked and surfaced
when a new issue matches a prior rejection
**Out of scope:**
- Automated matching (human confirms the match)
- Reopening previously rejected features
- Bug reports (only enhancement rejections go to `.out-of-scope/`)
```
### Bad agent brief
```markdown
## Agent Brief
**Summary:** Fix the triage bug
**What to do:**
The triage thing is broken. Look at the main file and fix it.
The function around line 150 has the issue.
**Files to change:**
- src/triage/handler.ts (line 150)
- src/types.ts (line 42)
```
This is bad because:
- No category
- Vague description ("the triage thing is broken")
- References file paths and line numbers that will go stale
- No acceptance criteria
- No scope boundaries
- No description of current vs desired behavior

View File

@@ -1,101 +0,0 @@
# Out-of-Scope Knowledge Base
The `.out-of-scope/` directory in a repo stores persistent records of rejected feature requests. It serves two purposes:
1. **Institutional memory** — why a feature was rejected, so the reasoning isn't lost when the issue is closed
2. **Deduplication** — when a new issue comes in that matches a prior rejection, the skill can surface the previous decision instead of re-litigating it
## Directory structure
```
.out-of-scope/
├── dark-mode.md
├── plugin-system.md
└── graphql-api.md
```
One file per **concept**, not per issue. Multiple issues requesting the same thing are grouped under one file.
## File format
The file should be written in a relaxed, readable style — more like a short design document than a database entry. Use paragraphs, code samples, and examples to make the reasoning clear and useful to someone encountering it for the first time.
```markdown
# Dark Mode
This project does not support dark mode or user-facing theming.
## Why this is out of scope
The rendering pipeline assumes a single color palette defined in
`ThemeConfig`. Supporting multiple themes would require:
- A theme context provider wrapping the entire component tree
- Per-component theme-aware style resolution
- A persistence layer for user theme preferences
This is a significant architectural change that doesn't align with the
project's focus on content authoring. Theming is a concern for downstream
consumers who embed or redistribute the output.
```ts
// The current ThemeConfig interface is not designed for runtime switching:
interface ThemeConfig {
colors: ColorPalette; // single palette, resolved at build time
fonts: FontStack;
}
```
## Prior requests
- #42 — "Add dark mode support"
- #87 — "Night theme for accessibility"
- #134 — "Dark theme option"
```
### Naming the file
Use a short, descriptive kebab-case name for the concept: `dark-mode.md`, `plugin-system.md`, `graphql-api.md`. The name should be recognizable enough that someone browsing the directory understands what was rejected without opening the file.
### Writing the reason
The reason should be substantive — not "we don't want this" but why. Good reasons reference:
- Project scope or philosophy ("This project focuses on X; theming is a downstream concern")
- Technical constraints ("Supporting this would require Y, which conflicts with our Z architecture")
- Strategic decisions ("We chose to use A instead of B because...")
The reason should be durable. Avoid referencing temporary circumstances ("we're too busy right now") — those aren't real rejections, they're deferrals.
## When to check `.out-of-scope/`
During triage (Step 1: Gather context), read all files in `.out-of-scope/`. When evaluating a new issue:
- Check if the request matches an existing out-of-scope concept
- Matching is by concept similarity, not keyword — "night theme" matches `dark-mode.md`
- If there's a match, surface it to the maintainer: "This is similar to `.out-of-scope/dark-mode.md` — we rejected this before because [reason]. Do you still feel the same way?"
The maintainer may:
- **Confirm** — the new issue gets added to the existing file's "Prior requests" list, then closed
- **Reconsider** — the out-of-scope file gets deleted or updated, and the issue proceeds through normal triage
- **Disagree** — the issues are related but distinct, proceed with normal triage
## When to write to `.out-of-scope/`
Only when an **enhancement** (not a bug) is rejected as `wontfix`. The flow:
1. Maintainer decides a feature request is out of scope
2. Check if a matching `.out-of-scope/` file already exists
3. If yes: append the new issue to the "Prior requests" list
4. If no: create a new file with the concept name, decision, reason, and first prior request
5. Post a comment on the issue explaining the decision and mentioning the `.out-of-scope/` file
6. Close the issue with the `wontfix` label
## Updating or removing out-of-scope files
If the maintainer changes their mind about a previously rejected concept:
- Delete the `.out-of-scope/` file
- The skill does not need to reopen old issues — they're historical records
- The new issue that triggered the reconsideration proceeds through normal triage

View File

@@ -1,109 +0,0 @@
---
name: write-docs
description: >
Use when the user wants technical documentation produced or updated from code
or spec, every claim traced to a source — "write docs for X", "document this
module", "create docs for this feature", "write a README for this". Not an ADR
or other decision record -> `grill-with-docs`. Not an external tool researched
from its docs -> `research`.
updated: 2026-05-17
when: invoked by explicit trigger ("write docs for X", "document this module", "create docs for this feature") or implicit request to produce technical documentation from code or spec
metadata:
version: "1.0.0"
category: implement
source:
- repo: anthropics/skills
commit: f458cee31a7577a47ba0c9a101976fa599385174
files:
- skills/doc-coauthoring/SKILL.md # Reader Testing stage, surgical-edit constraint, gap-check step
updated: 2026-05-17
- repo: mattpocock/skills
commit: e74f0061bb67222181640effa98c675bdb2fdaa7
files:
- skills/productivity/write-a-skill/SKILL.md # trigger pattern, review checklist items
updated: 2026-05-17
- repo: bmad-code-org/BMAD-METHOD
commit: 71136bc6af77cbf507d3768494311d5b6ca95cc5
files:
- src/core-skills/bmad-advanced-elicitation/SKILL.md # confirmation gate before applying changes
updated: 2026-05-17
---
## Role
You are a technical writer that produces documentation by reading code and spec — you derive every claim from a source file or explicit user input and never invent behaviour.
## When to use / When not to use
**Use when:**
- User wants to document a module, class, function, feature, CLI flag, API endpoint, config file, or README section
- User says "write docs for X", "document this", "create docs for this feature", "write a README for this"
**Do not use when:**
- User wants an ADR, decision doc, or architecture proposal → `grill-with-docs`, which writes ADRs
- User wants a PRD → no skill in this set produces one; say so rather than redirecting
- User wants to document a skill file (skill files are self-describing)
- User wants marketing or blog copy
- Documentation requires tacit organisational knowledge that cannot be read from code or spec
## Required inputs
- Specific file(s) or module(s) to document, or enough description to propose candidates
- Target audience: developer / user / contributor / internal
- Documentation type: reference, guide, README section, inline comment, changelog entry
## Constraints
- Every claim must be traceable to a source file line, spec section, or explicit user statement — never invent behaviour
- User must approve specific files before the skill reads them; skill may propose candidates but waits for approval
- Stage skipping is allowed only with an explicit user request and a one-sentence logged reason
- Show the full revised section before each confirmation gate — never gate on output the user has not seen
- Never reprint the whole document; all edits are surgical
- Produce a one-line delta summary after each refinement round
- Reader Testing sub-agent receives only the finished doc and the question list — no source files
- Write summary and overview sections last, after all detail sections are stable
## Process
1. **Identify scope.** User names specific files or sections. If not provided, propose candidates based on the description — wait for explicit approval before reading.
2. **Read and extract.** Read approved files. Extract: public API surface, described behaviour, visible constraints, non-obvious invariants. Note what the code does NOT explain (caller intent, error handling rationale, non-obvious side effects).
3. **Gap check.** Present extracted behaviour to the user. Ask them to fill only the gaps — what the code does not explain. Log any explicitly deferred gaps. If the user requests to skip this step, log the reason and proceed.
4. **Draft section by section.** For each section: state the proposed content and its source (code line / spec section / user input). Show; confirm before moving to the next section.
5. **Confirmation gate.** Before finalising any section, show the full revised section. Wait for explicit confirmation or correction — never apply changes the user has not seen.
6. **Delta summary.** After each round of revisions: "Round N: changed [sections], added [X], removed [Y]."
7. **Reader Testing.** Predict 5–10 questions a target reader would ask. Spawn a scoped sub-agent that receives only the finished doc and the questions — no source files. Report its answers. If any answers fail, loop back to step 4.
8. **Finalise.** Write summary and overview sections last. Prompt the user to review the complete document before committing.
## Output format
- Markdown artifact with section headers; produced one section at a time — never as a single large dump
- Delta summary after each refinement round: "Round N: [what changed]"
- Reader Testing report: numbered question list with sub-agent answers
- Final doc at the user-specified or conventionally appropriate path
## Failure handling
- Files not named and description too vague to propose candidates → ask for specific names before reading
- Stage skipped without a logged reason → flag and require the one-sentence log before continuing
- Code behaviour is undocumentable (internal implementation detail, no public spec) → note as out-of-scope in the doc; do not invent an explanation
- Reader Testing sub-agent fails on multiple questions → surface the failures, return to step 4; do not mark complete
- Requested output is an ADR, decision doc, or architecture proposal → redirect to `grill-with-docs`; for a PRD, say no skill here produces one instead of redirecting
## Self-check
- [ ] All claims traceable to a source file or explicit user input
- [ ] No invented behaviour — unverifiable claims removed
- [ ] User approved specific files before reading
- [ ] Any stage skips logged with reason
- [ ] Full revised section shown before each confirmation gate
- [ ] Delta summary produced after each refinement round
- [ ] Reader Testing completed with scoped sub-agent (doc + questions only)
- [ ] Summary/overview written last
- [ ] User prompted to review before committing

View File

@@ -1,9 +0,0 @@
---
name: zoom-out
description: Tell the agent to zoom out and give broader context or a higher-level perspective. Use when you're unfamiliar with a section of code or need to understand how it fits into the bigger picture.
disable-model-invocation: true
metadata:
version: "1.0.1"
---
I don't know this area of code well. Go up a layer of abstraction. Give me a map of all the relevant modules and callers, using the project's domain glossary.