Skip to content AI News: ChatGPT and Codex will share one usage limit from December →

How to Create Claude Skills: Build One End to End, Then Test It

Type /pr-description develop in Claude Code and you get a pull request title and body drafted from your branch's commits. A plain request like "draft the PR description for this branch" can trigger the same skill without the slash. It takes three files: SKILL.md, a template and a short shell script.

If you want the concept first (what a skill is, how it compares with MCP or a project), start with the Claude Skills chapter. Ready-made skills are in the Claude Skills catalog, and the coding ones are collected under Claude Code skills.

Where the skill folder goes

Put a skill your team should share in the repository. Claude Code reads skills from several locations, and the folder decides which sessions load it:

LocationPathLoads in
Personal~/.claude/skills/<name>/SKILL.mdAll your projects on this machine
Project.claude/skills/<name>/SKILL.mdSessions in this repository; commit it and your team gets it
Plugin<plugin>/skills/<name>/SKILL.mdWherever the plugin is enabled, as /plugin-name:skill-name

Anthropic's Complete Guide to Building Skills for Claude sets three naming rules: the file is called exactly SKILL.md, case-sensitive; the folder name is kebab-case; and no README.md goes inside the folder. And you don't need to restart: Claude Code watches skill folders and picks up edits in the current session. If the top-level skills folder didn't exist when the session started, run /reload-skills after each change there.

The skill: pr-description

A PR description is a good first skill because you already explain it to Claude the same way every time: read the commits, follow the team template, flag migrations. The finished folder:

.claude/skills/pr-description/
├── SKILL.md
├── template.md
└── scripts/
    └── branch-context.sh

Here's the full SKILL.md:

---
name: pr-description
description: Writes a pull request title and description from the commits and diff on the current branch. Use when the user asks for a PR description, PR body or pull request summary, or is about to open a pull request. Not for commit messages or code review.
argument-hint: "[base-branch]"
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/branch-context.sh *) Bash(git diff *)
---

# PR description

Base branch: $ARGUMENTS (if empty, use main).

1. Run `${CLAUDE_SKILL_DIR}/scripts/branch-context.sh [base branch]` and read
   the commits and changed files it prints. If it says the base branch wasn't
   found, stop and ask which branch the PR targets.
2. For a file whose stat line doesn't explain the change, read it with
   `git diff [base branch]...HEAD -- [file]`.
3. Fill in [template.md](template.md). Keep every heading. Write "None" under
   a heading with nothing to report.
4. Title: imperative mood, under 72 characters, no trailing period.
5. Print the title and the filled template as one markdown block. Don't push,
   and don't open the PR.

## Rules
- Take the what and the why from the commits and the diff. If the why isn't
  in either, ask for it.
- Every migration, new environment variable and new config key goes under
  "Deploy notes".
- Under "Testing", name the tests added or changed. If there are none, say so.

## Example
Commits "add retry to webhook sender", "cap retries at 3", "test retry backoff"
Title: Retry failed webhook deliveries up to 3 times

What each front-matter line does:

${CLAUDE_SKILL_DIR} expands to the skill's own folder in both the body and the allowed-tools rule, so the pre-approval matches the exact command the body tells Claude to run, wherever the skill is installed. $ARGUMENTS becomes whatever you type after the command.

The helper script

Gathering the commits is the fragile step, so it's a script. Claude runs a bundled script through bash, and only its output enters context, not its code. Save this as scripts/branch-context.sh and run chmod +x on it:

#!/usr/bin/env bash
# Prints what a PR description needs: commits and changed files vs. the base branch.
set -euo pipefail
base="${1:-main}"
if ! git rev-parse --verify --quiet "$base" > /dev/null; then
  echo "Base branch '$base' not found. Local branches:"
  git branch --format='%(refname:short)'
  exit 0
fi
echo "Base: $base"
echo
echo "Commits:"
git log --oneline "$base"..HEAD
echo
echo "Files changed:"
git diff --stat "$base"...HEAD

A missing base branch doesn't crash it. The script prints the branches that do exist and exits cleanly, so Claude has something to ask you about.

The template file

template.md is plain markdown:

## Summary
What this PR does and why, in one to three sentences.

## Changes
- One line per change a reviewer should know about.

## Testing
Tests added or changed, and how to run them.

## Deploy notes
Migrations, environment variables, config keys. "None" if there are none.

Four headings would fit inside SKILL.md. Keep them in their own file anyway: whoever owns the team's PR format can change it without touching the instructions. Claude Code's docs say to link each supporting file from SKILL.md and keep SKILL.md itself under 500 lines.

Run it

Start a message with the command and an optional base branch:

/pr-description develop

The slash only runs the skill at the start of a message. Mid-sentence, "go ahead and /pr-description" counts as permission for Claude to use it, and Claude judges from your wording whether to.

Test that Claude picks it up

