Files
zernie__vigiles/docs/rules/frontmatter-valid.md
zernie a87d0cf2bc fix(audit,testing): three dogfood defects — a heading, a salvage, and a check count (#130)
A bundled script named in a markdown heading was invisible to skill-resource-resolves, because the use-directive gate reads prose and a heading is not prose. An ATX heading now counts; the widening stops there, measured at 1 finding before and after over 28 SKILL.md files.

Malformed frontmatter was regex-salvaged into the tool contract the lethal-trifecta and Safety ring read, so a unit whose allowed-tools a strict loader rejects scored as the narrow contract its author meant. A salvage may now only make the verdict worse, never better — the vendored corpus forced that nuance by going red when the first pass refused salvages outright.

vigiles test reported a clean exit with zero assertions as a pass. vigiles/testing now counts checks per tier and the runner reports a fourth, non-fatal state. Silence stays a pass: undefined means nobody counted, 0 means counted and found nothing.

No new CLI verb or flag. Every mechanism is deterministic. Direction is strictly more conservative: nothing can now pass that could not before.
2026-08-09 02:25:39 +05:00

3.3 KiB
Raw Permalink Blame History

frontmatter-valid

Flag a skill/agent whose --- frontmatter block exists but isn't valid YAML — so its fields may not parse as the author intended. Same detector vigiles scan uses (the malformed flag from src/core/frontmatter-read.ts, a real js-yaml parse).

Honest caveat — why this is warn, not error

A spec-compliant YAML parser (js-yaml) is stricter than some lenient frontmatter loaders. The most common trip is a one-line description: that contains a : colon, a quote, or an embedded <example> block:

description: Use this agent when: <example>user: "..." assistant: "..."</example>

That is invalid YAML (a plain scalar can't contain : ), so it's flagged — but depending on the harness's loader it may still load (possibly with a literal \n instead of a newline). Calibration against the mid-2026 sweep: 7% of frontmatter blocks were flagged, concentrated in 2 repos (ananddtyagi, MadAppGang) and 0 across the other 11 marketplaces — the signal correlates with prose stuffed into frontmatter, but vigiles has not empirically confirmed every flagged file fails to load.

So this ships warn by default (a nudge, exit 0) and scan surfaces it as an informational ℹ note, not a structural defect (no leaderboard penalty). Verify against your harness before setting "error". The unambiguous cases (an unclosed [a, b, c, a tab indent, a duplicate key) are real breakage worth fixing regardless.

What it flags

allowed-tools: [read, write          # ✗ unclosed flow array — invalid YAML
description: a value with: a colon    # ⚠ invalid plain scalar (may still load)

The file's other fields are still salvaged by the reader, so the rest of scan/lint keeps working on a malformed file.

Except the tool contract, which is not salvaged for SCORING. A salvaged allowed-tools: / tools: is a regex guess at a block a strict loader rejects, so vigiles audit treats a malformed unit's contract as inherits-all rather than grading the guess — see lethal-trifecta. The live PreToolUse rail still uses the salvage (something to enforce beats nothing); only the score refuses it. So a broken block can cost a grade even when the fields "look fine", and fixing the YAML restores both.

Configuration

{ "rules": { "frontmatter-valid": "warn" } }

Severity

Value Behavior
"error" vigiles lint exits non-zero (2) — only set this once verified
"warn" (default) Prints a warning, exits 0
false Skip the check

Scope

skills/*/SKILL.md + agents/*.md (and .claude/...). The block must be at the file start (after an optional BOM / a leading vigiles integrity comment) — a --- horizontal rule in the body is never mistaken for frontmatter.

See also

  • subagent-frontmatter — required fields + valid model/color (a parsed frontmatter that's missing/typo'd a field, vs this rule's unparseable block).