Skip to content

How to Write SKILL.md for Claude Code, Codex, and 19+ AI Tools

· 7 min read

What is SKILL.md?

SKILL.md is a cross-platform instruction file for AI coding agents. You write one file, and it works across Claude Code, Codex CLI, Gemini CLI, Kiro CLI, Cursor, and 19+ other tools.

I’ve written 30+ skills over the past few months for deployment, testing, code review, and content workflows. The pattern is simple once you internalize it, but the first few attempts usually fail for the same reasons. This guide covers what actually works.

How does it work?

The loading mechanism has two phases:

  1. Index phase — On startup, the tool reads only the YAML frontmatter (name and description) from every SKILL.md file. This builds a lightweight index.
  2. Match phase — When a user sends a message, the tool compares it against all descriptions. If there’s a match, the full markdown body loads into context.

This means your description field is everything. If it doesn’t match, the skill never fires.

Where do SKILL.md files live?

Paths vary by tool, but the format is the same:

ToolPersonal skills pathProject skills path
Claude Code~/.claude/skills/.claude/skills/
Codex CLI~/.codex/skills/ or ~/.agents/skills/.codex/skills/
VS Code Copilot~/.github/skills/.github/skills/
Gemini CLI~/.gemini/skills/.gemini/skills/
Antigravity CLI~/.agy/skills/.agy/skills/
Kiro CLI~/.kiro/skills/.kiro/skills/

The directory name becomes the invocation command. In Claude Code, type /skill-name. In Codex, type $skill-name. The format inside SKILL.md is identical across all platforms.

The anatomy of a SKILL.md

---
name: deploy-to-staging
description: "Use when the user asks to deploy, push to staging, or ship to test environment. Runs the deployment pipeline with safety checks."
---

# Deploy to Staging

## When to use
- User says "deploy", "push to staging", "ship it"
- After tests pass and user wants to see changes live

## Instructions
1. Run `pnpm test` and confirm all tests pass
2. Run `pnpm build` to verify build succeeds
3. Execute `./scripts/deploy-staging.sh`
4. Report the deployment URL back to user

## Rules
- Never deploy if tests are failing
- Always confirm with user before running deploy script
- If deploy fails, show the error log and suggest fixes

How to write a description that actually triggers

The description is the make-or-break field. Here’s what works and what doesn’t:

Bad descriptionWhy it failsGood description
”Helps with deployments”Too vague, won’t match specific requests”Use when the user asks to deploy, push to staging, or ship to test"
"Code review tool”Doesn’t describe when to trigger”Use when reviewing PRs, checking code quality, or before merging branches"
"Database utilities”No trigger words”Use when the user asks to run migrations, seed data, or query the database”

Rules for descriptions:

  1. Start with “Use when” — forces you to describe the trigger scenario
  2. Include the actual words users say — “deploy”, “push”, “ship”, not “initiate deployment sequence”
  3. List 2-3 trigger scenarios — covers variations of the same intent
  4. Keep it under 200 characters — tools truncate long descriptions

Five mistakes that break skills

1. The mega-skill

One SKILL.md that does everything: deploys, tests, reviews, writes docs, makes coffee.

Fix: One skill, one job. If you’re using “and” more than once in the description, split it.

2. Documentation-style body

Writing prose that explains the concept instead of giving commands.

<!-- Bad: reads like documentation -->
The deployment process involves several stages including
building the application, running tests, and pushing to
the staging environment...

<!-- Good: imperative instructions -->
1. Run `pnpm build`
2. Run `pnpm test`
3. Execute `./scripts/deploy.sh`
4. Report the URL from stdout

3. No examples

The agent doesn’t know what good output looks like without examples.

## Example

Input: "deploy the auth service to staging"

Output:
- Ran tests: 47 passed, 0 failed
- Built successfully (2.3s)
- Deployed to: https://staging.example.com/auth
- Health check: ✅ 200 OK

4. Conflicting skills

Two skills with overlapping descriptions. The tool picks one semi-randomly.

