Why: CONTEXT.md is an instructed every-session read at 33,799 bytes (~8,450
tokens), and CONTEXT.md:17 layered docs/VISION.md on top. After the AGENTS.md
trim, that left ~9,650 tokens of instructed reads sitting behind a file whose
own format contract — grill-with-docs/CONTEXT-FORMAT.md:43, "Keep definitions
tight. One sentence max." — it was not following. 22 glossary entries averaged
190 words; the top four were 55% of the file, and one ("Vale audit prefilter")
was 1,444 words of pre-commit forensics filed as a definition.
Implementation notes:
- CONTEXT.md rewritten to CONTEXT-FORMAT.md's prescribed template: ## Language
(five clusters, 22 terms with _Avoid_ aliases), ## Relationships,
## Example dialogue, ## Flagged ambiguities. 33,799 -> 9,762 bytes.
- Vale prefilter forensics moved to docs/spec/gates.md under nine subsections:
the two-copy style layout, vale-wrap.sh and the Vale 3.15.2
text.frontmatter.description limitation, the --config argv defect (E100),
glob scoping, the rule inventory, and 0-files-means-NOT-RUN.
- Instruction-file format and the bidirectional-reference principle moved to
docs/spec/architecture.md, the latter flagged as aspirational: no instruction
file carries a `when:` field, only 2 of 39 skills do, and the reference
scanner script it names does not exist.
- Added a per-plugin scope table to architecture.md so "which plugin owns this
skill" survives the trim, and corrected its claim that the content index
lives in providers/claude-code/CLAUDE.md — that file is now two import lines
and the index sits in core/AGENTS.md.
- "Repo and Gitea are the only source of truth" moved from CONTEXT.md's
Principles into AGENTS.md session rules; it was operative guidance in a
glossary. docs/VISION.md and LESSONS.md added to the on-demand list.
- The apm-consumed install entry (432 words) was deleted outright: all four
consequences are already carried by README.md, ADR-0018, gates.md and
AGENTS.md.
- ADR-0013, ADR-0015 and ADR-0017 each pointed at CONTEXT.md sections that
moved; amended with dated supersession notes rather than left dangling.
Impact: the every-session set drops from ~15,700 to ~4,140 tokens across both
passes (-74%). The deleted "lint plugin" entry was also stale on a safety
claim — it said lint-runner inherits Edit, but ADR-0016 restored
`disallowedTools: Edit, Write, NotebookEdit` and CONTEXT.md was never updated.
Refs: #99
9.9 KiB
Vale audit prefilter expands into a plugin-content harness, scoped to prose-pattern rules only
Issue #84 wired Vale as a deterministic prefilter for skill-audit/agent-audit, scoped to
exactly four pattern-matchable checks (imperative description opener, vague capability wording,
generic reference-pointer padding, Copilot's dead Use proactively phrasing), documented only in
CONTEXT.md's "Vale audit prefilter" section — never its own ADR — and explicitly excluding body
discipline, near-miss exclusion strength, and control calibration as non-goals. This ADR records a
deferred PR #85 review item to broaden that coverage, retroactively captures #84's own rationale
(since it was never recorded as a decision in its own right), and layers the expansion on top
without reversing or weakening the original four rules.
2026-08-17 amendment. The CONTEXT.md section named above no longer holds that documentation.
CONTEXT.md was cut back to a glossary and the prefilter's mechanics — the two-copy style layout,
vale-wrap.sh, the --config argv defect, the rule inventory, and the 0-files-means-NOT-RUN
fallback — moved to docs/spec/gates.md. Read that file, not CONTEXT.md, for the harness itself;
this ADR still owns the scope decision.
File scope stays the same. SKILL.md plus agent files (**/agents/*.md,
**/*.agent.md) only — matching the existing prefilter's globs. Skill-level
README.md files and plugin.json manifests are not added: README.md files are navigational, not
spec-governed content, and plugin.json is JSON, not prose Vale can meaningfully lint.
Rule categories are prose-pattern-matchable only. Structural, schema, and security concerns
stay out of this Vale-based harness because this repo already has dedicated tools for them:
skill-frontmatter (required frontmatter fields), validate-plugins/validate-marketplace
(claude plugin validate --strict, schema), and gitleaks/detect-private-key (secrets).
Duplicating those concerns as Vale rules would fight tools that already own them better.
Governance docs are excluded as a rule source. docs/research/governance_principles/CONTROLS.md
and governance.md were investigated and found to contribute nothing minable: CONTROLS.md is
org/CI-infrastructure controls (secret scanning, dependency/license scanning, agent permission
scoping, audit logging, human approval gates, periodic reviews) — none of it is a prose pattern
expressible as a Vale rule against SKILL.md/agent-file text, and what it does cover is either
already handled elsewhere (gitleaks) or genuinely out of scope for a plugin-content prose harness
(dependency/license scanning is a code-dependency concern, not skill authoring).
Spec-derived custom rules stay mostly as-is. Re-reading agentskills.io's
optimizing-descriptions.md and skill-authoring.md, plus claude-code-plugins/agent-definition.md
and github-copilot-plugins/agent-definition.md, found that the existing four Kyberforge rules
already cover the pattern-matchable surface those specs describe. The remaining spec guidance —
calibrating control vs. giving freedom, avoiding menus of options, coherent skill scope, moderate
detail level — is semantic judgment, already skill-audit's job via LLM review, not new lintable
rules. One confirmation surfaced: Claude Code's Use proactively phrasing is meaningful for .md
agent files (it triggers auto-invocation), unlike Copilot's .agent.md files where it's dead
phrasing — so KyberforgeCopilot/ProactivePhrase's existing .agent.md-only scope is correct and
must not be extended to .md files.
write-good/alex are trialed, not adopted wholesale. These built-in/third-party Vale
packages are tuned for general blog-style prose (passive voice, weasel words, wordy phrases) and
are expected to be noisy against this repo's terse, imperative instruction-file corpus. Only
individual rules proven low-noise against the existing corpus get cherry-picked into
styles/Kyberforge; the packages are never referenced wholesale in BasedOnStyles.
A new non-Vale check closes a real gap. skill-authoring.md states SKILL.md should stay
under 500 lines / 5,000 tokens — currently unenforced anywhere in this repo. This is a whole-file
length ceiling, not a text pattern, so it isn't a Vale rule — it becomes a new deterministic script
and pre-commit hook, sibling to the existing skill-frontmatter hook.
Rules land directly in styles/Kyberforge, enforcing immediately. No trial/report-only tier
is introduced (see Considered Options). "Enforcing immediately" holds only because every rule in
both styles is level: error: Vale's exit code keys on error-level alerts alone, so a
warning- or suggestion-level rule prints an alert and still exits 0, and pre-commit suppresses
output from hooks that pass — such a rule is invisible and blocks nothing. Every Vale alert is
therefore a FAIL, in the audit skills and in the blocking pre-commit hook alike, with no ignorable
tier; that matches every other gate in this repo (shellcheck, the test suite,
conventional-pre-commit). The implementation pass finalizes the cherry-picked
write-good/alex rules and any new spec-derived rule wording, runs the full set against the
existing SKILL.md/agent-file corpus, fixes any resulting violations across that corpus, and lands
the rule changes and the corpus fixes as one atomic commit — the same enforcement model as the
original four rules, never a partial or opt-in state.
Considered options
Phased rollout via a separate trial style + config (rejected). A styles/KyberforgeTrial/
directory plus a parallel .vale.trial.ini (mirroring the root config's globs but with
BasedOnStyles = Kyberforge, KyberforgeTrial) would let new rules be swept report-only via
lint-runner/vale-run before promotion into the enforcing styles/Kyberforge + root
.vale.ini. This was considered because BasedOnStyles = Kyberforge activates every rule file
under that directory automatically — there's no partial/opt-in application within a style, so a
rule dropped straight into styles/Kyberforge goes live in the blocking pre-commit hook
immediately. Rejected in favor of finalizing rules directly and fixing violations via subagent
before committing: simpler, no new trial-config machinery to build or maintain — at the cost of no
standing report-only tier for future candidate rules. Note that the first implementation shipped
graded severities (error/warning/suggestion) and thereby recreated the rejected option by
accident: the five non-error rules never affected an exit code and never surfaced output through
a passing pre-commit hook, so they were a report-only tier that reported to nobody. Flattening
every rule to level: error is what actually implements this decision.
Consequences
styles/Kyberforge/gained one new rule file, cherry-picked fromwrite-good/alexas low-noise against this repo's corpus:SentenceOpenerThereIs.yml(22 hits across 273 held-out markdown files; both in-corpus hits were clean rewrites, needing no suppression).- A second candidate,
VagueQualifier.yml, was cherry-picked and then dropped. Against the 41 skill/agent files it hit twice: one marginal real finding (prototype/SKILL.md, "very different" → "fundamentally different") and one false positive (caveman/SKILL.md, which quotesof courseas an example of filler — a mention, not a use) that no rewrite could clear, forcing the repo's only Vale suppression comments. Of its 15 held-out hits, 9 were indocs/research/examples/(out-of-scope upstream material) and the remaining 6 were the word "very" in two idioms in a single research doc, each already adjacent to the hard number carrying the fact. One marginal catch does not pay for a permanent suppression, so the rule is deleted and this ADR's "cherry-picked rules" is one rule, not two. - A new pre-commit hook,
skill-size-check(scripts/skill-size-check.sh), enforces the 500-line/5,000-tokenSKILL.mdceiling, sibling toskill-frontmatter. Both halves of that ceiling are blocking gates, not just the line count:MAX_LINES=500, andMAX_WORDS=2770as a word-count proxy for the 5,000-token limit (calibrated to the densest prose this repo measured, 1.81 tokens per word, so a worst-caseSKILL.mdat the ceiling still lands under 5,000 tokens —wc -wis not BPE tokenization). Either one exceeded fails the hook. Both are inclusive: a file at exactly 500 lines or exactly 2,770 words passes, and only one past a ceiling fails.skill-audit/scripts/validate.shenforces the same pair on the same inclusive terms, so the audit and the commit hook cannot disagree about whether a givenSKILL.mdis over size. styles/KyberforgeTrial/and.vale.trial.iniwere deliberately not created — noted here so a future reader doesn't wonder if a trial tier was forgotten.- The styles-portability question — whether
styles/and.vale.inishould move intoplugins/lint/so the prefilter also works for repos that installkyberforge@holocronas an external plugin, rather than living at this repo's root — was deliberately deferred, not fixed, in this pass. This repo-root placement remains intentional: this ADR's "File scope stays the same" framing is specific to Kyberforge's own authoring conventions in this repo, not a genericlint-plugin feature. Portability is a known limitation, tracked for a separate future session, not silently forgotten.
What this ADR's implementation pass did: synced and trialed write-good/alex against the
existing SKILL.md/agent-file corpus, cherry-picked the one low-noise rule above into
styles/Kyberforge, wrote scripts/skill-size-check.sh and its pre-commit hook, fixed the
resulting corpus violations, and landed the rule changes and corpus fixes as one atomic commit —
matching the enforcement model described above (no partial or opt-in state), with every rule at
level: error so that model is real rather than nominal.