Install a write-time hook that checks instruction artifacts as they are edited, so the defects the audit passes hunt stop accumulating between rituals — the one spell in this book that ships a mechanism rather than prose. Runs only the checks a script can decide without a model: emphasis inflation, descriptions past the truncation cliff, undeclared agent model tiers, rule globs matching nothing, memory files over a size ceiling. Use for "stop this happening again", "enforce the opus pocus rul...
Installs into .claude/skills of the current project.
Are you the author of Protego?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/totes-mickgoats-protego)
---
name: protego
description: Install a write-time hook that checks instruction artifacts as they are edited, so the defects the audit passes hunt stop accumulating between rituals — the one spell in this book that ships a mechanism rather than prose. Runs only the checks a script can decide without a model: emphasis inflation, descriptions past the truncation cliff, undeclared agent model tiers, rule globs matching nothing, memory files over a size ceiling. Use for "stop this happening again", "enforce the opus pocus rules", "add a lint for my CLAUDE.md", "how do I keep this from regressing", or as part of /opus-pocus. Advisory by default, never blocking. NOT for auditing what is already there (→ the audit passes). NOT for judgement calls a script cannot make.
---
# 🦋 Protego
> *"The cheapest curse to remove is the one that never lands."*
This book has one loud doctrine — *if a rule matters enough to shout, it matters enough to enforce
with a hook; blocking hooks achieve near-total compliance, prose is best-effort* — and until this
spell it was entirely prose: a whole book of advice about mechanism, delivered as text, to be
obeyed by goodwill.
Protego is the shield: a hook that runs when an instruction artifact is written, catching the
mechanically-decidable defects at the moment they are introduced. Not so the audit becomes
unnecessary, but so it stops re-finding the same five classes every quarter.
## What ships
- `hooks/protego.sh` — the check itself. Reads the hook payload on stdin, works out whether the
edited file is an instruction artifact, runs the checks, and emits **only when it has a
finding**.
- A `hooks` block for the plugin manifest wiring it to `PostToolUse` on `Write|Edit`.
Installed as part of the plugin, it is already wired. Copied into a repo by hand, wire it in that
repo's settings file with the same event and matcher.
## What it checks
Only what a script can decide without a model. Each finding names the spell that owns the full
treatment, because the hook's job is to notice, not to adjudicate:
| Check | Fires when | Owner |
|---|---|---|
| Emphasis inflation | over 6 emphasis tokens in a file under 500 words, or over ~10 per 1k words above that — the small-N split `quietus-capslockius` uses, because one `NEVER` in a 300-word file is a rate of 3.3/1k and means nothing | `quietus-capslockius` |
| Description length | a skill or agent `description:` over 1,200 characters, conservatively under the commonly-measured cliff | `descriptio-reducio` |
| Late `NOT for` | the disambiguation clause starts past character 900 — the part that prevents wrong routing is the part most likely truncated | `descriptio-reducio` |
| Undeclared model tier | an agent with no `model:`, **and only on a roster of 5 or more** — below that, inheriting is correct and `sorting-hat` says so | `sorting-hat` |
| Dead rule glob | a `paths:` entry matching zero tracked files under **both** git pathspec modes | `accio-rulebook` |
| Memory file size | over 25,000 bytes | `obliviate-fossilium` |
What it deliberately does not check: anything needing judgement. Whether a rule is vague, whether
two rules contradict, whether a verify-your-work line has a loop partner — those are model
questions, and a script guessing at them produces exactly the false positives that teach people to
disable hooks.
## Advisory by default, and why
**It never blocks. It always exits 0.**
Its thresholds are unmeasured in your repo. The truncation cliff is harness-specific, the size
ceiling is a judgement, and the emphasis threshold is a heuristic with real exceptions — a
security guard's `NEVER` is correct at any count. A blocking gate built on numbers nobody measured
here, shipped into strangers' repositories, is precisely the failure `alohomora` documents: a
guard that refuses legitimate work, whose natural remedy is a bypass, which trains everyone to
bypass it.
It also stays quiet on a clean file. A hook that speaks on every edit is the noise
`muffliato-hookus` exists to cut, and silence-as-output is the only honest default.
### Making it blocking, deliberately
If you want it to refuse rather than advise, that is a reasonable choice **after** you have done
what `alohomora` requires of any blocking guard:
1. **Measure your own thresholds first.** Run `descriptio-reducio` for your real cliff and
`quietus-capslockius` for your emphasis baseline. Blocking on someone else's numbers is
blocking on nothing.
2. **Build the negative corpus.** Collect the instruction files in your repo that are *correct*
and must never fire, and confirm the hook stays silent on all of them. Negative tests are the
deliverable, not an afterthought.
3. **Narrow to one check.** Block on the single check you have measured; leave the rest advisory.
A guard that blocks on six heuristics fails on the weakest one.
4. **Give the escape a TTL, an attribution and a ceiling** before you need it, not after.
Then change the emitted decision, and keep the negative corpus as a test that runs on change.
## Bounds
- Scope: instruction artifacts only — memory files, `.claude/skills/`, `.claude/agents/`, `.claude/rules/`. Every other path exits immediately and silently.
- Cap: the checks above and no more. Adding a check that needs a model turns a hook into a spiral; adding one whose threshold you have not measured turns it into an `alohomora` finding.
- Done when the hook is installed, wired, and pipe-tested. Not when it stops finding things — it is meant to keep running.
- **Test before shipping any change to it.** Pipe a synthetic payload: a file that must fire, a file that must not, empty stdin, malformed JSON, and a path that does not exist. An untested hook is this book's own `priori-incantato` finding.
- Degrade quietly: absent input, unparseable payload, missing file, no `python3`, no `git` — every one of those is silence and exit 0, never an error surfaced as a tool failure.
- See `skills/opus-pocus/references/casting-safety.md` for the full rules.
## Report format
When installing: confirm the wiring (which event, which matcher), paste the pipe-test output for
the fire case and the silent case, and state which checks are active. When proposing changes to
it: the check, the threshold, where the threshold came from, and the negative-corpus result.
`SCANNED NOTHING` if the repo has no instruction artifacts for it to watch — a shield over an
empty doorway is not protection, and installing it there would claim a coverage that does not
exist.