v0.3.0 — Doctrine
Doctrine. The skill taught two filters for what earns its tokens and left a hole between them: nothing screened the sentences that justify a claim. A generator following both faithfully wrote a one-clause rule under three sentences of argument — and every harness this skill produces inherited that shape. This release closes the hole and then applies it to the skill's own surface.
Added
- The filter extended to the why.
SKILL.mdnow screens justification the same way it screens claims, and names the five shapes that go: restating what you just said, arguing for it, spelling out a consequence the reader computes anyway, giving the negative case equal weight when the positive implies it, and narrating what the next paragraph will do. Named, because a model cannot recognize "cut the persuasion" in its own prose without them. - The parameter space as a teaching surface, and its link to compression. An argument that takes three named values teaches the three cases by existing; prose moved into a signature is not shortened, it is relocated to a surface re-read for free.
- References need not be prose. A failing test, a schema, a rubric, or a function in another codebase pins a target more precisely than a paragraph describing it — and the runnable ones fail loudly when the target moves, where a paragraph goes quietly stale.
- A check's failure message is an interface too, read at exactly the moment it matters and free otherwise.
hook_event.py— look up one hook event's schema (--event PreToolUse, 432 words) instead of reading all thirty (3,777). Its--eventchoices are generated from the file, so the signature doubles as the authoritative event list; several of these events postdate common training data, and a model that cannot see them enumerated refuses to author one as nonexistent.
Fixed
validate_harness.pyno longer fails correct harnesses on a validmodel:. It enumerated model ids, so the documented aliasfableand the idclaude-opus-5both drew "unrecognized" whileclaude-opus-4-8passed. It now checks shape — a documented alias, or anyclaude-prefixed id — so it cannot go wrong on its own as models ship.Setuphook triggers were documented wrong. The event router listed--init-only/--init/--maintenanceas three equivalent flags; the latter two do nothing without-p. A generator reading only that file — the one it is told to read first, on every hook task — would wire aSetuphook that never fires.SessionEndwas ordered beforeElicitationin the router while the schema reference called its own list authoritative. The docs agree with the schema reference.- Workflow permission rules now carry their reason. The skill told the generator to write matching
permissions.allowentries and never to record why, so they read as ordinary convenience allowances on disk — and the next person tightening permissions deletes them, leaving a workflow that stalls mid-run on a prompt nobody is watching.
Changed
- Three lint findings gained a consequence clause, on the theory that a check's message is read exactly when it matters: the 500-line skill guideline now says why 500, a malformed
paths:glob says the rule will never fire, and a missing spec says drift detection reports nothing in either direction. - Three others deliberately did not. The docs do not say what happens when an
@importtarget is missing, or when subagent frontmatter fails to parse, or when amodel:value is simply a typo. Writing a plausible consequence would have put an invented mechanic in a linter whose entire value is that its gotchas are real; a test now asserts those messages stay bare. - The skill's own prose was compressed against the new filter. Total words 30,712 → 30,072 (−2.1%); words trapped in paragraphs of 110 or more, 9,476 → 7,861 (−17.0%). The gap between those two numbers is the change: these files did not get shorter, they stopped arguing.
- The always-loaded budget rose from 2,500 to 2,650 words, deliberately, rather than cutting the new doctrine to fit. 2,500 was a target set while removing an unconditional file load; the mechanic is the 5,000-token compaction ceiling, which did not move and still sits over a thousand words away. This project also teaches that a number stripped of its reason is a rail wearing a digit, so holding one after its justification changed would have been the skill failing its own test.
Known limitations
- The claim that this release's doctrine reaches generated harnesses is not end-to-end verified. The doctrine is present in
SKILL.mdand the skill's own prose was compressed against it, both checked mechanically. Whether a generated harness comes out shorter-paragraphed with its reasons attached in a clause can only be answered by running the interview to completion, andAskUserQuestiondoes not exist in headless or subagent contexts, so no automated test can do it. The runbook and a prepared target repo ship indocs/plan/v3/; the run itself is outstanding. - Carried forward from 0.2.0: the interview cannot be end-to-end tested for the same reason, and installing the plugin from a local directory path copies gitignored files into the plugin cache (harmless; GitHub-source installs are unaffected).