docs: exclude misc/ skills from the public docs

misc/ skills are niche — they stay promoted (README + plugin manifest,
so they're installable) but no longer get a public aihero.dev docs
page. Remove the four misc pages and decouple the docs rule from the
promotion rule in CLAUDE.md and the writing-docs guide.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Matt Pocock 2026-07-01 11:31:29 +01:00
parent ade35dc0d8
commit 8fa032a8fd
6 changed files with 3 additions and 164 deletions

View file

@ -1,10 +1,10 @@
# Writing docs pages # Writing docs pages
Every promoted skill (`engineering/`, `productivity/`, `misc/`) has a human-facing **docs page** at `docs/<bucket>/<skill-name>.md` — the docs tree mirrors the bucket folders under `skills/`. It is published at `https://aihero.dev/skills-<skill-name>`; the URL is always `skills-<skill-name>` regardless of bucket, so the docs path is repo organisation only. The page is not the skill and not a copy of `SKILL.md`. Every skill in `engineering/` and `productivity/` has a human-facing **docs page** at `docs/<bucket>/<skill-name>.md` — the docs tree mirrors those two bucket folders under `skills/`. It is published at `https://aihero.dev/skills-<skill-name>`; the URL is always `skills-<skill-name>` regardless of bucket, so the docs path is repo organisation only. The page is not the skill and not a copy of `SKILL.md`. `misc/` skills are promoted (they appear in the README and plugin manifest, so they're installable) but deliberately get **no** public docs page — they're niche enough to earn an install entry but not an `aihero.dev` page.
Most of these skills are **user-invoked**: the agent will never fire them for you, so *you* are the index that has to remember they exist and when to reach for them. That memory is **cognitive load**. The job of a docs page is to relieve it — to orient one reader around one skill so they can hold it in their head, know when to reach for it, and see where it sits in the system. The pages are collectively a distributed router; each is a node. Most of these skills are **user-invoked**: the agent will never fire them for you, so *you* are the index that has to remember they exist and when to reach for them. That memory is **cognitive load**. The job of a docs page is to relieve it — to orient one reader around one skill so they can hold it in their head, know when to reach for it, and see where it sits in the system. The pages are collectively a distributed router; each is a node.
Act whenever a promoted skill is added, renamed, or has its behaviour changed: create or re-sync its docs page. A rename moves the file too (`docs/<bucket>/<old>.md``docs/<bucket>/<new>.md`), because the published URL tracks the name; a skill that moves buckets moves its docs file to the matching folder. Skills in `personal/`, `in-progress/`, and `deprecated/` get no page, mirroring the README rule. Act whenever a promoted skill is added, renamed, or has its behaviour changed: create or re-sync its docs page. A rename moves the file too (`docs/<bucket>/<old>.md``docs/<bucket>/<new>.md`), because the published URL tracks the name; a skill that moves between `engineering/` and `productivity/` moves its docs file to the matching folder. Skills in `personal/`, `in-progress/`, and `deprecated/` get no page because they aren't promoted at all; `misc/` skills get no page despite being promoted. A skill moving *into* `misc/` loses its docs page; one moving *out* of `misc/` into `engineering/` or `productivity/` gains one.
Because these pages are published on `aihero.dev`, **every link is absolute** — never a repo-relative path. A link to another skill points at `https://aihero.dev/skills-<name>`; a link into the repo points at its full `https://github.com/mattpocock/skills/...` URL. A relative link that works in the repo breaks once published. Because these pages are published on `aihero.dev`, **every link is absolute** — never a repo-relative path. A link to another skill points at `https://aihero.dev/skills-<name>`; a link into the repo points at its full `https://github.com/mattpocock/skills/...` URL. A relative link that works in the repo breaks once published.

View file

@ -13,7 +13,7 @@ Each skill entry in the top-level `README.md` must link the skill name to its `S
Each bucket folder has a `README.md` that lists every skill in the bucket with a one-line description, with the skill name linked to its `SKILL.md`. Bucket `README.md`s and the top-level `README.md` group entries into **User-invoked** and **Model-invoked**. Each bucket folder has a `README.md` that lists every skill in the bucket with a one-line description, with the skill name linked to its `SKILL.md`. Bucket `README.md`s and the top-level `README.md` group entries into **User-invoked** and **Model-invoked**.
Every promoted skill also has a human-facing docs page at `docs/<bucket>/<skill-name>.md` (the docs tree mirrors the bucket folders under `skills/`). The published URL is `https://aihero.dev/skills-<skill-name>` regardless of bucket — the docs path is repo organisation only. When you add, rename, or change the behaviour of a skill in `engineering/`, `productivity/`, or `misc/`, create or re-sync its docs page following [.agents/writing-docs.md](./.agents/writing-docs.md). Skills in `engineering/` and `productivity/` also have a human-facing docs page at `docs/<bucket>/<skill-name>.md` (the docs tree mirrors those two bucket folders under `skills/`). The published URL is `https://aihero.dev/skills-<skill-name>` regardless of bucket — the docs path is repo organisation only. When you add, rename, or change the behaviour of a skill in `engineering/` or `productivity/`, create or re-sync its docs page following [.agents/writing-docs.md](./.agents/writing-docs.md). `misc/` skills are promoted (README + `plugin.json`) but get **no** docs page.
Every `SKILL.md` is either user-invoked (`disable-model-invocation: true`, reachable only by the human) or model-invoked (model- or user-reachable). See [.agents/invocation.md](./.agents/invocation.md). Every `SKILL.md` is either user-invoked (`disable-model-invocation: true`, reachable only by the human) or model-invoked (model- or user-reachable). See [.agents/invocation.md](./.agents/invocation.md).

View file

@ -1,38 +0,0 @@
Quickstart:
```bash
npx skills add mattpocock/skills --skill=git-guardrails-claude-code
```
```bash
npx skills update git-guardrails-claude-code
```
[Source](https://github.com/mattpocock/skills/tree/main/skills/misc/git-guardrails-claude-code)
## What it does
`git-guardrails-claude-code` installs a Claude Code **PreToolUse hook** that blocks destructive git commands — `git push`, `reset --hard`, `clean -f`, `branch -D`, `checkout .` / `restore .` — before they run.
This is a **guardrail**, not a request. The block lives in the harness, not in the agent's instructions — the hook inspects every Bash command and, on a match, exits with code 2 so the command never executes. An agent can forget a "please don't push" note in its prompt; it cannot talk its way past a hook that fires before the tool call lands.
## When to reach for it
Type `/git-guardrails-claude-code`, or the agent reaches for it automatically when a task fits.
Reach for it when you want an agent to work freely in a repo but never perform the handful of git operations that lose work or rewrite shared history. It's a one-time install: run it once per project (or once globally) and the guardrail is standing thereafter. For enforcing quality *at commit time* — Prettier, type-checking, tests via Husky — that's a different mechanism, so use [setup-pre-commit](https://aihero.dev/skills-setup-pre-commit) instead.
## The guardrail
The hook is a small shell script matching each Bash command against a list of dangerous patterns. When one matches, the agent sees a `BLOCKED` message telling it that it does not have authority to run that command, and the command is dropped.
Two knobs at install time: **scope** — this project (`.claude/settings.json`) or all projects (`~/.claude/settings.json`) — and the **pattern list**, which you can extend or trim so the wall sits exactly where you want it. Everything not on the list still runs untouched.
## It's working if
- A blocked command (e.g. `git push`) never executes, and the agent reports it was denied rather than that it failed.
- Ordinary git — `add`, `commit`, `status`, `checkout <branch>` — runs as normal.
## Where it fits
This is a **run-once setup** skill, and a standalone: install the guardrail and forget it. Its closest neighbour is [setup-pre-commit](https://aihero.dev/skills-setup-pre-commit), which also writes hooks into a repo but guards commit *quality* rather than destructive git *actions* — the two stack cleanly. When you're unsure which safety or setup skill fits, [ask-matt](https://aihero.dev/skills-ask-matt) routes you.

View file

@ -1,43 +0,0 @@
Quickstart:
```bash
npx skills add mattpocock/skills --skill=migrate-to-shoehorn
```
```bash
npx skills update migrate-to-shoehorn
```
[Source](https://github.com/mattpocock/skills/tree/main/skills/misc/migrate-to-shoehorn)
## What it does
`migrate-to-shoehorn` sweeps a test suite for `as` type assertions and replaces them with `@total-typescript/shoehorn` helpers, so a test can pass just the properties it cares about while TypeScript stays happy.
This is **test code only**. Shoehorn exists to fake partial data behind a type-safe front; it must never touch production code, where a real value is always required.
## When to reach for it
Type `/migrate-to-shoehorn`, or the agent reaches for it automatically when a task fits — it triggers when you mention shoehorn, want to strip `as` out of tests, or need to hand a function partial test data.
Reach for it when a test is forced to fabricate a whole object — every header, every cookie, twenty more fields — just to satisfy one property the assertion actually reads, or when `as unknown as Type` is smuggling deliberately-wrong data past the compiler for an error case.
## The partial idea
The word to think with is **partial**. A test rarely needs a complete object; it needs the one or two fields under test. `as` forces you to either build the whole thing or lie to the compiler. Shoehorn lets you supply the *partial* and infers the rest:
- `fromPartial()` — pass the fields that matter, still type-checked against the real shape.
- `fromAny()` — pass intentionally wrong data for error paths, keeping autocomplete.
- `fromExact()` — force a full object when you want no gaps.
The migration is mechanical: `as Type` becomes `fromPartial()`, `as unknown as Type` becomes `fromAny()`, imports get added, and a type check confirms the swap held.
## It's working if
- Test files no longer carry `as Type` or `as unknown as Type` on faked data.
- Each migrated call passes only the properties the test reads, wrapped in `fromPartial` or `fromAny`.
- The type check still passes, and no shoehorn import leaks into production source.
## Where it fits
This is a reach-for-it-anytime standalone — a one-shot cleanup you run over a test file or suite whenever `as` has crept in. It sits naturally alongside [tdd](https://aihero.dev/skills-tdd), which is where those test files get written in the first place and where partial test data pays off most. When you're unsure which skill fits, [ask-matt](https://aihero.dev/skills-ask-matt) routes you.

View file

@ -1,43 +0,0 @@
Quickstart:
```bash
npx skills add mattpocock/skills --skill=scaffold-exercises
```
```bash
npx skills update scaffold-exercises
```
[Source](https://github.com/mattpocock/skills/tree/main/skills/misc/scaffold-exercises)
## What it does
`scaffold-exercises` reads a course plan and builds the exercise directory tree it describes — numbered sections, numbered exercises, and their `problem/`, `solution/`, and `explainer/` variant folders, each seeded with a stub `readme.md`.
The scaffold is only done when it **passes `pnpm ai-hero-cli internal lint`**. The linter is the contract — folder shape, numeric prefixes, non-empty readmes, no stray `.gitkeep` or `speaker-notes.md`, no broken links. The skill scaffolds, runs the lint, and iterates until it's green rather than leaving you a tree that merely looks right.
## When to reach for it
Type `/scaffold-exercises`, or the agent reaches for it automatically when a task fits — turning a plan into stubbed exercise directories, or setting up a new course section.
Reach for it when you have a plan (section names, exercise names, which variants each needs) and want the skeleton on disk and lint-clean before you write any real content. It only lays down structure and empty-but-valid readmes; the teaching material comes later.
## Prerequisites
The skill writes into an `exercises/` directory and validates with `pnpm ai-hero-cli internal lint`, so run it inside a course repo that has the AI Hero CLI available. Outside that tooling the lint step — the whole point — can't run.
## Lint-passing is the spec
The naming isn't cosmetic: sections are `XX-section-name/`, exercises are `XX.YY-exercise-name/` in dash-case, and every variant folder carries a non-empty `readme.md`. Those rules exist because the linter enforces them, and the linter is what downstream course tooling relies on. So the mental model is inverted from "make a folder tree" to "make a tree the linter accepts" — default new stubs to `explainer/`, keep readmes real (a single title line counts), and let the lint pass be the definition of done.
Renumbering later follows the same rule: use `git mv` so history survives, then re-run lint.
## It's working if
- `pnpm ai-hero-cli internal lint` passes with the new tree in place.
- Every variant folder has a non-empty `readme.md`; no `.gitkeep` or `speaker-notes.md` slipped in.
- Section and exercise folders carry correct `XX` / `XX.YY` prefixes in dash-case.
## Where it fits
`scaffold-exercises` is a reach-for-it-anytime standalone at the start of building a course section: it produces the empty, lint-clean scaffold you then fill in. It sits next to Matt's course-planning work — once a plan exists, this turns it into directories — but it owns no planning itself. When you're unsure which skill or flow fits, [ask-matt](https://aihero.dev/skills-ask-matt) routes you.

View file

@ -1,37 +0,0 @@
Quickstart:
```bash
npx skills add mattpocock/skills --skill=setup-pre-commit
```
```bash
npx skills update setup-pre-commit
```
[Source](https://github.com/mattpocock/skills/tree/main/skills/misc/setup-pre-commit)
## What it does
`setup-pre-commit` wires up a Husky pre-commit hook in the current repo: lint-staged runs Prettier over your staged files, then a type check and the test suite run before the commit is allowed through.
It **adapts to the repo instead of imposing a fixed config**. It detects your package manager from the lockfile, only wires up the `typecheck` and `test` steps that already exist as scripts (and tells you which it skipped), and writes a Prettier config only if you don't already have one. You get a working gate tuned to what the repo actually has, not a template you then have to unpick.
## When to reach for it
Type `/setup-pre-commit`, or the agent reaches for it automatically when a task fits.
Reach for it when a repo has no commit-time formatting or checks and you want them added once — "set up Husky", "add pre-commit hooks", "run Prettier on commit". It is about the commit boundary specifically; to stop dangerous git operations (`push`, `reset --hard`, `clean`) from running at all, use [git-guardrails-claude-code](https://aihero.dev/skills-git-guardrails-claude-code) instead.
## The gate
The hook is a **gate**: nothing lands in a commit until it passes. Ordering is deliberate — lint-staged goes first because it is fast and touches only staged files, then the slower whole-repo `typecheck` and `test` run. The final step is a real commit through the new hook, so the gate is smoke-tested the moment it's installed rather than the next time you happen to commit.
## It's working if
- A commit runs Prettier, the type check, and the tests before it completes — and a failing check aborts the commit.
- `.husky/pre-commit`, `.lintstagedrc`, and a Prettier config exist, and `prepare` in package.json is `"husky"`.
- The hook uses your repo's package manager, and only names steps whose scripts exist.
## Where it fits
A **run-once setup** — you install the gate once per repo and it runs on every commit thereafter, no re-invocation. Its natural neighbour is [git-guardrails-claude-code](https://aihero.dev/skills-git-guardrails-claude-code), because the two guard different edges: this one gates what enters a commit, that one blocks destructive git commands from executing. When you're unsure which skill fits, [ask-matt](https://aihero.dev/skills-ask-matt) routes you.