· claude-code / skills / tutorial

How to write a Claude Code skill (and ship it to a team)

Claude Code skills are on-demand Markdown guides that extend what the model does. Write one, install it, invoke it — start to finish in 20 minutes.

By Ethan

2,227 words · 12 min read

Claude Code skills are on-demand Markdown files that teach Claude a reusable workflow — a commit-message format, a code-review rubric, a debugging protocol. Unlike CLAUDE.md, which loads every session whether you need it or not, a skill loads only when invoked. You write the file, drop it in the right directory, and from that point forward /your-skill-name loads your instructions into the session.

This tutorial builds a working skill from scratch: a commit-message skill that generates Conventional Commits from staged diffs. By the end you’ll have a skill installed, testable via slash command, debuggable when it misbehaves, and — if you want — packaged into a plugin your whole team can install in one command.

Who this is for

Developers who already use Claude Code and find themselves repeating the same prompts — “write me a commit message in our format,” “review this diff for our naming conventions,” “use the error-handling pattern from our style guide.” If that loop sounds familiar, skills are the fix. You need familiarity with Claude Code basics. No knowledge of its internals required.

What is a Claude Code skill

A skill is a SKILL.md file with YAML frontmatter. When Claude Code starts a session, it loads the name and description of every installed skill into the system prompt. That index is how Claude decides when to fire a skill automatically. The full SKILL.md body only loads when the skill is actually triggered — either by Claude deciding the description matches the task, or by you invoking it directly with /skill-name.

Compare this to CLAUDE.md:

CLAUDE.mdSkills
When it loadsEvery session, alwaysOn demand — only when triggered
Primary purposeProject-wide defaults and guardrailsReusable process guides
ScopeApplies to every messageInvoked for a specific task

The distinction matters for context cost. A 400-line CLAUDE.md consumes tokens on every message in every session. A 400-line skill costs nothing until called. For heavy process documentation — review rubrics, release checklists, multi-step debugging protocols — the on-demand model is the right one.

Anatomy of a skill file

A minimal valid skill:

---
name: commit-message
description: Generates conventional commit messages by analyzing staged git diffs. Use when the user asks for help writing a commit message or reviewing staged changes.
---

# Conventional Commit Messages

1. Run `git diff --staged` to read what's staged.
2. Write the commit in this format: `<type>(<scope>): <short description>`
3. Types: feat, fix, refactor, docs, test, chore, style, perf

The name field

The directory name is the invocation key — type /commit-message and Claude loads the skill in the directory called commit-message. The name: field is optional: it sets the display label shown in menus and listings, and defaults to the directory name if omitted. Use letters, numbers, and hyphens only in your directory name; spaces and special characters break invocation.

The description field

This is the most consequential part of your skill file, and the part authors most often get wrong.

At session start, Claude reads the descriptions of every installed skill to build a mental index of when each one should fire. It makes auto-trigger decisions from this index alone — the full body doesn’t load until after the decision. A vague description ("Helps with commits") never matches anything. A specific one ("Generates conventional commit messages by analyzing staged git diffs. Use when the user asks for help writing a commit message") fires reliably.

Two rules for descriptions:

  1. Write in third person. The description is injected into the system prompt verbatim. First-person ("I can help you...") breaks the framing. Pattern: "Does X. Use when..." — what it does plus when to trigger it.
  2. Never summarize the workflow in the description. If the description says “runs two review passes,” Claude may treat that as the full instruction and skip reading the body. Keep descriptions as triggering conditions only, not process summaries.

The command-name tag convention

Skills can use a <command-name> HTML-comment-style tag in the body to mark the invocation point. When Claude Code loads a skill, it looks for this tag to confirm the skill loaded correctly. Some skills use this to expose conditional behavior — for example, <SUBAGENT-STOP> in the Superpowers using-superpowers skill tells Claude to skip the skill body when it’s running as a subagent, not an interactive session. You don’t need this for a basic skill, but it’s useful to know what it means if you see it in production skills.

File size

Keep SKILL.md under 500 lines. The full file loads into context on every invocation. Heavy reference material — large tables, extended examples, external rubrics — belongs in separate files that SKILL.md links to. Claude loads those supplementary files only when the body explicitly references them.

Write your first skill

