Use when adding or changing a skill, hook, or runtime file in this repo — including deciding which unit a new capability should be.
Doctrine for authoring moo's own surfaces.
A skill's frontmatter carries name and description; read any shipped SKILL.md for the current key set. The description is one line, and Claude Code caps it at 1024 characters.
No when_to_use. Claude Code reads that key and renders it dash-joined onto the description, but every other agent copies SKILL.md verbatim and never reads it, so the text deciding when a skill fires would be invisible wherever it is installed outside Claude Code.
A condition that follows what the skill does is marked Use when <condition>. — a finite clause, never a bare noun phrase or a bare dash. The key name was what marked the condition as a condition; in one string nothing else does, and an unmarked trailing clause reads as more of what the skill produces. A description may also open with the condition and stop there, where naming the capability would discriminate nothing.
A skill that stays in this repo declares metadata.internal: true. The skills.sh installer walks the tree and offers every SKILL.md it finds; that flag is what it filters on.
Version lives in plugin.json only (DRY). The official Claude Code spec does not allow version in SKILL.md frontmatter.
Phrase design decisions as "X over Y: reason".
Unit choice — behavior inlines at build, data references at runtime; a skill's firing is probabilistic, so behavior that must run every time is a hook:
| The new thing is... | Unit |
|---|---|
| Data selected per use (catalog, profile, corpus) | Runtime file |
| A trigger + procedure that stands alone | Skill |
| A trigger only the human perceives | Skill with disable-model-invocation: true |
| Behavior that must run every time, deterministically | Function hook |
| An unproven idea | hunch skill + HYPOTHESIS.md; graduates or dies |
| Doctrine for this repo's own surfaces | Repo-local skill in .claude/skills/; never ships |
Composition — name-calls, never imports:
Output form — bound by what the skill hands back, never by one shared sentence. Plain words is the only part that holds across all three:
| The Output hands back | Bound it by |
|---|---|
| Something the agent restated in its own words | As short as it goes with nothing the skill can't afford to drop lost — name that thing, it differs per skill |
| The user's own words — a record, an amended proposal | Preserving them. A compression clause here destroys the result |
| A structure the reader navigates — verdict then evidence, a case set then a rule | Bounding each part where a reader would pad it, never the whole |
A cap counted in lines is a compression budget on a handed-back artifact — replace it. A cap on one turn of a loop is pacing, and the rest arrives on the user's next pull — keep it.
Every hook is a function hook: it reaches the human with no model turn. The API is early access; plugin-authoring and /plugin-types are the reference for every event and call.
$.prompt.submit of its own.$.prompt.fill a sentence start they finish, with any bulk added as prompt.submit context.$.state (this session) or $.store (across sessions), never in temp files or module variables. A hot reload drops module variables.A hook that spawns headless claude -p copies its flag set from hope/hooks/judge.sh, where each flag is commented at the point of use.
595eda0
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.