Frontmatter validity

Check S5 · execution surface family · severity HIGH · automatic · one of the 15 skill and plugin checks

The question this check asks: does this skill declare what it is? The Agent Skills specification makes a skill a directory with a SKILL.md whose frontmatter carries a name and a description; the installer keys on the name and the agent decides from the description whether to load the skill at all. A directory with no SKILL.md, a frontmatter block that does not parse, a name that is not the directory's, or no description, is a skill that has declared nothing — and an installer that copes with that is an installer that will copy whatever is there.

Why it matters

The specification, published at agentskills.io as an open standard originally developed by Anthropic, is short on this point. name is required, at most 64 characters, made of lowercase letters, digits and hyphens, and must match the parent directory's name. description is required, at most 1,024 characters, and non-empty. The specification ships a validator, skills-ref validate ./my-skill, for exactly these rules. A skill that fails them is not malicious for failing them; but a name that is not the directory's is a skill that will be installed under one label and invoked under another, and a missing description is an agent choosing a tool it has not been told the purpose of. The ClawHavoc listings of February 2026 were delivered, by Antiy CERT's account, as a zip of JSON and a SKILL.md with the download link inside the documentation; the frontmatter was not the attack, and this check does not pretend it was. It is the check that says whether the document the other checks read is the document the installer will act on. The malicious skills page has the record and the measurement.

How RepoGates scores it

Every skill directory discovered in the tree is expected to carry a SKILL.md, and the first 64 KB of each is read — SKILL.md files first, before anything else this tier reads. The block between the opening --- lines is parsed with PyYAML's plain loader in the application layer, the one that builds data and never a Python object. Five findings follow, in the order they are decided. skill-no-skillmd:<dir> is HIGH and 10 points: a skill directory with no SKILL.md, or a repository key where a skill was expected and none was found — “no SKILL.md where a skill was expected — nothing declares what this installs”. skill-frontmatter:unparsed is MEDIUM and 4 points when the block does not parse or is not a mapping, and a note when the document is nested below another skill's directory. skill-frontmatter:name-mismatch is MEDIUM and 4 points when the name is not the directory's — “name 'X' is not the directory 'Y'” — and a note when one is the other plus a hyphenated prefix, vercel-react-best-practices in a directory called react-best-practices. skill-frontmatter:name-shape is MEDIUM and 4 points when the name is empty or not ^[a-z0-9-]{1,64}$; skill-frontmatter:description-missing is MEDIUM and 4 points“no description — the agent has nothing to decide from”; and skill-frontmatter:description-long, over 1,024 characters, is a note at 0 points, because the installer copes. Under the default personal profile the HIGH and the MEDIUMs are warnings — a REVIEW with the file and both names printed — and the notes allow; nothing on this check blocks. The rows sit in the install dimension.

Measured on 20 September 2026 through the same code as /v1/skill/score, the check fired on 6 of the 189 skills.sh keys, 11 of the 310 official-marketplace plugins, 5 of the first 100 community plugins and 3 of the malicious set. The six on skills.sh are one repository, leonxlnx/taste-skill, and its five listings: five directories named *-skill whose frontmatter names are not — industrial-brutalist-ui in brutalist-skill, image-to-code in image-to-code-skill, and three more of the same habit. The eleven official rows: empty names on logrocket, vanta, vanta-mcp-plugin and windsor-ai, the last also with no description; a colon in pinecone:assistant and a slash in zoom-plugin's contact-center/android; a plural, an infix and a rewording on amplitude, hookify and mlflow (analyze-experiments beside analyze-experiment); a 00- ordering prefix on planetscale's directory; and pixeltable in a directory called pixeltable-skill. The five community rows: attacca and 0x, a top-level SKILL.md with no frontmatter at all; deeplake-hivemind and hivemind, a harnesses/openclaw/skills/SKILL.md compared to the container skills; and an empty name on agenticmail. The three malicious rows are Snyk's snyk-labs/toxicskills-goof (two mediums, beside the block it earns on S8), the ToxicSkills operator's aztr0nutzs/NET_NiNjA.v1.2 (a mismatch and an unparsed block, beside its archives), and oduffy-delphi/deep-research-claude — the empty repository John Stawinski registered as proof in June 2026, which is “no SKILL.md where a skill was expected” at REVIEW 90. No listing on the three top lists was blocked by this check, and none can be.

False positives we know about

Naming habits. The measurement record grades two of its own findings as misreads and says so: a directory named with a -skill or -skills suffix, or a leading NN- ordering prefix, is the same habit as the vendor prefix that is already a note — pixeltable, leonxlnx's five, planetscale — and should be graded the same way; and a SKILL.md sitting directly inside a directory named skills, found by the discovery fallback, is a container's root skill and should be compared to its parent, not to the word skills — the two hivemind rows. Each is a REVIEW, never a BLOCK, and the proposed rule is written beside the evidence. The page will change when the rule does.