Step 1: Create the directory structure

mkdir -p ~/.claude/skills/commit-message
touch ~/.claude/skills/commit-message/SKILL.md

Skills live in subdirectories, not flat files. ~/.claude/skills/commit-message.md does not work — the subdirectory is required and silently ignored if missing.

Step 2: Write the SKILL.md

Open ~/.claude/skills/commit-message/SKILL.md and paste this:

---
name: commit-message
description: Generates conventional commit messages by analyzing staged git diffs. Use when the user asks for help writing commit messages or reviewing staged changes.
---

# Conventional Commit Messages

## Quick start

1. Run `git diff --staged` to read what's staged.
2. Write the commit message in this format:

```
<type>(<scope>): <short description>

<optional body: why this change, not what it does>
```

**Types**: feat, fix, refactor, docs, test, chore, style, perf

## Examples

```
feat(auth): add JWT refresh token rotation
fix(api): handle null response from upstream service
chore: upgrade lodash to 4.17.21
docs(readme): add local dev prerequisites
```

## Rules

- Subject line max 72 characters.
- Scope is the module, package, or subsystem being changed. Omit when the change is cross-cutting.
- Body is optional. Use it only when the *why* is non-obvious from the diff.
- No period at the end of the subject line.
- Breaking changes: append `!` after the type/scope and add a `BREAKING CHANGE:` footer.

Step 3: Verify the structure

ls -la ~/.claude/skills/commit-message/

Expected output:

total 8
drwxr-xr-x  3 you  staff   96 May 14 09:00 .
drwxr-xr-x  5 you  staff  160 May 14 09:00 ..
-rw-r--r--  1 you  staff  612 May 14 09:00 SKILL.md

Install and invoke

Personal skills in ~/.claude/skills/ are available immediately in any new Claude Code session — no install command needed. Start a new session, and the skill is ready.

Three ways to invoke it:

Method 1: Slash command in the terminal

/commit-message

Claude loads the SKILL.md body and executes it in the current session. This always works regardless of whether auto-trigger would have fired.

Method 2: Natural language (auto-trigger)

Because the description is loaded at session start, Claude can trigger the skill automatically when your message matches the trigger conditions. If you type “write a commit message for these staged changes,” Claude fires /commit-message on its own — you don’t type the slash command.

Whether auto-trigger fires depends entirely on description quality. This is why the description is the skill’s most critical field.

Method 3: The Skill tool

Within a session, Claude invokes skills programmatically:

Skill({ skill: "commit-message" })

You don’t call this directly — it’s how Claude Code fires your skill internally. Plugin-namespaced skills use the plugin:skill format: Skill({ skill: "superpowers:brainstorming" }).

Install paths

LocationPathWho sees it
Personal~/.claude/skills/<name>/SKILL.mdYou only, all your projects
Project.claude/skills/<name>/SKILL.mdEveryone who clones the repo
Pluginvia claude plugins installAnyone who installs the plugin

Project-level skills are the right choice for team conventions — a code-review rubric, a release checklist, a logging standard. Commit .claude/skills/ to the repo and every contributor gets the skill automatically with no additional setup.

Test and iterate

Start with a forced invocation before relying on auto-trigger:

/commit-message

Verify that Claude loads the body and generates a commit message from your staged diff. If it works via slash command, the skill is installed correctly. Auto-trigger issues are always description problems, not installation problems.

Debugging checklist when a skill doesn’t fire:

  1. Directory name — verify the directory name matches the slug you’re typing. /commit_message (underscore) won’t match a directory named commit-message (hyphen). Spaces or special characters in the directory name break invocation entirely.
  2. Description specificity — add the exact phrasing you use in practice. If you say “write a commit” rather than “write a commit message,” your description needs to match. Start with "Use when..." and list concrete trigger phrases.
  3. Directory structure — the file must be at ~/.claude/skills/<name>/SKILL.md. A flat ~/.claude/skills/<name>.md is silently ignored. Confirm with ls ~/.claude/skills/<name>/.
  4. Force-invoke as baseline/skill-name loads the skill regardless of auto-trigger logic. If the slash command works but auto-trigger doesn’t, the issue is the description, not the file.
  5. Plugin conflict — if a plugin skill and a personal skill share the same name:, check which one wins with claude plugins details <plugin-name>. The resolution order (personal vs. project vs. plugin) is documented in the official Anthropic docs.

