SKILL.md Scaffolder

Build a Claude Code skill file with correct frontmatter — and a description that actually gets it triggered.

Verified against Claude Code v2.1.204 · July 2026

Lowercase letters, numbers, and hyphens; 64 characters max. We slugify as you type. It should match the skill's folder name.

Third person. Say what the skill does and when to use it, with words users actually type. This is the only text Claude sees before deciding to load the skill. 0/1024

Allowed tools (optional — leave all unchecked to inherit every tool)
Body sections
.claude/skills/my-skill/SKILL.md

The SKILL.md format, explained

A skill is how you teach Claude Code a repeatable capability: a folder containing a SKILL.md file — YAML frontmatter on top, markdown instructions below — plus any scripts or reference files the job needs. Claude discovers your skills automatically and loads one only when a request matches its description. No plugin API, no build step: a skill is a text file in the right place.

Frontmatter fields

The frontmatter is the YAML block between --- markers at the top of the file. Two fields are required; everything else is optional.

FieldRequiredRulesWhat it does
name Yes Lowercase letters, numbers, and hyphens only; 64 characters max. Match the skill's folder name. The skill's identifier and listing label. In Claude Code the slash command comes from the skill's folder name (e.g. /pdf-form-filler) — which is why the two should match. Cannot contain the words claude or anthropic.
description Yes 1,024 characters max. Third person. State what the skill does and when to use it. The trigger. This is the only part of your skill that is always in Claude's context — it alone decides whether the skill loads. See below.
allowed-tools No Comma-separated tool names, e.g. Read, Grep, Bash(python:*). In Claude Code, grants the listed tools without a per-use permission prompt while the skill is active — it does not remove other tools. Omit it to keep your normal permission behavior. To block a tool a skill should never call, use disallowed-tools.

Claude Code supports a few more optional fields — disable-model-invocation, user-invocable, disallowed-tools, and when_to_use — but the three above cover almost every skill, so keep frontmatter minimal. If a skill silently fails to load, the most common causes are a name/folder mismatch, invalid YAML (a stray colon in an unquoted description is the classic), or a missing required field.

The description is the trigger — write it like one

Here is the mechanic that makes or breaks a skill: at startup, Claude Code reads only the name and description of every installed skill into context. The body of your SKILL.md is invisible until Claude decides — from the description alone — that the skill fits the current request. A brilliant skill with a vague description never runs.

Three rules that follow directly from that:

  1. Say what it does and when to use it. "Extracts tables from PDFs" describes a capability; "…Use when the user wants to pull tables, data, or figures out of a PDF file" describes a match. Include both halves.
  2. Use the words users actually type. Claude is matching your description against a real request. If people say "fill out this form," put fill out and form in the description — not just "automates document field population."
  3. Write in third person. The description is read by the model, about the skill — "Generates conventional-commit messages…" not "I generate…" or "Use me to…".

Too vague to trigger

description: Helps with commits.

Triggers reliably

description: Writes conventional-commit messages from the staged
  diff. Use when the user asks to commit, wants a commit message,
  or mentions conventional commits or commitlint.

Directory layout

Skills live in a skills directory, one folder per skill, with SKILL.md inside:

~/.claude/skills/          # personal — every project on this machine
  pdf-form-filler/
    SKILL.md               # required: frontmatter + instructions
    scripts/
      fill.py              # run, not rewritten — Claude executes bundled scripts
    references/
      field-mapping.md     # loaded only when the task needs it

.claude/skills/            # project — committed, shared with your team
  deploy-checklist/
    SKILL.md

Personal skills (~/.claude/skills/) follow you across projects; project skills (.claude/skills/, committed to the repo) ship to everyone who clones it. Plugins can also carry skills. The folder name and the frontmatter name should match.

Progressive disclosure: why skills stay cheap

Skills load in three levels, and each level costs context only when it's needed:

  1. Metadata, always. Every skill's name + description sit in context permanently — a few dozen tokens each. This is the price of being discoverable, and it's why you can install many skills without bloating every session.
  2. The SKILL.md body, on trigger. When a request matches the description, Claude reads the full file. Keep it under roughly 500 lines — long enough to be complete, short enough to load fast.
  3. Bundled files, on demand. Reference docs, templates, and scripts in the skill folder are read or executed only when the task actually calls for them. This is where the depth goes: a lean SKILL.md that points to references/schema.md beats a 2,000-line SKILL.md every time.

Design for the levels: the description earns the load, the body gives the procedure, the bundled files carry the detail.

A complete example

A realistic, working skill — short body, precise trigger, one bundled reference:

---
name: changelog-writer
description: Drafts a CHANGELOG entry from merged commits since the
  last release tag. Use when the user asks to update the changelog,
  write release notes, or prepare a release.
allowed-tools: Read, Grep, Bash(git log:*), Bash(git tag:*), Edit
---

# Changelog Writer

## Instructions

1. Find the latest release tag: `git tag --sort=-v:refname | head -1`.
2. List merged commits since that tag: `git log <tag>..HEAD --oneline --no-merges`.
3. Group commits under **Added / Changed / Fixed** (see
   `references/keepachangelog.md` for category rules).
4. Draft the entry at the top of `CHANGELOG.md` under an `[Unreleased]`
   heading. Do not invent entries for commits you cannot see.
5. Show the draft and wait for approval before editing the file.

## Common mistakes

- Do not bump the version number — that belongs to the release script.
- Skip dependency-bot commits unless they fix a security issue.

Frequently asked questions

How is a skill different from CLAUDE.md?
CLAUDE.md is always-on context — conventions Claude should follow in every session. A skill is on-demand capability — a procedure loaded only when it's relevant. If you find yourself pasting the same multi-step instructions into CLAUDE.md, that's a skill. (Building the always-on file instead? Use our CLAUDE.md Generator.)
How is a skill different from a slash command?
They converge: a skill can be invoked explicitly as /skill-name, and Claude can also trigger it automatically from the description. A skill is a slash command that knows when to volunteer.
Skills or MCP?
MCP servers connect Claude to external systems — APIs, databases, browsers. Skills teach Claude procedures using the tools it already has. If the capability is "talk to service X," it's MCP (see our MCP Config Generator); if it's "do task Y the right way," it's a skill.
Where do skills work?
Claude Code (personal, project, and plugin skills), the Claude apps via capabilities, and the Claude API / Agent SDK. The same SKILL.md format travels across all of them.
My skill never triggers. What do I check?
In order: is the folder in the right place, does the folder name match name, is the YAML valid (quote any description containing a colon), and — the usual culprit — does the description actually contain the words you're typing when you expect it to fire? Rewrite the description with the trigger rules, restart the session, and try the request again.