Common SKILL.md mistakes and how to avoid them

The mistakes skillmd lint catches most often in SKILL.md files, why each one costs points, and the exact fix for each.

Contents

Most SKILL.md problems are not exotic. They are the same handful of mistakes repeated across thousands of files: a description that says nothing, a body that is three sentences long, a name that does not match its folder. skillmd lint catches all of them before you publish. This post walks through each one, the rule that flags it, and the fix.

Every skill starts at a quality score of 100. Errors subtract 30 points, warnings subtract 10, and the security scan can subtract more. None of these mistakes are fatal alone, but they stack, and a file with three or four of them looks worse than the sum of its parts.

Mistake 1: a missing or too-terse description

The description field is what an agent reads to decide whether your skill is relevant before it opens the body. Leave it out entirely and you hit SK003, an error: description is required, and the file fails lint outright.

The harder case is a description that exists but says nothing. Lint warns under SK010 when the description is shorter than about 20 characters. “Handles PDFs” clears the character count and still tells an agent almost nothing about when to use the skill.

Fix: write one sentence naming the input, the action, and the output. “Extracts text and tables from PDF files using pdfplumber, with page-range and layout options” tells an agent when to reach for it. Run skillmd rules SK010 to see the rule text while editing.

Mistake 2: no license declared

SK011 is a warning, so it is easy to forget. No license field in frontmatter costs 10 points for something that takes one line to fix.

license: MIT

Use a real SPDX identifier: MIT, Apache-2.0, ISC, whatever applies. Anyone installing the skill wants to know the terms without opening an issue to ask.

Mistake 3: a stub body with no headings

SK020 fires when the body is under roughly 200 characters, a placeholder someone meant to fill in later. SK021 fires when the body has no Markdown heading at all. Unstructured prose might contain real instructions, but an agent has nothing to anchor on.

Fix both by treating the body as the actual instructions, not a footnote:

## Usage

Run this skill when a user needs structured text or table data pulled out of a PDF instead of just raw text.

## Steps

1. Load the PDF with the extraction library.
2. Extract text page by page, or target a page range if specified.
3. For tables, return structured rows rather than flattened text.

A couple of headings and a real steps list clear both warnings.

Mistake 4: a name that’s too long or doesn’t match its directory

The name field has a hard cap: over 120 characters trips SK002, an error. Rare, but it happens when someone pastes a full sentence into name instead of a short identifier.

More common is SK040, a warning: the slugified form of name does not match the directory the skill lives in. If your folder is pdf-extract but name reads PDF Extraction Tool, lint flags the mismatch. It still works, since the runtime does not require the two to agree, but a mismatch usually means the skill was renamed once and left half-updated.

Fix: keep name short and matched to the directory name. If you rename one, rename the other.

Mistake 5: a description so long it rejects the whole file

This is the opposite failure from mistake 1. SK003 also covers the upper bound: over 1024 characters in description and the entire file is rejected, not trimmed to fit. This happens when someone pastes an entire usage guide into the frontmatter field instead of the body. The description is a one-sentence summary for relevance matching, not step-by-step instructions. If you are writing more than two or three sentences there, move the rest into the body under a heading.

Mistake 6: tripping the security scan with ordinary documentation

The security scan is a textual pattern match over the body, not a sandbox. It cannot tell the difference between a skill that actually shells out to a script and one that merely explains, in prose, what a shell command does.

Three flags matter for the score: reads_secrets costs 25 points, executes_scripts costs 15, and network_calls costs 8. Writing “pass your API key as an environment variable,” or including a fenced shell block with curl in it, can trigger these flags even when the skill never runs anything itself.

If your score is lower than expected, check the body for words like “token,” “secret,” or “API key,” and for shell, Python, or JS code fences. Keep real examples if the skill genuinely does that work, but for purely explanatory text, reword around the trigger words or describe the shape of the call instead of writing it as a literal command.

Mistake 7: frontmatter that doesn’t start at byte zero

This has no rule ID of its own, since it is a parse failure rather than a lint warning, but it is common enough to call out. The frontmatter block must open with --- as the very first bytes of the file. A leading blank line or a byte order mark from an editor defaulting to UTF-8-with-BOM breaks parsing before lint reaches the numbered rules.

If skillmd lint reports a parse error on a file that looks fine, check the first line for invisible characters. Re-saving as plain UTF-8 without a BOM usually clears it.

Run lint before you publish

All of this is checkable locally before a skill reaches the registry:

skillmd lint my-skill/SKILL.md

If a rule ID in the output is unfamiliar, skillmd rules SK010 (or any other ID) prints that rule’s description so you are not guessing at what triggered it.

The scoring is simple enough to hold in your head: start at 100, subtract 30 per error, 10 per warning, and up to 25 more for security flags. A file with a missing license and a mismatched name lands at 80. A file with a missing description error and a stub body warning lands at 60. None of these are hard to fix once you know which rule is complaining, which is the entire point of running lint before you publish instead of after.