How to Write a Claude Code Skill: Templates and Best Practices
A Claude Code skill is a Markdown file in `.claude/skills/` with four key sections: a description (what task this skill handles), context (project-specific facts needed for the task), instructions (step-by-step what Claude should do), and examples (input/output pairs). The description is the most important — it's how Claude decides when to use the skill.
Writing an effective skill is 80% about the description and instructions. Claude reads the description to decide whether this skill is relevant to your current request. If the description is vague ('helps with coding tasks'), Claude can't reliably match it. If it's specific ('write Prisma database migrations for this project's PostgreSQL schema'), Claude knows exactly when to apply it.
The instructions section should read like a checklist that a new team member would follow. Be explicit: 'Check src/prisma/schema.prisma before writing the migration', 'Run `pnpm prisma migrate dev --name [description]` after writing the migration file', 'Never change existing column types in a migration — write a new column and a data migration instead.' These specifics are what distinguish a skill from a generic prompt.
Include 1-2 concrete examples in your skill file. Claude learns from examples far better than from abstract rules. An example of a good migration + the resulting SQL is worth 10 bullet points about migration best practices. Use code blocks with the actual format you expect.
The context section is for project-specific facts the skill needs: which ORM you use, where migration files live, your naming convention for migration files, whether you use transactions, etc. This context doesn't belong in CLAUDE.md (too specific to this workflow) or in the main prompt (too repetitive to include every time).
Skill files support @imports for pulling in external content. If your 'write-migration' skill needs to reference your current database schema, you can @prisma/schema.prisma to always include the latest schema. If it needs to reference past migration examples, @migrations/examples/ pulls in a directory of examples.
Test your skills by invoking them on a simple case, checking the output, and refining. Common failure modes: instructions too abstract (Claude improvises), missing context (Claude reads extra files it shouldn't need), or anti-patterns not explicitly prohibited (Claude repeats the mistake you were trying to prevent).
Examples
# Skill: Write Database Migration
## Description
Use this skill when asked to add, rename, or modify database tables or columns.
Applies to: Prisma migrations, schema changes, data migrations.
## Context
- ORM: Prisma 5.x
- Database: PostgreSQL 16
- Migration files: `prisma/migrations/`
- Naming: `[timestamp]_[description]` (auto-generated by Prisma)
- Schema file: `prisma/schema.prisma`
@prisma/schema.prisma
## Instructions
1. Read the current schema in `prisma/schema.prisma` to understand existing models
2. Make the minimal schema change needed — do not refactor unrelated models
3. For new columns on existing tables with data, always provide a default value
4. Run: `pnpm prisma migrate dev --name [descriptive-name]` to generate the migration
5. Review the generated SQL in `prisma/migrations/[timestamp]_[name]/migration.sql`
6. If the migration changes enum values, write a separate data migration script
7. Run `pnpm prisma generate` to update the client types
## Rules
- NEVER change a column's type directly — add a new column, migrate data, then drop the old one
- NEVER write raw SQL migration files by hand — always use `prisma migrate dev`
- ALWAYS check that the generated migration is reversible
## Example
Request: "Add a `bio` column to the User model"
Schema change:
```prisma
model User {
id String @id @default(cuid())
email String @unique
name String
bio String? @db.Text // Added
}
```
Command to run:
```bash
pnpm prisma migrate dev --name add_user_bio
```# Skill: Write PR Description
## Description
Use this skill when asked to write a GitHub pull request description.
Invoke when: creating a PR, updating PR description, summarizing changes.
## Instructions
1. Run `git log origin/main...HEAD --oneline` to list commits
2. Run `git diff origin/main...HEAD --stat` to see changed files
3. Read the 3-5 most important changed files to understand the change
4. Write the PR description following the template below
## Template
```markdown
## Summary
<!-- 2-3 sentences: what changed and why -->
## Changes
- <!-- bullet list of specific changes -->
## Testing
- [ ] Unit tests pass (`pnpm test`)
- [ ] Manual testing done (describe what you tested)
- [ ] No regressions in related features
## Screenshots
<!-- If UI changes, add before/after screenshots -->
```
## Rules
- Keep Summary to 2-3 sentences — no more
- List changes as specific bullets, not vague phrases like 'improved performance'
- Always include the testing checklist
- Never use jargon that a non-author reviewer wouldn't understandTips
- →Write the description first and show it to a teammate — if they can predict what the skill does from the description alone, it's specific enough.
- →Include a 'When NOT to use this skill' section if the skill has common misapplication patterns — explicit exclusions prevent Claude from applying it in the wrong context.
- →Use ordered numbered lists for instructions, not bullet points — the order matters and numbered lists signal that to Claude.
- →Test your skill with a deliberately tricky case (edge case input, missing context) to see if the instructions cover it. If Claude improvises wrongly, add a specific rule.
- →Keep skills under 300 lines. Long skills get fuzzy — Claude is more likely to miss instructions buried in the middle of a long document.
- →Add `@file-to-read-as-context` at the top of the Context section — files imported this way give Claude the current state of your project without you having to re-describe it.
FAQ
How do I know if my skill is being used correctly?+
After Claude completes a task where the skill should have applied, ask: 'What skill did you use for this?' Claude will name the skill and describe how it applied the instructions. If Claude says 'I didn't use a specific skill', your skill's description may not match the task vocabulary closely enough.
Can a skill file include conditional logic?+
Not in a programming sense, but you can write conditional instructions in natural language: 'If the column has a non-null constraint and the table already has data, add a DEFAULT value clause.' Claude interprets these conditions correctly. For truly complex branching, consider splitting into two separate skills.
Should a skill include the commands to run or just the instructions?+
Include the exact commands. Don't write 'run the migration command' when you can write `pnpm prisma migrate dev --name [name]`. Exact commands eliminate ambiguity and prevent Claude from guessing your project's tooling.
Can I use a skill in headless/--print mode?+
Yes. Claude reads skills in headless mode just like interactive mode. Include the skill name in your --print prompt: `claude --print 'Use the write-migration skill to add a sessions table with user_id and token columns'`.