Fix: Make descriptions mutually exclusive. “Use when deploying to staging” vs “Use when deploying to production” — not “Use when deploying”.

5. Body exceeds 500 lines

Large bodies eat context window and slow down responses.

Fix: Move reference material to a references/ subdirectory:

my-skill/
├── SKILL.md          # Core instructions (under 500 lines)
└── references/
    ├── api-schema.md # Loaded only when referenced
    └── examples.md

Complete template you can copy

---
name: skill-name-here
description: "Use when [exact trigger phrase 1], [trigger phrase 2], or [trigger phrase 3]. Does [what the skill produces]."
---

# Skill Title

## When to use
- [Specific scenario 1]
- [Specific scenario 2]
- [Specific scenario 3]

## Instructions
1. [First step — be specific about inputs]
2. [Second step — include exact commands]
3. [Third step — describe expected output]

## Example

Input: "[realistic user message]"

Output:
[what the agent should produce]

## Rules
- [Hard constraint 1]
- [Hard constraint 2]
- [What to never do]

How to test your skill

Change the description, then test if it triggers:

# In Claude Code / Codex / Kiro CLI:
> deploy to staging

# Did the skill activate? Check the context panel.
# If not, tweak the description and try again.

Iterate on the description until the trigger is reliable. This is the only testing that matters.

SKILL.md vs other config files

FileLoads whenUse for
SKILL.mdOn demand (description match)Specialized workflows
CLAUDE.md / AGENTS.mdEvery conversationProject-wide rules, style guides
.cursorrulesEvery conversation (Cursor)Editor-specific preferences
.envAlwaysSecrets, API keys

Advanced: Frontmatter fields beyond name and description

The spec has evolved. Here are fields you’ll encounter across platforms:

FieldPlatformPurpose
disable-model-invocationClaude Code, VS Code CopilotSet to true to prevent auto-triggering. Skill only fires via /skill-name. Use for workflows with side effects.
context: forkVS Code Copilot (experimental)Runs the skill in a dedicated subagent context instead of inline.
dependenciesClaude CodeDeclares packages (e.g., python>=3.8, pandas>=1.5.0). Claude installs them when loading.
user-invocableClaude CodeSet to false to make a skill model-only (no slash command).

For Codex specifically, implicit invocation control lives in a separate agents/openai.yaml file with policy.allow_implicit_invocation: false — not in the SKILL.md frontmatter.

Naming rules (per the agentskills.io spec):

  • Maximum 64 characters
  • Lowercase letters, numbers, and hyphens only
  • Must match the directory name
  • Cannot contain reserved words (“anthropic”, “claude”)
  • Description maximum: 1,024 characters (truncated at 1,536 combined with when_to_use)

Security considerations

Skills are text instructions, not sandboxed code. Treat them like dependencies:

  • Read a skill’s SKILL.md before installing it — it’s a text file, takes 30 seconds
  • Prefer skills from known repos (github.com/anthropics/skills, github.com/openai/skills)
  • Be cautious with skills that include executable scripts in scripts/
  • Use project-level skills (.claude/skills/) over global ones (~/.claude/skills/) to limit blast radius
  • The spec doesn’t yet have skill signing or trust levels — read what you install

FAQ

What tools support SKILL.md?
Claude Code, Codex CLI, Gemini CLI, Antigravity CLI, Kiro CLI, Cursor, GitHub Copilot, and 19+ other AI coding tools. It's become a de facto standard.
What's the difference between SKILL.md and CLAUDE.md?
CLAUDE.md loads into context on every conversation. SKILL.md only loads when its description matches the user's request. Use SKILL.md for specialized workflows; use CLAUDE.md for always-on project rules.
How long should a SKILL.md body be?
Under 500 lines. If you need more, split into multiple skills or put reference material in a references/ subdirectory.
Why doesn't my skill trigger reliably?
Your description probably doesn't contain the words users actually say. Include exact trigger phrases and scenarios, not abstract descriptions of capability.

Related Posts