Reference · 7 min read
SKILL.md Format: Every Frontmatter Field Explained
A complete SKILL.md reference: required fields, open-standard keys, Claude Code extras like context: fork and paths, arguments, variables, and examples.
A SKILL.md file has two parts: YAML frontmatter between --- lines, and a Markdown body with the instructions. Only two frontmatter fields are required, name and description. The open standard at agentskills.io adds four optional fields (license, compatibility, metadata, allowed-tools), and Claude Code supports a further set of its own, such as disable-model-invocation, context, paths, and model, which control who can invoke the skill and how it runs.
This page documents every field, the body syntax for arguments and variables, and the limits that matter in practice.
What is the minimal valid SKILL.md?
---
name: changelog-entry
description: Writes a CHANGELOG.md entry in Keep a Changelog format from recent commits. Use when the user asks to update the changelog, write release notes, or prepare a version bump.
---
Read commits since the last tag with `git log $(git describe --tags --abbrev=0)..HEAD --oneline`.
Group them under Added, Changed, Fixed, and Removed. Skip merge commits and chores.
Saved at .claude/skills/changelog-entry/SKILL.md, this is a working skill. Everything below is optional refinement.
Required fields
name
| Rule | Detail |
|---|---|
| Length | 1 to 64 characters |
| Characters | Lowercase a-z, digits 0-9, hyphens |
| Hyphens | No leading, trailing, or consecutive hyphens |
| Folder | Must match the parent directory name |
| claude.ai and API | May not contain “anthropic” or “claude,” or XML tags |
name: pdf-form-filler # valid
name: PDF_Form_Filler # invalid: uppercase and underscores
name: pdf--forms # invalid: consecutive hyphens
name: claude-helper # valid in Claude Code, rejected on claude.ai and the API
The name also becomes the slash command: name: pdf-form-filler gives you /pdf-form-filler.
description
Up to 1,024 characters. This is the text Claude reads when deciding whether to load the skill, so it must say both what the skill does and when to use it, in the words users actually type.
description: Audits React components for accessibility issues against WCAG 2.2 AA, including focus order, ARIA misuse, color contrast, and keyboard traps. Use when reviewing UI components, before a release, or when the user mentions a11y, screen readers, or keyboard navigation.
Write in the third person, front-load the core capability, and list concrete trigger terms. If the description contains a colon followed by a space, quote the whole string, or YAML will try to parse it as a mapping.
Optional open-standard fields
These work in Claude Code, claude.ai, the Claude API, and other tools that implement the Agent Skills specification.
| Field | Type | Limit | Purpose |
|---|---|---|---|
license | string | none | License name or a pointer to a bundled file, for example MIT or Proprietary. See LICENSE.txt |
compatibility | string | 500 chars | Environment requirements: required tools, network access, target product |
metadata | map of string to string | none | Arbitrary key-value pairs such as author or version |
allowed-tools | space-separated string | none | Tools pre-approved while the skill is active (experimental in the spec) |
---
name: release-notes
description: Drafts user-facing release notes from merged pull requests. Use when preparing a release or when asked what changed since the last version.
license: MIT
compatibility: "Requires git and the GitHub CLI (gh) with network access."
metadata:
author: platform-team
version: "1.3.0"
allowed-tools: Bash(git log:*) Bash(gh pr list:*) Read
---
Note that metadata values must be strings, which is why version is quoted.
Claude Code-only fields
Claude Code reads the fields below in addition to the standard ones. Other surfaces ignore or reject them, so a skill that needs to upload to claude.ai should avoid them.
| Field | Default | What it does |
|---|---|---|
when_to_use | none | Extra trigger guidance appended to the description in the skill listing |
argument-hint | none | Hint shown in the / autocomplete, for example [issue-number] |
arguments | none | Named arguments mapped to positions, for $name substitution |
disable-model-invocation | false | true means only the user can invoke the skill with /name |
user-invocable | true | false hides the skill from the / menu; only Claude invokes it |
allowed-tools | none | Tools Claude may use without a permission prompt while the skill is active |
disallowed-tools | none | Tools Claude may not use while the skill is active |
model | inherit | Model to use while the skill runs |
effort | inherit | Reasoning effort: low, medium, high, xhigh, or max |
context | inline | fork runs the skill in a subagent with its own context window |
agent | general-purpose | Subagent type to use when context: fork |
background | false | Background execution for a forked skill |
hooks | none | Hooks scoped to the skill’s lifecycle |
paths | none | Glob patterns limiting when the skill applies |
shell | bash | Shell for !`command` lines: bash or powershell |
Controlling who can invoke a skill
The two invocation flags are the fields you will use most:
# A deploy skill: never auto-triggered, only when you type /deploy-staging
disable-model-invocation: true
# Background knowledge: Claude loads it when relevant, but it is not a command
user-invocable: false
Use disable-model-invocation: true for anything with side effects, such as deploying, publishing, sending messages, or deleting data. Use user-invocable: false for reference material like “our internal API conventions” that makes no sense as a command.
Running a skill in a subagent
context: fork
agent: Explore
With context: fork, the skill runs in a separate subagent and only the result comes back to your main conversation. This suits research-heavy skills that read many files, because the file contents never fill your main context. The trade-off is that the subagent does not see your conversation history, so the skill’s instructions and arguments must be self-contained.
Scoping a skill to file paths
paths:
- "migrations/**/*.sql"
- "db/schema.rb"
paths limits the skill to work involving matching files, which keeps a migration skill from competing with unrelated skills in the rest of the repo.
Description length in the listing
Claude Code combines description and when_to_use in the skill listing and truncates the result at 1,536 characters. Put the most important trigger terms first.
Body syntax: arguments, variables, and dynamic context
Arguments
When a user types /fix-issue 482 high, the text after the skill name is available in the body:
| Placeholder | Value in the example |
|---|---|
$ARGUMENTS | 482 high |
$ARGUMENTS[0] or $0 | 482 |
$ARGUMENTS[1] or $1 | high |
With named arguments, the names map to positions in order:
---
name: fix-issue
description: Fixes a GitHub issue end to end, from reproduction to pull request. Use when the user asks to fix, resolve, or work on a numbered issue.
argument-hint: "[issue-number] [priority]"
arguments: issue priority
disable-model-invocation: true
---
Fix issue #$issue (priority: $priority).
1. Read it with `gh issue view $issue`.
2. Write a failing test that reproduces it.
3. Fix, run the suite, and open a PR that references #$issue.
Built-in variables
| Variable | Expands to |
|---|---|
${CLAUDE_SKILL_DIR} | Absolute path of the skill’s folder |
${CLAUDE_PROJECT_DIR} | Root of the current project |
${CLAUDE_SESSION_ID} | Current session ID |
${CLAUDE_SKILL_DIR} is the reliable way to call bundled scripts regardless of where the skill is installed:
Run `python3 ${CLAUDE_SKILL_DIR}/scripts/validate_form.py output.pdf` and fix every reported field.
Dynamic context with !command
A line containing !`command` runs the command before Claude sees the skill, and the output replaces the placeholder:
## Current state
- Branch: !`git branch --show-current`
- Uncommitted files: !`git status --porcelain | head -20`
- Open PRs: !`gh pr list --limit 5 || true`
Rules to know:
- A failing command aborts loading the skill, unless you handle the failure, for example with
|| true. - Commands go through your normal permission rules.
- Setting
"disableSkillShellExecution": truein settings turns the feature off entirely. shell: powershellswitches the interpreter for Windows-first skills.
How should the body and supporting files be organized?
Keep the body under 500 lines, roughly 5,000 tokens. It loads in full on every invocation and stays in context for the session. Move detail into files the body links to:
api-conventions/
├── SKILL.md
├── references/
│ ├── errors.md # error envelope and codes
│ └── pagination.md # cursor pagination rules
├── scripts/
│ └── lint_openapi.py # executed, output only
└── assets/
└── endpoint-template.ts
Link each reference directly from SKILL.md with a sentence saying when to read it, and keep references one level deep. A reference that points to another reference is easy for Claude to read only partially.
Validation checklist
Before you commit or share a skill, check:
-
namematches the folder and follows the character rules -
descriptionstates what and when, under 1,024 characters - Strings containing
:are quoted - No misspelled keys (Claude Code ignores them silently)
- Only standard keys, if the skill must upload to claude.ai or the API
- Body under 500 lines; references linked from
SKILL.md - Scripts called via
${CLAUDE_SKILL_DIR} - Every
!`command`either cannot fail or ends with|| true
A quick parse check catches most YAML mistakes:
python3 -c "import sys,yaml; t=open(sys.argv[1]).read().split('---')[1]; print(yaml.safe_load(t))" SKILL.md
Next steps
- Put the fields to work: Write your first Claude Code skill
- Writing guidance beyond syntax: Skill authoring best practices
- When fields are right but the skill still does not load: Skill not triggering?
- Skills that help: skill-authoring, skill-description-tuning
- Sources: Claude Code skills docs, Agent Skills specification
Frequently asked questions
Which SKILL.md fields are required?
Only name and description. name must be 1 to 64 characters of lowercase letters, digits, and single hyphens, and must match the folder name. description can be up to 1,024 characters. Every other field is optional.
What happens if I add a frontmatter key Claude Code does not recognize?
Claude Code ignores unknown keys, so a typo like disable-model-invokation fails silently rather than erroring. claude.ai and the Claude API are stricter and reject uploads containing keys outside the open standard.
Should allowed-tools be a list or a string?
The open standard defines it as a space-separated string, for example allowed-tools: Read Grep Glob. It is marked experimental in the spec, so support varies across tools. Use the string form if you want the skill to stay portable.