One iteration cycle: edit SKILL.md, test with /commit-message. Edits to existing skill files take effect live within the current session without restarting; only creating a brand-new top-level skills directory requires a session restart.

A practical test for description quality: read the description aloud and ask whether it uniquely identifies when this skill should fire versus every other skill you have installed. If the answer is ambiguous, tighten it.

Package and share

If the skill is useful beyond your machine, the plugin route adds version control and a one-command team install.

Plugin directory structure

my-skills-plugin/
  .claude-plugin/
    plugin.json
  skills/
    commit-message/
      SKILL.md
    code-review/
      SKILL.md
      rubric.md
  README.md

Supplementary files (rubric.md, large lookup tables) live alongside SKILL.md in the skill directory. The main skill file stays concise; heavy content moves to reference files that load on demand.

plugin.json

{
  "name": "my-skills-plugin",
  "description": "Team workflow skills",
  "version": "1.0.0",
  "author": {
    "name": "Your Name",
    "email": "[email protected]"
  },
  "repository": "https://github.com/yourusername/my-skills-plugin"
}

Validate before publishing:

claude plugins validate .

Installing from a GitHub repo

# Register the repo as a marketplace source (one-time per machine)
claude plugins marketplace add yourusername/my-skills-plugin

# Install the plugin
claude plugins install my-skills-plugin@yourusername

Claude Code restarts, the plugin’s skills are available, and the plugin appears in ~/.claude/settings.json under enabledPlugins. Team members run the same two commands on their machines and get the same skills.

Test a plugin locally before publishing:

claude --plugin-dir /path/to/my-skills-plugin

This loads the plugin for one session only — nothing is written to settings.json. Run /commit-message inside that session to confirm the skill body loads correctly.

Plugin CLI reference (Claude Code v2.1.140):

claude plugins list                          # show installed plugins
claude plugins install <name>@<source>       # install
claude plugins update <name>                 # update to latest version
claude plugins uninstall <name>              # remove
claude plugins details <name>                # list skills + estimated token cost per skill
claude plugins validate <path>               # validate plugin.json

claude plugins details is worth running on any new plugin before installing it on a shared machine — it shows each skill’s estimated token footprint so you know the per-invocation cost before you commit to it.

Going further

Superpowers is the canonical reference plugin for production skill patterns. It ships 14 skills covering brainstorming, systematic debugging, TDD, code review, and more. Each skill demonstrates the format: a concise SKILL.md under 200 lines, heavy reference moved to supplementary files, and a description tuned for reliable auto-trigger. GitHub: obra/superpowers. Install it with:

claude plugins install superpowers@claude-plugins-official

For team skills in production outside the plugin system, the packages/agents/skills/ directory in this repo has 16 editorial-pipeline skills used by AI agents running this site’s publishing workflow. They’re loaded via a different mechanism (injected through CLAUDE.md rather than the Skill tool), but the content structure — numbered steps, exact CLI invocations, explicit failure modes — is exactly what makes a skill reliable at scale. The editorial rubric, house-style guide, and SEO checklist are all skills here. Worth reading if you’re building skills for agent workflows rather than interactive sessions.

The full frontmatter spec beyond name and description is at agentskills.io/specification and docs.anthropic.com/en/docs/claude-code/skills.

Skills extend Claude’s behavior with reusable workflows; MCP extends what Claude can connect to. If you want Claude Code to query live data sources — databases, APIs, external services — building an MCP server for Claude Code is the natural complement, and takes about the same 30 minutes to get working.

For teams running heavy AI agent sessions — multiple Claude Code instances, parallel pipelines, automated workflows — Claude Max is worth evaluating. The higher usage limits matter when skills are firing across many parallel sessions. GitHub Copilot has no equivalent extensibility model as of 2026: there’s no way to package and share workflow instructions the way Claude Code skills allow. For teams already on Claude Code, skills are the lowest-effort path to consistent AI behavior across everyone’s sessions. Before committing to Max, the Claude Code 2026 review covers benchmark accuracy, usage-limit tradeoffs, and the April regression story in one place.