| name | skill-creator |
| description | Use this skill when the users asks for help creating or improving a skill, or when they ask for best practices in skill creation. This skill provides guidance on how to write well-scoped, effective skills that trigger reliably on relevant prompts. |
Best practices for skill creators
How to write skills that are well-scoped and calibrated to the task.
Start from real expertise
A common pitfall in skill creation is asking an LLM to generate a skill without providing domain-specific context — relying solely on the LLM's general training knowledge. The result is vague, generic procedures ("handle errors appropriately," "follow best practices for authentication") rather than the specific API patterns, edge cases, and project conventions that make a skill valuable.
Effective skills are grounded in real expertise. The key is feeding domain-specific context into the creation process.
Extract from a hands-on task
Complete a real task in conversation with an agent, providing context, corrections, and preferences along the way. Then extract the reusable pattern into a skill. Pay attention to:
- Steps that worked — the sequence of actions that led to success
- Corrections you made — places where you steered the agent's approach (e.g., "use library X instead of Y," "check for edge case Z")
- Input/output formats — what the data looked like going in and coming out
- Context you provided — project-specific facts, conventions, or constraints the agent didn't already know
Synthesize from existing project artifacts
When you have a body of existing knowledge, you can feed it into an LLM and ask it to synthesize a skill. A data-pipeline skill synthesized from your team's actual incident reports and runbooks will outperform one synthesized from a generic "data engineering best practices" article, because it captures your schemas, failure modes, and recovery procedures. The key is project-specific material, not generic references.
Good source material includes:
- Internal documentation, runbooks, and style guides
- API specifications, schemas, and configuration files
- Code review comments and issue trackers (captures recurring concerns and reviewer expectations)
- Version control history, especially patches and fixes (reveals patterns through what actually changed)
- Real-world failure cases and their resolutions
Refine with real execution
The first draft of a skill usually needs refinement. Run the skill against real tasks, then feed the results — all of them, not just failures — back into the creation process. Ask: what triggered false positives? What was missed? What could be cut?
Even a single pass of execute-then-revise noticeably improves quality, and complex domains often benefit from several.
Read agent execution traces, not just final outputs. If the agent wastes time on unproductive steps, common causes include instructions that are too vague (the agent tries several approaches before finding one that works), instructions that don't apply to the current task (the agent follows them anyway), or too many options presented without a clear default.
For a more structured approach to iteration, including test cases, assertions, and grading, see Evaluating skill output quality.
Spending context wisely
Once a skill activates, its full SKILL.md body loads into the agent's context window alongside conversation history, system context, and other active skills. Every token in your skill competes for the agent's attention with everything else in that window.
Add what the agent lacks, omit what it knows
Focus on what the agent wouldn't know without your skill: project-specific conventions, domain-specific procedures, non-obvious edge cases, and the particular tools or APIs to use. You don't need to explain what a PDF is, how HTTP works, or what a database migration does.
<!-- Too verbose — the agent already knows what PDFs are -->
## Extract PDF text
PDF (Portable Document Format) files are a common file format that contains
text, images, and other content. To extract text from a PDF, you'll need to
use a library. pdfplumber is recommended because it handles most cases well.
<!-- Better — jumps straight to what the agent wouldn't know on its own -->
## Extract PDF text
Use pdfplumber for text extraction. For scanned documents, fall back to
pdf2image with pytesseract.
```python
import pdfplumber
with pdfplumber.open("file.pdf") as pdf:
text = pdf.pages[0].extract_text()
```
Ask yourself about each piece of content: "Would the agent get this wrong without this instruction?" If the answer is no, cut it. If you're unsure, test it. And if the agent already handles the entire task well without the skill, the skill may not be adding value. See Evaluating skill output quality for how to test this systematically.
Design coherent units
Deciding what a skill should cover is like deciding what a function should do: you want it to encapsulate a coherent unit of work that composes well with other skills. Skills scoped too narrowly force multiple skills to load for a single task, risking overhead and conflicting instructions. Skills scoped too broadly become hard to activate precisely. A skill for querying a database and formatting the results may be one coherent unit, while a skill that also covers database administration is probably trying to do too much.
Aim for moderate detail
Overly comprehensive skills can hurt more than they help — the agent struggles to extract what's relevant and may pursue unproductive paths triggered by instructions that don't apply to the current task. Concise, stepwise guidance with a working example tends to outperform exhaustive documentation. When you find yourself covering every edge case, consider whether most are better handled by the agent's own judgment.
Structure large skills with progressive disclosure
The specification recommends keeping SKILL.md under 500 lines and 5,000 tokens — just the core instructions the agent needs on every run. When a skill legitimately needs more content, move detailed reference material to separate files in references/ or similar directories.
The key is telling the agent when to load each file. "Read references/api-errors.md if the API returns a non-200 status code" is more useful than a generic "see references/ for details." This lets the agent load context on demand rather than up front, which is how progressive disclosure is designed to work.
Calibrating control
Not every part of a skill needs the same level of prescriptiveness. Match the specificity of your instructions to the fragility of the task.
Match specificity to fragility
Give the agent freedom when multiple approaches are valid and the task tolerates variation. For flexible instructions, explaining why can be more effective than rigid directives — an agent that understands the purpose behind an instruction makes better context-dependent decisions. A code review skill can describe what to look for without prescribing exact steps:
## Code review process
1. Check all database queries for SQL injection (use parameterized queries)
2. Verify authentication checks on every endpoint
3. Look for race conditions in concurrent code paths
4. Confirm error messages don't leak internal details
Be prescriptive when operations are fragile, consistency matters, or a specific sequence must be followed:
## Database migration
Run exactly this sequence:
```bash
python scripts/migrate.py --verify --backup
```
Do not modify the command or add additional flags.
Most skills have a mix. Calibrate each part independently.
Provide defaults, not menus
When multiple tools or approaches could work, pick a default and mention alternatives briefly rather than presenting them as equal options.
<!-- Too many options -->
You can use pypdf, pdfplumber, PyMuPDF, or pdf2image...
<!-- Clear default with escape hatch -->
Use pdfplumber for text extraction:
```python
import pdfplumber
```
For scanned PDFs requiring OCR, use pdf2image with pytesseract instead.
Favor procedures over declarations
A skill should teach the agent how to approach a class of problems, not what to produce for a specific instance. Compare:
<!-- Specific answer — only useful for this exact task -->
Join the `orders` table to `customers` on `customer_id`, filter where
`region = 'EMEA'`, and sum the `amount` column.
<!-- Reusable method — works for any analytical query -->
1. Read the schema from `references/schema.yaml` to find relevant tables
2. Join tables using the `_id` foreign key convention
3. Apply any filters from the user's request as WHERE clauses
4. Aggregate numeric columns as needed and format as a markdown table
This doesn't mean skills can't include specific details — output format templates (see Templates for output format), constraints like "never output PII," and tool-specific instructions are all valuable. The point is that the approach should generalize even when individual details are specific.
Patterns for effective instructions
These are reusable techniques for structuring skill content. Not every skill needs all of them — use the ones that fit your task.
Gotchas sections
The highest-value content in many skills is a list of gotchas — environment-specific facts that defy reasonable assumptions. These aren't general advice ("handle errors appropriately") but concrete corrections to mistakes the agent will make without being told otherwise:
## Gotchas
- The `users` table uses soft deletes. Queries must include
`WHERE deleted_at IS NULL` or results will include deactivated accounts.
- The user ID is `user_id` in the database, `uid` in the auth service,
and `accountId` in the billing API. All three refer to the same value.
- The `/health` endpoint returns 200 as long as the web server is running,
even if the database connection is down. Use `/ready` to check full
service health.
Keep gotchas in SKILL.md where the agent reads them before encountering the situation. A separate reference file works if you tell the agent when to load it, but for non-obvious issues, the agent may not recognize the trigger.
When an agent makes a mistake you have to correct, add the correction to the gotchas section. This is one of the most direct ways to improve a skill iteratively (see [Refine with real execution](#refine-with-real-execution)).
Templates for output format
When you need the agent to produce output in a specific format, provide a template. This is more reliable than describing the format in prose, because agents pattern-match well against concrete structures. Short templates can live inline in SKILL.md; for longer templates, or templates only needed in certain cases, store them in assets/ and reference them from SKILL.md so they only load when needed.
## Report structure
Use this template, adapting sections as needed for the specific analysis:
```markdown
# [Analysis Title]
## Executive summary
[One-paragraph overview of key findings]
## Key findings
- Finding 1 with supporting data
- Finding 2 with supporting data
## Recommendations
1. Specific actionable recommendation
2. Specific actionable recommendation
```
Checklists for multi-step workflows
An explicit checklist helps the agent track progress and avoid skipping steps, especially when steps have dependencies or validation gates.
## Form processing workflow
Progress:
- [ ] Step 1: Analyze the form (run `scripts/analyze_form.py`)
- [ ] Step 2: Create field mapping (edit `fields.json`)
- [ ] Step 3: Validate mapping (run `scripts/validate_fields.py`)
- [ ] Step 4: Fill the form (run `scripts/fill_form.py`)
- [ ] Step 5: Verify output (run `scripts/verify_output.py`)
Validation loops
Instruct the agent to validate its own work before moving on. The pattern is: do the work, run a validator (a script, a reference checklist, or a self-check), fix any issues, and repeat until validation passes.
## Editing workflow
1. Make your edits
2. Run validation: `python scripts/validate.py output/`
3. If validation fails:
- Review the error message
- Fix the issues
- Run validation again
4. Only proceed when validation passes
A reference document can also serve as the "validator" — instruct the agent to check its work against the reference before finalizing.
Plan-validate-execute
For batch or destructive operations, have the agent create an intermediate plan in a structured format, validate it against a source of truth, and only then execute.
## PDF form filling
1. Extract form fields: `python scripts/analyze_form.py input.pdf` → `form_fields.json`
(lists every field name, type, and whether it's required)
2. Create `field_values.json` mapping each field name to its intended value
3. Validate: `python scripts/validate_fields.py form_fields.json field_values.json`
(checks that every field name exists in the form, types are compatible, and
required fields aren't missing)
4. If validation fails, revise `field_values.json` and re-validate
5. Fill the form: `python scripts/fill_form.py input.pdf field_values.json output.pdf`
The key ingredient is step 3: a validation script that checks the plan (field_values.json) against the source of truth (form_fields.json). Errors like "Field 'signature_date' not found — available fields: customer_name, order_total, signature_date_signed" give the agent enough information to self-correct.
Bundling reusable scripts
When iterating on a skill, compare the agent's execution traces across test cases. If you notice the agent independently reinventing the same logic each run — building charts, parsing a specific format, validating output — that's a signal to write a tested script once and bundle it in scripts/.
For more on designing and bundling scripts, see Using scripts in skills.
Optimizing skill descriptions
How to improve your skill's description so it triggers reliably on relevant prompts.
A skill only helps if it gets activated. The description field in your SKILL.md frontmatter is the primary mechanism agents use to decide whether to load a skill for a given task. An under-specified description means the skill won't trigger when it should; an over-broad description means it triggers when it shouldn't.
This guide covers how to systematically test and improve your skill's description for triggering accuracy.
How skill triggering works
Agents use progressive disclosure to manage context. At startup, they load only the name and description of each available skill — just enough to decide when a skill might be relevant. When a user's task matches a description, the agent reads the full SKILL.md into context and follows its instructions.
This means the description carries the entire burden of triggering. If the description doesn't convey when the skill is useful, the agent won't know to reach for it.
One important nuance: agents typically only consult skills for tasks that require knowledge or capabilities beyond what they can handle alone. A simple, one-step request like "read this PDF" may not trigger a PDF skill even if the description matches perfectly, because the agent can handle it with basic tools. Tasks that involve specialized knowledge — an unfamiliar API, a domain-specific workflow, or an uncommon format — are where a well-written description can make the difference.
Writing effective descriptions
Before testing, it helps to know what a good description looks like. A few principles:
- Use imperative phrasing. Frame the description as an instruction to the agent: "Use this skill when..." rather than "This skill does..." The agent is deciding whether to act, so tell it when to act.
- Focus on user intent, not implementation. Describe what the user is trying to achieve, not the skill's internal mechanics. The agent matches against what the user asked for.
- Err on the side of being pushy. Explicitly list contexts where the skill applies, including cases where the user doesn't name the domain directly: "even if they don't explicitly mention 'CSV' or 'analysis.'"
- Keep it concise. A few sentences to a short paragraph is usually right — long enough to cover the skill's scope, short enough that it doesn't bloat the agent's context across many skills. The specification enforces a hard limit of 1024 characters.
Designing trigger eval queries
To test triggering, you need a set of eval queries — realistic user prompts labeled with whether they should or shouldn't trigger your skill.
[
{ "query": "I've got a spreadsheet in ~/data/q4_results.xlsx with revenue in col C and expenses in col D — can you add a profit margin column and highlight anything under 10%?", "should_trigger": true },
{ "query": "whats the quickest way to convert this json file to yaml", "should_trigger": false }
]
Aim for about 20 queries: 8-10 that should trigger and 8-10 that shouldn't.
Should-trigger queries
These test whether the description captures the skill's scope. Vary them along several axes:
- Phrasing: some formal, some casual, some with typos or abbreviations.
- Explicitness: some name the skill's domain directly ("analyze this CSV"), others describe the need without naming it ("my boss wants a chart from this data file").
- Detail: mix terse prompts with context-heavy ones — a short "analyze my sales CSV and make a chart" alongside a longer message with file paths, column names, and backstory.
- Complexity: vary the number of steps and decision points. Include single-step tasks alongside multi-step workflows to test whether the agent can discern the skill is relevant when the task it addresses is buried in a larger chain.
The most useful should-trigger queries are ones where the skill would help but the connection isn't obvious from the query alone. These are the cases where description wording makes the difference — if the query already asks for exactly what the skill does, any reasonable description would trigger.
Should-not-trigger queries
The most valuable negative test cases are near-misses — queries that share keywords or concepts with your skill but actually need something different. These test whether the description is precise, not just broad.
For a CSV analysis skill, weak negative examples would be:
"Write a fibonacci function" — obviously irrelevant, tests nothing.
"What's the weather today?" — no keyword overlap, too easy.
Strong negative examples:
"I need to update the formulas in my Excel budget spreadsheet" — shares "spreadsheet" and "data" concepts, but needs Excel editing, not CSV analysis.
"can you write a python script that reads a csv and uploads each row to our postgres database" — involves CSV, but the task is database ETL, not analysis.
Tips for realism
Real user prompts contain context that generic test queries lack. Include:
- File paths (
~/Downloads/report_final_v2.xlsx)
- Personal context (
"my manager asked me to...")
- Specific details (column names, company names, data values)
- Casual language, abbreviations, and occasional typos
Testing whether a description triggers
The basic approach: run each query through your agent with the skill installed and observe whether the agent invokes it. Make sure the skill is registered and discoverable by your agent — how this works varies by client (e.g., a skills directory, a configuration file, or a CLI flag).
Most agent clients provide some form of observability — execution logs, tool call histories, or verbose output — that lets you see which skills were consulted during a run. Check your client's documentation for details. The skill triggered if the agent loaded your skill's SKILL.md; it didn't trigger if the agent proceeded without consulting it.
A query "passes" if:
should_trigger is true and the skill was invoked, or
should_trigger is false and the skill was not invoked.
Running multiple times
Model behavior is nondeterministic — the same query might trigger the skill on one run but not the next. Run each query multiple times (3 is a reasonable starting point) and compute a trigger rate: the fraction of runs where the skill was invoked.
A should-trigger query passes if its trigger rate is above a threshold (0.5 is a reasonable default). A should-not-trigger query passes if its trigger rate is below that threshold.
With 20 queries at 3 runs each, that's 60 invocations. You'll want to script this. Here's the general structure — replace the claude invocation and detection logic in check_triggered with whatever your agent client provides:
#!/bin/bash
QUERIES_FILE="${1:?Usage: $0 <queries.json>}"
SKILL_NAME="my-skill"
RUNS=3
check_triggered() {
local query="$1"
claude -p "$query" --output-format json 2>/dev/null \
| jq -e --arg skill "$SKILL_NAME" \
'any(.messages[].content[]; .type == "tool_use" and .name == "Skill" and .input.skill == $skill)' \
> /dev/null 2>&1
}
count=$(jq length "$QUERIES_FILE")
for i in $(seq 0 $((count - 1))); do
query=$(jq -r ".[$i].query" "$QUERIES_FILE")
should_trigger=$(jq -r ".[$i].should_trigger" "$QUERIES_FILE")
triggers=0
for run in $(seq 1 $RUNS); do
check_triggered "$query" && triggers=$((triggers + 1))
done
jq -n \
--arg query "$query" \
--argjson should_trigger "$should_trigger" \
--argjson triggers "$triggers" \
--argjson runs "$RUNS" \
'{query: $query, should_trigger: $should_trigger, triggers: $triggers, runs: $runs, trigger_rate: ($triggers / $runs)}'
done | jq -s '.'
If your agent client supports it, you can stop a run early once the outcome is clear — the agent either consulted the skill or started working without it. This can significantly reduce the time and cost of running the full eval set.
Avoiding overfitting with train/validation splits
If you optimize the description against all your queries, you risk overfitting — crafting a description that works for these specific phrasings but fails on new ones.
The solution is to split your query set:
- Train set (~60%): the queries you use to identify failures and guide improvements.
- Validation set (~40%): queries you set aside and only use to check whether improvements generalize.
Make sure both sets contain a proportional mix of should-trigger and should-not-trigger queries — don't accidentally put all the positives in one set. Shuffle randomly and keep the split fixed across iterations so you're comparing apples to apples.
If you're using a script like the one above, you can split your queries into two files — train_queries.json and validation_queries.json — and run the script against each one separately.
The optimization loop
- Evaluate the current description on both train and validation sets. The train results guide your changes; the validation results tell you whether those changes are generalizing.
- Identify failures in the train set: which should-trigger queries didn't trigger? Which should-not-trigger queries did?
- Only use train set failures to guide your changes — whether you're revising the description yourself or prompting an LLM, keep validation set results out of the process.
- Revise the description. Focus on generalizing:
- If should-trigger queries are failing, the description may be too narrow. Broaden the scope or add context about when the skill is useful.
- If should-not-trigger queries are false-triggering, the description may be too broad. Add specificity about what the skill does not do, or clarify the boundary between this skill and adjacent capabilities.
- Avoid adding specific keywords from failed queries — that's overfitting. Instead, find the general category or concept those queries represent and address that.
- If you're stuck after several iterations, try a structurally different approach to the description rather than incremental tweaks. A different framing or sentence structure may break through where refinement can't.
- Check that the description stays under the 1024-character limit — descriptions tend to grow during optimization.
- Repeat steps 1-3 until all train set queries pass or you stop seeing meaningful improvement.
- Select the best iteration by its validation pass rate — the fraction of queries in the validation set that passed. Note that the best description may not be the last one you produced; an earlier iteration might have a higher validation pass rate than later ones that overfit to the train set.
Five iterations is usually enough. If performance isn't improving, the issue may be with the queries (too easy, too hard, or poorly labeled) rather than the description.
The [`skill-creator`](https://github.com/anthropics/skills/tree/main/skills/skill-creator) Skill automates this loop end-to-end: it splits the eval set, evaluates trigger rates in parallel, proposes description improvements using Claude, and generates a live HTML report you can watch as it runs.
Applying the result
Once you've selected the best description:
- Update the
description field in your SKILL.md frontmatter.
- Verify the description is under the 1024-character limit.
- Verify the description triggers as expected. Try a few prompts manually as a quick sanity check. For a more rigorous test, write 5-10 fresh queries (a mix of should-trigger and should-not-trigger) and run them through the eval script — since these queries were never part of the optimization process, they give you an honest check on whether the description generalizes.
Before and after:
description: Process CSV files.
description: >
Analyze CSV and tabular data files — compute summary statistics,
add derived columns, generate charts, and clean messy data. Use this
skill when the user has a CSV, TSV, or Excel file and wants to
explore, transform, or visualize the data, even if they don't
explicitly mention "CSV" or "analysis."
The improved description is more specific about what the skill does (summary stats, derived columns, charts, cleaning) and broader about when it applies (CSV, TSV, Excel; even without explicit keywords).