Best practices · 7 min read
12 Best Practices for Writing Claude Code Skills
Twelve rules for writing Claude Code skills that trigger reliably and work: concise bodies, trigger-ready descriptions, checklists, scripts, and real tests.
Good Claude Code skills are short, specific, and tested. The rules that matter most: write the description as a trigger (what the skill does plus when to use it), include only what Claude would not do on its own, match how strictly you constrain Claude to how fragile the task is, put deterministic work in scripts, and test with real prompts in fresh sessions. The twelve rules below expand on each, with before-and-after examples.
These rules draw on Anthropic’s published skill authoring best practices and on patterns from the skills in this directory.
1. Be concise: Claude is already smart
Every line of the body costs context for the rest of the session once the skill loads. The test for each sentence: would Claude get this wrong without it?
<!-- Before: explains what Claude already knows -->
PDF (Portable Document Format) files are a common file format that contains
text, images, and other content. To extract text from a PDF, you need a library.
There are many libraries available...
<!-- After: only the decision Claude needs -->
Extract text with pdfplumber. For scanned PDFs (no text layer), fall back to
OCR with `scripts/ocr.py`.
Spend your words on your team’s conventions, the non-obvious failure modes, and the order of operations. Skip definitions and general advice.
2. Treat the description as the trigger
Claude reads only the name and description when choosing which skill to load. The body cannot help if the description never matches.
A trigger-ready description:
- States what the skill does and when to use it
- Uses the words users actually type
- Is written in the third person
- Front-loads the key capability (Claude Code truncates
descriptionpluswhen_to_useat 1,536 characters in the skill listing)
# Weak
description: Helps with Postgres performance.
# Strong
description: Diagnoses slow Postgres queries with EXPLAIN (ANALYZE, BUFFERS) and recommends indexes, including partial, covering, and expression indexes, while flagging unused or duplicate ones. Use when a query is slow, when the user shares an EXPLAIN plan, asks which index to add, or mentions sequential scans.
If a skill keeps firing at the wrong time or not at all, skill-description-tuning runs a structured test-and-revise loop on the description.
3. Match degrees of freedom to fragility
Decide how much room Claude gets, step by step:
| Freedom | When | Form |
|---|---|---|
| High | Many valid approaches; judgment matters (code review, design feedback) | Goals and criteria in prose |
| Medium | A preferred pattern exists, some variation is fine (report formats) | Templates or pseudocode with parameters |
| Low | Fragile operations where one deviation causes damage (migrations, releases) | Exact commands, in order, with “do not modify” |
A useful image: an open field needs only a direction, but a narrow bridge needs guardrails. A database migration skill should say “Run exactly python scripts/migrate.py --verify --backup. Do not add flags.” A code review skill should say what good looks like and let Claude find the problems.
4. Use checklists for multi-step workflows
For procedures longer than four or five steps, give Claude a checklist to copy into its response and tick off. It makes progress visible and noticeably reduces skipped steps.
## Workflow
Copy this checklist and update it as you go:
- [ ] 1. Reproduce the bug with a failing test
- [ ] 2. Identify the root cause (not just the symptom)
- [ ] 3. Fix with the smallest change
- [ ] 4. Run the full suite
- [ ] 5. Add a regression note to the PR
systematic-debugging and tdd-loop both rely on this pattern.
5. Build in feedback loops
The strongest skills make Claude check its own work: run a validator, fix what it reports, run it again, and only proceed when it passes.
## Validate before finishing
1. Run `python ${CLAUDE_SKILL_DIR}/scripts/validate.py output.json`
2. If it reports errors, fix them and run it again
3. Only report success when the validator exits with no errors
Feedback loops work without scripts too. “Re-read your summary against the checklist above and fix any item you missed” is a loop. The point is a concrete check with a pass condition, not “double-check your work.”
6. Keep references one level deep
Use progressive disclosure: SKILL.md is the overview and workflow, and detail goes into reference files that load only when needed. Link every reference directly from SKILL.md, with a sentence saying when to read it:
## Dialects
- **Postgres**: rules below.
- **MySQL**: read [references/mysql.md](references/mysql.md) before reviewing.
- **SQLite**: read [references/sqlite.md](references/sqlite.md).
Avoid chains where SKILL.md points to advanced.md, which points to details.md. Claude may preview nested files only partially. For reference files over about 100 lines, put a short table of contents at the top so Claude can see the full scope even from a partial read.
7. Put deterministic work in scripts
If a task has one correct answer, such as parsing, validating, counting, or transforming, ship a script instead of instructions. Scripts are more reliable than generated code, and only their output enters context, not their source.
pdf-form-filler/
├── SKILL.md
└── scripts/
├── analyze_form.py # lists every field and its type
├── fill_form.py # writes values from a JSON mapping
└── verify_output.py # confirms every field was written
Make the intent clear in the instructions: “Run analyze_form.py” (execute) versus “See analyze_form.py for the field-type logic” (read). Scripts should handle their own errors with clear messages instead of failing with a stack trace and leaving Claude to guess. Document any constants: TIMEOUT = 30 # most HTTP requests finish in under 30s beats a bare 30.
8. Test with real prompts
Before you trust a skill, test it the way it will be used:
- Triggering. In fresh sessions, try three or four prompts that should load the skill and two that should not. Record the results.
- Behavior. Give it three realistic tasks, including one edge case. Read the output critically.
- Baseline. Run the same tasks without the skill. If the outputs look the same, the skill is not adding value.
- Models. If your team uses different models, test on each. A skill that is clear enough for one may need more detail for another.
Write evaluations before you write extensive documentation. Find where Claude actually fails without the skill, and write the skill to fix those failures, not to cover imagined ones.
9. Avoid time-sensitive information
Instructions like “before August, use the v1 API” become wrong silently. Describe the current method, and park legacy detail in a clearly labeled section:
## Current method
Use the v2 endpoint: `api.example.com/v2/messages`
## Legacy (v1, deprecated)
<details>
<summary>Only for maintaining old integrations</summary>
The v1 endpoint `api.example.com/v1/messages` is no longer supported.
</details>
The same applies to version numbers, pricing, and “latest” anything. If the skill must reference a version, say how to check the current one.
10. Use consistent terminology
Pick one term for each concept and use it everywhere. If the skill says “API endpoint” in one step, “URL” in another, and “route” in a third, Claude may treat them as different things.
| Choose one | Avoid mixing with |
|---|---|
| field | box, element, control |
| migration | change, script, patch |
| finding | issue, problem, comment |
The same goes for output formats. If the report section says “Verdict,” the checklist should not say “Result.”
11. Name skills clearly and consistently
The name becomes the slash command and appears in every listing.
- Use lowercase letters, digits, and single hyphens, 64 characters at most, matching the folder.
- Prefer descriptive, action-oriented names:
processing-pdfs,reviewing-migrations, or noun phrases likeschema-migrations. Be consistent within a collection. - Avoid vague names:
helper,utils,tools,misc. - Avoid “claude” and “anthropic” if the skill might ever be uploaded to claude.ai or the API, where they are not allowed.
12. Choose invocation settings deliberately
Decide who should be able to start the skill:
# Side effects (deploy, publish, send, delete): manual only
disable-model-invocation: true
# Background knowledge, not a meaningful command: Claude only
user-invocable: false
A deploy skill that Claude can trigger because a conversation mentioned “shipping” is a real risk. Equally, a reference skill like “our API conventions” clutters the / menu if users can invoke it. For research-heavy skills that read many files, consider context: fork so the work happens in a subagent and only the result returns.
Bonus: common anti-patterns
- Offering too many options. “You can use pypdf, pdfplumber, PyMuPDF, or pdf2image” forces Claude to choose. Give a default and one escape hatch.
- Windows-style paths. Use forward slashes (
scripts/helper.py) so the skill works on every platform. - Assuming tools are installed. Say “Install with
pip install pypdf” or check first, and note requirements incompatibility. - Restating CLAUDE.md. Facts every session needs belong in
CLAUDE.md, not in a skill that might not load. - One giant skill. If a skill covers three unrelated jobs, its description cannot trigger well for any of them. Split it.
A pre-publish checklist
- Description says what and when, in the third person, with trigger terms first
- Body under 500 lines; every sentence changes behavior
- References one level deep, linked from
SKILL.md - Deterministic steps are scripts, with clear error messages
- Multi-step workflows have a checklist and a validation loop
- No time-sensitive statements; consistent terminology
- Tested: triggers, behavior, and a no-skill baseline
- Invocation flags set deliberately
Next steps
- Apply the rules: Write your first Claude Code skill
- Syntax for everything mentioned here: SKILL.md format reference
- Debug triggering: Skill not triggering?
- See the rules in practice: skill-authoring, code-review, schema-migrations
- Anthropic’s guidance: Skill authoring best practices
Frequently asked questions
How long should a SKILL.md be?
As short as it can be while still changing Claude's behavior. Keep the body under 500 lines, around 5,000 tokens, and move anything conditional into reference files. Many excellent skills are under 150 lines because they contain only rules Claude would not follow unprompted.
Should I write skills in the second person or the imperative?
Write the body as direct instructions in the imperative: 'Run the linter', 'Report findings by severity'. Write the description in the third person ('Reviews migrations...') because it is read as a catalog entry when Claude decides which skill to load.
How do I know whether a skill is actually helping?
Run the same three to five realistic tasks with and without the skill and compare the output. If you cannot see a difference, the skill is restating what Claude already does. Cut it down to the parts that change behavior, or delete it.