Seeing a skill trigger once proves Claude found it, nothing more. Anthropic's Claude Code docs say to run each test prompt in a fresh session, with the skill on and again with it off, because context left over from writing the skill hides gaps in it. Switch it off for the baseline with "pr-description": "off" under skillOverrides in your settings.

Two checks come before any prompt. Ask What skills are available? and confirm pr-description is listed. Then ask When would you use the pr-description skill?, which makes Claude quote the description back so you can see what it's matching against.

Then the prompts. The guide's triggering tests cover obvious tasks, paraphrased requests and unrelated topics. Anthropic's skill-creator adds that the useful negatives are near-misses that share keywords with the skill. For pr-description:

PromptExpectedWhat it tests
I'm opening a pull request from this branch into develop, draft the descriptionTriggersThe obvious phrasing, with a base branch
write up what this branch changes so reviewers know what they're looking atTriggersA paraphrase with no "PR" in it
write a commit message for what's stagedDoesn'tThe commit-message near-miss the description excludes
review the diff on this branch for bugs before I open the PRDoesn'tMentions a PR, but it's a code review
add a Screenshots section to .github/pull_request_template.mdDoesn'tShares "pull request" and "template", wrong job

Keep test prompts substantive. Claude consults skills for tasks it can't easily handle on its own, so a one-step request may skip even a perfect description. Rows two to five carry the information. A pass on row two means the description covers how people actually ask, passes on rows three and four mean the exclusion line works, and a pass on row five shows Claude isn't matching on shared words alone.

When it never fires, or fires too often

If the paraphrase row fails, the description lacks the words people use. Claude Code's checklist for a skill that doesn't trigger starts there:

Anthropic's skill-creator goes further and calls for "pushy" descriptions, because Claude tends to undertrigger. That's the right call for a skill whose output Claude can't produce well alone.

When a near-miss row fires, narrow it. Claude Code's fix for a skill that triggers too often is a more specific description, or disable-model-invocation: true so only /pr-description starts it. The guide adds negative triggers, which is what "Not for commit messages or code review" is doing. Reach for disable-model-invocation only when the skill has side effects, like a deploy. A PR draft is harmless, so tighten the wording.

A third failure looks like a trigger problem and isn't. The skill fires, and three turns later Claude stops following it. The body enters the conversation once and isn't re-read, and after compaction Claude Code keeps the first 5,000 tokens of each skill. Claude Code's fix depends on the rule. One that must hold every time moves into a hook. Guidance Claude applies with judgment goes near the top of SKILL.md, worded for the whole task: "keep the PR body under 10 lines unless the diff touches more than one module".

Anthropic's best practices, as do and don't

Anthropic's skill authoring best practices, applied to pr-description:

RuleDon'tDo
Assume Claude already knows"A pull request asks to merge one branch into another, and reviewers read its description to…""Title: imperative mood, under 72 characters."
Description in third person"I can help you write PR descriptions""Writes a pull request title and description from…"
Match freedom to fragility"Collect the commits somehow"An exact script command for data; free wording for the summary
References one level deepSKILL.md links template.md, which links sections.mdEvery file linked straight from SKILL.md
Scripts handle their own errorsgit log main..HEAD that dies on a repo without mainPrint the branches that exist and exit 0
One term per thing"base branch" in step 1, "target" in step 2, "upstream" in the rules"base branch" everywhere
Evaluations before instructionsWrite 200 lines, then try itThree tasks Claude gets wrong without the skill, then just enough text to fix them

One more applies if your team mixes models: Anthropic says to test the skill with every model you plan to run it on, since what's enough for Opus may need more detail for Haiku.

Share it with your team

Commit .claude/skills/ and your team has it. Past one repo, Claude Code can share skills through a plugin, or through managed settings for a whole organization. A plugin is worth it when you're packaging several skills, subagents, hooks or MCP servers as one unit for many projects.

Two cautions before you push. Uploading to claude.ai or the Skills API accepts only six front-matter fields, so argument-hint would fail that upload with a hard error; drop it for a skill headed there. And a project skill's allowed-tools applies even in a folder you've never trusted, so read those lines in any repo you clone.

Project facts every session needs go in CLAUDE.md, not in a skill. When a job's output would flood the conversation, hand it to a subagent instead.

When skill-creator beats writing by hand

Write by hand when you already know the procedure and the skill fits on a page, as pr-description does. Use Anthropic's skill-creator when trigger accuracy matters or you need proof the skill helps. In Claude Code it runs each test in an isolated subagent, benchmarks with-skill against without, and tunes the description from should-trigger and should-not-trigger prompts. Install it with:

/plugin install skill-creator@claude-plugins-official

Then ask evaluate my pr-description skill with skill-creator. Each test runs twice, so it costs more usage than the five prompts above. Spend it on a skill the whole team will lean on.

Sources

Weekly

New prompts in your inbox

One email a week: the best new prompts and one short guide. Confirm by email and get the free Prompt Cheat Sheet (PDF). Unsubscribe any time. Privacy policy