A Claude Skill is a folder containing a SKILL.md file plus optional reference documents and scripts that teaches Claude how to carry out one specific process well. Building one takes six steps: scope the task, write the frontmatter, write the instructions body, add any supporting files, install the folder in the right place for your surface, and test that Claude actually loads it when you ask for that task. Below is a working walkthrough of all six, using a real example skill that drafts release notes from a git log.
Step 1: Decide what the skill should own
A Skill earns its place when you catch yourself re-explaining the same process to Claude across sessions. For this walkthrough, the process is: read the commits since the last tag, group them by type (feature, fix, chore), and produce a changelog section in the project’s existing format. That is narrow enough to describe completely in one file, and specific enough that Claude cannot guess it from the task name alone.
Keep the scope to one job. A Skill that tries to cover “all git tasks” forces Claude to re-read a long document for a task that needed three lines of instruction. If you notice the body growing past a screen or two, that is usually a sign the Skill is actually two Skills.
Step 2: Write the SKILL.md frontmatter
Every Skill directory needs a SKILL.md file at its root, starting with YAML frontmatter. Anthropic’s Skills documentation specifies exactly two required fields, each with hard limits Claude enforces when it loads the file:
| Field | Limit | What it must contain |
|---|---|---|
name | 64 characters max | Lowercase letters, numbers, and hyphens only. Cannot contain “claude” or “anthropic”. No XML tags. |
description | 1,024 characters max | Must state both what the Skill does and when Claude should use it. No XML tags. |
The description field is the one Claude actually reads to decide whether your Skill applies. At startup, Claude loads only the name and description of every available Skill into its system prompt — roughly 100 tokens each — and matches your request against those descriptions. A vague description (“helps with git stuff”) will lose that match against a more specific one. Write it the way you’d answer “when should I use this”:
For the changelog example:
--- name: changelog-from-commits description: Generate a changelog section from git commits since the last tag, grouped by type and formatted to match this repo's CHANGELOG.md. Use when the user asks to draft release notes, a changelog entry, or "what changed since the last release." ---
Notice the description does two jobs in one sentence each: it says what the Skill produces, and it lists the phrasings that should trigger it. Both matter — this is the same reason a well-written system prompt states the behavior you want rather than hinting at it.
Step 3: Write the instructions body
Everything below the closing --- is the Skill’s instructions. This is what Claude reads in full once the Skill is triggered, so it should read like a runbook, not a product description. For the changelog Skill, the body walks through the actual steps:
- Run
git log <last-tag>..HEAD --onelineto get the raw commit list. - Sort commits into Features, Fixes, and Chores using the Conventional Commits prefix (
feat:,fix:,chore:); anything unprefixed goes under Chores. - Drop merge commits and anything matching
^Merge branch. - Read the top of
CHANGELOG.mdto copy the existing heading format exactly. - Write the new section above the previous entry, never editing past entries.
Anthropic’s documentation calls this the token budget for “Level 2” content: the SKILL.md body should stay under roughly 5,000 tokens. That is generous for most single-purpose Skills, but it is a real ceiling — if your instructions need more than that, move the detail into a separate reference file instead of inflating the body (Step 4). Keeping the body short also keeps it debuggable: a five-step runbook is easy to check against what Claude actually did; a page of prose is not.
Step 4: Add reference files and scripts, and understand why order matters
A Skill directory can hold more than SKILL.md. Anthropic’s documentation describes this as progressive disclosure, and the loading behavior at each level is specific enough that it changes how you should split content:
| Level | Loaded | Cost |
|---|---|---|
| 1 – name + description | Always, for every Skill, at startup | ~100 tokens each |
| 2 – SKILL.md body | Only once this Skill is triggered | Under ~5,000 tokens |
| 3+ – reference files, scripts | Only if the body tells Claude to read or run them | Nothing until accessed |
For the changelog Skill, a FORMAT.md file holding three full worked examples of past changelog sections costs nothing unless Claude’s task actually needs to see them — the SKILL.md body just needs a line telling Claude to open it: “See FORMAT.md for three examples of correctly formatted sections before writing a new one.” A scripts/group_commits.py helper is the same story: Claude runs it with bash and only the script’s output, not its source, enters context. This is the detail most new Skill authors miss — they write one long SKILL.md instead of splitting detail into files that only load on demand, which quietly burns the context budget on every single task the Skill handles, not just the ones that need the detail.
Step 5: Put the folder where your surface looks for it
Where you save the Skill folder depends entirely on where you want to use it, and the three surfaces don’t share Skills with each other:
- Claude Code: drop the folder in
~/.claude/skills/for a personal Skill available in every project, or.claude/skills/inside a repo for a project-specific one. No upload step — it’s filesystem-based, and Claude Code can also install Skills bundled as plugins. - claude.ai: zip the folder and upload it under Settings > Features. This requires a Pro, Max, Team, or Enterprise plan with code execution turned on, and the Skill is private to your account, not shared with your org.
- Claude API: upload the folder through the Skills API (
/v1/skills) with the code execution tool enabled, then reference it byskill_idin thecontainerparameter. Custom Skills uploaded this way are shared workspace-wide, but the API container has no network access and cannot install packages at runtime — so a script that callspip installinside the Skill will fail silently on this surface even though it works fine in Claude Code.
A Skill built for Claude Code and a Skill uploaded to claude.ai are two separate objects, even with identical SKILL.md content. If you maintain the same process across surfaces, you’re maintaining two copies by hand — there is currently no sync between them.
Step 6: Test that it actually loads — don’t assume the description is enough
Open a fresh conversation and ask for the task in the plainest possible words a user would type — not the exact phrase from your description. For the changelog Skill, try “what’s changed since v1.4?” rather than “draft release notes.” If Claude answers from general knowledge instead of running your steps, the description didn’t match; tighten the trigger phrases rather than the instructions. Then check the output against what the Skill actually specifies, line by line, not just “does this look like a changelog” — it’s easy for a Skill to produce a plausible-looking result while silently skipping a step, such as including a merge commit the instructions told it to drop.
Five mistakes that keep a Skill from loading, and how to fix each one
These are the failures that show up most often once you move past the first working Skill, each traceable to a specific rule in the frontmatter spec or the loading model above.
- The description reads like marketing copy, not a trigger. “Supercharges your release process” tells Claude nothing to match against. Fix: rewrite it as “what it does” plus “when to use it,” using words the user would actually type.
- The name contains “claude” or “anthropic.” The frontmatter spec rejects both reserved words outright, and the Skill won’t load at all. Fix: rename to something scoped to the task, like
changelog-from-commits, notclaude-changelog-helper. - One Skill tries to cover too many related tasks. Symptoms: the body creeps past the ~5k token guidance, and Claude sometimes applies half the instructions to a task that only needed a third of them. Fix: split it into two Skills with two descriptions, even if they share a reference file.
- A script assumes network access or a runtime
pip install. Works in Claude Code, fails silently in the API’s code execution container, which has neither. Fix: vendor any dependency inside the Skill folder, or pre-install it, rather than fetching it at run time. - Reference material got pasted into SKILL.md instead of a separate file. This is the quiet one: nothing errors, but every invocation now pays the full token cost even when the task never touches that material. Fix: move worked examples, long reference tables, and API specs into their own
.mdfiles and link to them by name from the body.
None of these show up as an error message — Skills fail quietly, by not triggering or by triggering and doing the wrong amount of work. The fastest way to catch them is the same one described in Step 6: test with the phrasing an actual user would use, not the phrasing you wrote the description in.
How this differs from writing a system prompt or wiring up an MCP server
A Skill is not a replacement for either. A system prompt sets standing behavior for an entire conversation; a Skill loads only when one specific task matches, which is why it can afford to be far more detailed without costing tokens on unrelated turns. An MCP server, by contrast, gives Claude a connection to an external tool or data source — Anthropic’s own framing is that MCP gives Claude the aisles of the store, while a Skill is the employee who knows what to buy and how to use it once there. If your changelog Skill needed to post the result to a ticketing system rather than just write a file, that posting step is what an MCP server would handle; the Skill would still own the sequencing and formatting logic around it.
If the Skill runs inside Claude Code and its instructions call a script, remember that script executes with the same filesystem and network permissions as everything else Claude Code runs — the same trust boundary covered in our walkthrough of blocking dangerous bash commands with a PreToolUse hook. A Skill you didn’t write yourself should be read in full before you drop it into ~/.claude/skills/, for the same reason you’d audit any other code with shell access: a malicious or sloppy Skill can direct Claude to misuse a tool it already has permission for, which is a different failure mode than the prompt-level attacks covered in our guide to prompt injection, but worth the same scrutiny before you trust it with real repositories.
One more cross-surface detail worth checking before you build a Skill meant for the API: confirm which models you’re targeting still support the container tooling the Skill needs, since Anthropic retires older models on its own 60-day deprecation notice schedule, and a Skill tested against one model version is not guaranteed to behave identically on its replacement.



