Creating a New Skill
Follow these steps when creating a new skill, whether proposed during /done or requested directly.
1. Confirm Scope
Before creating, verify the pattern actually warrants a skill (not just a CLAUDE.md entry):
- Too detailed for CLAUDE.md — needs code examples, decision trees, or multi-section docs
- Reusable across sessions — will be needed repeatedly
- Complex enough to get wrong — without it, Claude might make mistakes or ask the same questions each session
If it's a simple one-liner convention, put it in the project CLAUDE.md instead.
2. Determine Level
Ask the user if not already decided:
- Project-level (
{project}/.claude/skills/{name}/SKILL.md) — Specific to one project. Examples: gene naming conventions, project-specific data formats, project-specific workflows. - User-level (
~/.claude/skills/{name}/SKILL.md) — Applies across multiple projects. Examples: plotting conventions, environment management, export formats.
3. Write an Effective Description
The description field in YAML frontmatter is the single most important part of a skill — it determines whether the skill gets activated. Follow these rules:
Front-load trigger conditions
The first sentence should say WHEN to use the skill, not just WHAT it does.
# BAD — describes what, not when:
description: R ggplot2 plotting conventions and theme.
# GOOD — front-loads triggers:
description: R ggplot2 plotting conventions and theme. Use when creating, modifying, or styling ggplot2 plots in R, or when adjusting plot themes, colors, labels, or formatting.
List concrete triggers
Be specific about what actions or contexts should activate the skill. Use verbs: "creating", "modifying", "saving", "debugging", "exporting".
# BAD — too vague:
description: Use when working with files.
# GOOD — specific actions:
description: Use when overwriting existing files, deleting files, or writing to directories that contain important data (data/, outs/).
Add explicit exclusions when needed
If the skill could be confused with similar skills, add "Do NOT load for" clauses.
description: >
Quarto document conventions for data science analysis scripts (.qmd).
Use when creating or rendering .qmd analysis scripts in data science projects.
Do NOT load for Quarto books, websites, or documentation projects.
Cover edge cases in triggers
Think about variations of the task that should also trigger the skill:
| Core trigger | Edge cases to include |
|---|---|
| "creating plots" | modifying, styling, fixing, adjusting themes |
| "saving figures" | choosing formats, setting DPI, export dimensions |
| "committing changes" | writing commit messages, creating branches, making PRs |
Keep it scannable
The description should be 1-3 sentences. If it needs more, use the multi-line > YAML syntax. Put the most important trigger first.
4. YAML Frontmatter Template
---
name: skill-name
description: >
One-sentence summary of what the skill covers.
Use when [specific trigger 1], [specific trigger 2], or [specific trigger 3].
Do NOT load for [exclusion 1] or [exclusion 2].
user-invocable: false
---
Fields:
name— kebab-case, matches the directory namedescription— trigger-focused (see rules above)user-invocable—trueonly if the user triggers it with/name(like/done,/publish). Most skills arefalse(auto-loaded based on context).
5. Skill Content Structure
After the frontmatter, organize the skill body:
- Title —
# Skill Name - Context/purpose — 1-2 sentences on why this skill exists
- Rules/conventions — The actual content, organized with
##sections - Code examples — When patterns need to be shown, include both R and Python if applicable
- Common mistakes — What goes wrong without this skill (helps justify its existence)
Keep it focused. A skill should cover one coherent topic, not be a grab-bag.
6. File Workflow
- Create/edit in
~/.claude/skills/{name}/SKILL.md - Use generic paths (e.g.,
~/miniconda3, not/Users/jm284/miniconda3) so skills are portable - Do not automatically copy to the lab repo — the user will run
/sync-skillswhen ready to publish
Skills with Bundled Resources
For skills that generate scripts (code-generating pipelines) or HPC-tool skills that deploy SLURM batch jobs, use the Anthropic skill-creator convention for bundled resources:
skill-name/
├── SKILL.md # <500 lines — workflow, decision points
├── templates/ # Job templates copied into project batch/<area>/
│ ├── my_array.sh
│ └── my_samples.tsv
├── scripts/ # Helper code deployed to project python/ or R/
│ └── my_helpers.py
└── references/ # Detailed docs loaded as needed
└── method_notes.md
The three subdirectories are semantically distinct — pick the right one for each resource:
| Subdir | What goes there | Where it gets deployed |
|---|---|---|
templates/ |
Whole batch jobs (SLURM array .sh, sample sheet .tsv stub, conda env .yml, aggregator .qmd) |
Project's batch/<area>/ (or scripts/<area>/ for .qmd), edited then run as-is |
scripts/ |
Reusable helper functions (parsers, plotters, importable modules) | Project's python/ or R/ dir, imported by analysis scripts |
references/ |
Long-form reading material (gotcha lists, lookup tables, tool docs) | Not deployed — loaded by Claude on demand from inside the skill |
Templates deployment convention: When the skill runs, it copies relevant
files from templates/ into the project's batch/<area>/ directory and tells
the user which placeholders to edit (<area>, <XX_script_name>, --array=1-N,
--mail-user=...). Templates should be self-documenting via top-of-file comments
that flag the edit points.
Helper deployment convention: When the skill runs:
- Check if
python/orR/dir exists in the project, create if needed - Check if the helper file already exists in the project
- If it exists and differs, warn the user and ask whether to overwrite
- If it doesn't exist, copy from the skill's
scripts/directory - The generated
.qmdimports from the project-level location
This keeps helper code as real, testable files rather than code blocks in SKILL.md. SKILL.md references the helpers and describes how the generated script uses them.
Examples in the wild:
buscousestemplates/(5 batch files + an aggregator) andreferences/(lineage table + gotchas list) — see~/.claude/skills/busco/hpc,expression-report, andnew-projectusereferences/and/or bundled examples- Older HPC-tool skills (
eggnog-mapper,prost-annotation,fcs-gx) embed batch scripts as fenced code blocks in SKILL.md — that's the legacy single-file pattern, slated for refactor
Shell and $-tokens in SKILL.md bodies
When a skill is invoked, Claude Code runs an argument-substitution pass over the SKILL.md
body before Claude sees it. It replaces $N (a $ immediately followed by a digit —
0-based, so \$0 is the first argument), \$ARGUMENTS, and any declared argument name —
and these collapse to empty strings when the skill is invoked with no arguments (the usual
auto-load case). A $ followed by a letter ($SLURM_ARRAY_TASK_ID, $HOME), command
substitutions $(…), and ${…} are left untouched.
So runnable shell pasted inline that uses positional args or awk fields — echo "\$0",
awk '{print \$1}' — is silently blanked on load. Two fixes:
- Escape each token with a leading backslash; the backslash is consumed on load and the
literal token survives. Never escape a
$+letter token ($SLURM_*,$HOME) — there the backslash is kept, leaving a stray\. - Preferred: put the script in
templates/and load it with Read. Substitution does not run on bundled files, so positional args and$SLURM_ARRAY_TASK_IDsurvive verbatim.
(The example tokens above are backslash-escaped in this file's source so they render correctly when the skill loads.)
7. Register in User CLAUDE.md
After creating a new user-level skill, add it to the appropriate table in ~/.claude/CLAUDE.md under "Available Skills":
- General skills table — if it applies to all project types
- Data Science skills table — if it only applies to data science projects
Project-level skills don't need registration in the user CLAUDE.md — they're discovered automatically from the project's .claude/skills/ directory.