Learning how to validate a SKILL.md comes down to one question: does the file parse and load? It is valid when the file opens with --- YAML frontmatter, that YAML is well-formed, and it carries a name (max 64 characters, lowercase letters, numbers, and hyphens) plus a description (max 1024 characters) that says what the skill does and when to use it. That is the whole bar. Everything past it is a different question about whether the skill actually fires and does its job, which this piece does not cover. Get the file well-formed first, then read the not-working post for the behavior side.
I once watched a skill vanish from a session because of a single stray tab in the frontmatter. No error, no warning. It just was not there, and I spent twenty minutes blaming everything except the one character that broke it. Validation is mostly about catching the five or six small things that make the loader skip your file in silence.
How to validate a SKILL.md: the must-pass checks
These are the rules the Agent Skills specification actually enforces. Break any one of them and the file is malformed. Honor all of them and the loader will accept it.
Frontmatter comes first, and it has to be real YAML. The very first line is ---, a closing --- ends the block, and what sits between them parses cleanly. Tabs break YAML. So do unquoted colons inside a value. A frontmatter that fails to parse is a skill that does not load, full stop.
Then the two required fields: name and description. The spec is strict about name. It must run 1 to 64 characters, lowercase letters and digits and hyphens only, no leading or trailing hyphen, no consecutive hyphens, and it has to match the parent directory name. So pdf-processing is fine. PDF-Processing is not. Neither is --pdf, and neither is a folder called pdf-tools holding a name: pdf-processing. That last one trips people up because the file looks perfect in isolation.
The description must be 1 to 1024 characters and non-empty. It is also the only thing the agent reads at startup to decide whether your skill is relevant, which makes it the most important line in the file. It has to name both the job and the trigger. "Helps with PDFs" passes the character check and fails at the job it exists to do. "Extracts text and tables from PDF files and fills forms. Use when the user mentions PDFs, forms, or document extraction" gives the model real words to match against.
Here is something the spec limit will not tell you. Claude Code truncates the combined description plus when_to_use text at 1,536 characters in the skill listing, per the Claude Code skills docs. A spec-valid 1024-character description can still lose its tail in some clients if you pad it out. Front-load the use case and you sidestep the whole problem.
The real ways to check it
There is a genuine command-line validator, and it does not come from Anthropic. The Agent Skills reference library, skills-ref, ships a validate subcommand documented in the specification:
skills-ref validate ./my-skill
It checks that the frontmatter is valid and follows the naming conventions. You install it from the agentskills repo into a virtual environment with pip install -e . or uv sync. This is the closest thing to an official standalone Claude skill linter that exists today, and it is the one I wire into CI so a broken skill cannot land in the first place.
Inside Claude Code, the load is the test. Ask "What skills are available?" and read the list it gives back. Your skill is there with its description intact? The file parsed and loaded. Your skill is missing? The frontmatter probably failed to parse, or the directory name does not match name. The docs troubleshooting section calls out this exact check, and I reach for it more than the CLI because it tells me what the agent itself sees.
Claude Code also has /doctor, which catches a failure mode the spec validator never will: description-budget overflow. Pile up enough skills and their descriptions start competing for a character budget that scales with the model's context window, and the ones you use least get dropped first. /doctor tells you whether the budget is overflowing and which skills got squeezed out. A skill can be flawless and still go dark because a dozen noisier ones crowded it off the list. That one surprised me the first time I hit it.
If you build with Anthropic's own skill-creator, packaging is a soft gate, nothing more. Its scripts/package_skill.py bundles the skill into a distributable .skill file, and a clean package is a decent signal that the structure holds together. But the docs never promise it lints every spec rule, so do not let a successful package stand in for the skills-ref check. Package and validate are two different jobs.
A manual checklist when you have no tooling
Sometimes you are editing a SKILL.md over SSH on a box with nothing installed. Run these by eye.
- First line is exactly
---, and there is a matching closing---. - No tabs anywhere in the frontmatter. Spaces only.
nameis lowercase, hyphen-separated, 64 characters or fewer, and equals the folder name.descriptionis present, under 1024 characters, and states what the skill does plus when to trigger it.- Any value containing a colon or a
#is quoted. - The body is non-empty and reads as instructions, not prose about instructions.
That covers the parse-and-load failures I see most often. Run it twice if the file matters.
None of it confirms the skill is any good, though.
"Valid" and "works" are not the same word
A valid skill loads. A working skill loads, triggers on the right request, and produces the output you wanted. Those two come apart constantly, and watching it happen is what taught me to keep them separate in my head. The most common version goes like this: the file is flawless, skills-ref is happy, the skill shows up in the listing, and Claude still never picks it because the description lacks the words a real user would type. That is a triggering problem. No linter will ever flag it for you.
So validate first, because a malformed skill can never work no matter how good the idea is. Then go debug the behavior. The not-working guide walks through trigger phrasing, model invocation settings, and the rest of it. And if you want a clean starting point that is well-formed by construction, the SKILL.md template hands you a frontmatter block that already passes every check above.
Prefer to skip the YAML entirely? Knack runs a short interview and writes the SKILL.md folder for you in the Anthropic format, valid frontmatter included, so the only thing left to debug is whether it triggers.