A vendor's empty name. Four official plugins ship a SKILL.md whose name: is blank; the installer falls back to the directory and the plugin works. The finding is real by the specification's letter and stays MEDIUM, because a skill invoked under a name it never declared is the thing the rule exists to notice.

What this check does not cover

What the text says. A SKILL.md whose frontmatter is perfect can instruct the agent to read ~/.aws/credentials; that is S9's question, and the scripts beside it are S10's. The other frontmatter fields. allowed-tools is S6, compatibility and metadata are S7, and the fields Claude Code adds beyond the specification — when_to_use, argument-hint and the rest — are not validated here. A SKILL.md this tier did not read. A repository with more skills than fit in twelve reads is a partial scan, stated on the report with the count of files unread, and the frontmatter of an unread file is neither a finding nor a pass. ClawHub (@owner/slug) is parsed and routed but not assessed on this tier: the Hub's API returns the whole SKILL.md text in its skill.description field, so the frontmatter is readable there and this check will read it when the ClawHub fetch ships; until then a ClawHub key answers “not assessed” as a whole, never a pass.

Scope, the same on every page of this roster: RepoGates does not see git clone, package managers or curl — outside Claude Code with the RepoGates plugin, whose hook refuses a clone or install that names a blocked repository on the command line, before it runs. The hook sees Bash tool calls in that one client and nothing else: npx skills add owner/repo and claude plugin install name@marketplace are shell lines it judges; /plugin install is a slash command the hook never sees; a skill copied by hand into ~/.claude/skills is never seen at all. This tier reads the listing record, the tree once, and at most twelve files of 64 KB each — SKILL.md files first, then a plugin's agents and commands, then the scripts beside each skill; more than fits is a partial scan, stated, and never a pass on what was not read. The deep scan reads the whole package. A PASS means nothing matched on what was read, never that the skill was run.

Check it yourself

The specification's own validator applies the same rules to a skill directory on disk:

skills-ref validate ./my-skill
head -n 12 ./my-skill/SKILL.md

The name: line should be the directory's name, in lowercase letters, digits and hyphens; the description: line should tell you, in a sentence, when an agent would use this. If the first line of the file is not ---, there is no frontmatter, and whatever installs the skill is guessing.

Questions

Why is a name that does not match its directory only a medium finding? Because on real listings it is almost always a habit, not a disguise. The specification says the name must match the parent directory, and installers key on it; but the measurement found vendors prefixing the name with their own (vercel-react-best-practices in a directory called react-best-practices), pluralising it (analyze-experiments beside analyze-experiment), or suffixing the directory with -skill. A prefixed variant is now a note at no points; the rest stay medium, which under the default profile is a warning with the two names printed, never a block. Three of those mediums — a -skill suffix on the directory and a 00- ordering prefix — are ones the record already calls its own misreads and proposes to make notes too.

What happens when the frontmatter does not parse? The finding says so, at medium, and the other frontmatter checks on that file do not run — there is no name or description to read. The block between the first two --- lines is parsed with PyYAML's plain loader, which builds data and never a Python object, in the application layer; a block that is not a mapping, or not YAML, or absent altogether, is unparsed. The one downgrade: a SKILL.md nested below another skill's directory — a sub-document the outer skill owns — is a note rather than a finding. In the measurement two community plugins carried the medium, attacca and 0x, each a top-level SKILL.md with no frontmatter at all, and both are real.

Which of the measured findings does RepoGates consider its own misreads? Two shapes, each a review on the report and never a block. The first: a directory whose name is the skill's name plus a -skill or -skills suffix, or plus a leading numbered ordering prefix — pixeltable's pixeltable-skill, leonxlnx's five directories, planetscale's numbered one. The rule that already grades a vendor prefix as a note is prefix-only, and the same habit on the other end of the name should be graded the same way. The second: a SKILL.md sitting directly inside a directory named skills, found by the discovery fallback and then compared to the container's name — deeplake-hivemind and hivemind in the community set. Both are written down in the measurement record with the proposed rule beside them; the page will change when the rule does.

Related checks

S6 Declared tool surface — the allowed-tools field of the same frontmatter · S7 Declared requirements — the compatibility and metadata fields · S11 Size — the specification's 500-line guidance on the same file · S1 Source repository — the repository the SKILL.md was read from, and its own verdict.

Add RepoGates to Chrome Pricing

Numbers on this page: the 20 September 2026 measurement of 189 skills.sh keys, all 310 official-marketplace plugins, the first 100 community-marketplace plugins and the named incidents, run through the same code as /v1/skill/score, with every REVIEW read by hand; the Agent Skills specification at agentskills.io as read the same day; the incident record behind the malicious skills page (Antiy CERT, 6 February 2026; Snyk, 5 February 2026; John Stawinski IV, 18 June 2026); weights from the product's scoring table.