What makes a good skill
At its core, a Claude Code skill is a markdown file — SKILL.md — that gets loaded into Claude's context when you invoke it. Claude reads the file, understands the instructions, and executes accordingly. There is no runtime, no compiled binary, and no plugin API. The entire skill is a prompt.
That simplicity is also a constraint. Because SKILL.md is pure instruction, the quality of a skill depends entirely on how clearly it communicates three things:
- Focus. A skill that tries to do ten things does none of them well. Pick one job. If you find yourself writing "and also…" in the description, split it into two skills.
- Specificity. Vague instructions produce inconsistent output. Tell Claude exactly what to look at, what to produce, and in what format. The more concrete your examples, the less Claude has to guess.
- A clear trigger description. The description field in frontmatter is what Claude reads to decide whether to suggest your skill. Write it as a one-sentence answer to "when should I use this?" — not a marketing headline.
Before writing a single line, browse the existing skill directory for inspiration. Notice how the best skills are narrow, opinionated, and specific about their output format.
Skill folder structure
A publishable skill is a folder with a predictable layout. Only SKILL.md is required; everything else is optional but encouraged for larger skills.
my-skill/
├── SKILL.md ← required: the main instruction file
├── README.md ← for humans browsing GitHub or the directory
├── metadata.json ← structured metadata (name, version, tags)
├── scripts/ ← executable helpers Claude can run via Bash
│ └── check-env.sh
├── references/ ← long reference docs loaded on demand
│ └── api-schema.md
└── templates/ ← reusable output templates
└── report.md
Keep the root clean. Only files that Claude needs to read or execute belong here. Documentation for contributors goes in README.md; long reference material that would bloat the main context goes in references/. The skills.sh CLI zips the entire folder when publishing, so avoid committing secrets, node_modules, or large binaries.
Write your SKILL.md
The SKILL.md file has two parts: a YAML frontmatter block that provides machine-readable metadata, and a markdown body that provides human- and Claude-readable instructions.
Frontmatter
The three required frontmatter fields are name, description, and version. Everything else is indexed by skills.sh but not required for local use.
Body sections
Structure the body with three core sections. You can add more, but these three are the minimum for a skill that behaves consistently:
- When to Use — tell Claude (and the reader) the exact situation that should trigger this skill. Be specific about file types, project states, or commands that are in scope.
- How It Works — describe the steps Claude should follow, in order. Number them if sequence matters. Reference any scripts or templates by path.
- Output Format — describe exactly what Claude should produce: a markdown report, a JSON object, inline code edits, a shell command. Include an example if possible.
Here is a complete, annotated example for a skill that audits environment variables before a deployment:
---
name: env-audit
description: >
Audit environment variables in this project before a deployment.
Checks for missing required vars, insecure defaults, and secrets
accidentally committed to version control.
version: 1.0.0
author: your-handle
tags: [devops, security, environment]
---
# env-audit
Audit environment variables for safety and completeness before deploying.
## When to Use
Invoke this skill before any deployment command — local, staging, or production.
Use it when:
- Adding a new service that requires environment variables
- Onboarding a new developer who needs to configure their .env
- Preparing a production release checklist
Out of scope: secret rotation, CI/CD pipeline configuration.
## How It Works
1. List all `.env*` files in the project root (`.env`, `.env.local`,
`.env.example`, `.env.production`, etc.).
2. Parse each file for key-value pairs. Ignore comments and blank lines.
3. Cross-reference `.env.example` as the source of truth for required keys.
Flag any key present in `.env.example` but missing from `.env`.
4. Scan for common insecure defaults: empty values, placeholder strings
(`changeme`, `your-secret-here`, `TODO`), and keys ending in `_SECRET`
or `_KEY` that match known weak patterns.
5. Check that `.env` and `.env.local` are listed in `.gitignore`. Warn
if any `.env*` file (except `.env.example`) is tracked by git.
6. Produce the audit report (see Output Format).
## Output Format
A markdown report with three sections:
### Missing Variables
Table of keys in `.env.example` not found in `.env`, with the default
value from `.env.example` if present.
### Security Warnings
Bulleted list of insecure values or git-tracked secrets. Each item
includes the file path, key name, and reason.
### Summary
One-line verdict: "All clear — N variables checked, no issues found."
or "N issue(s) found. Review warnings above before deploying."
Notice what this example does not do: it does not try to fix the problems it finds, it does not touch CI configuration, and it does not manage secrets storage. Staying in that narrow lane is what makes it reliable.
Test your skill locally
Before publishing, verify the skill works exactly as intended on your own machine. The skills CLI supports installing directly from a local folder path.
npx skills add ./my-skill -y
The -y flag skips the confirmation prompt. After installation, open Claude Code in any project and invoke the skill with its slash command:
/env-audit
Run through your intended use cases and check whether the output matches what you specified in the Output Format section. Common iteration points:
- If Claude adds steps you did not want, make the scope boundary in "When to Use" more explicit.
- If the output format varies between runs, add a concrete example to the Output Format section.
- If Claude ignores a script in scripts/, add an explicit instruction to run it: "Execute scripts/check-env.sh using Bash and use its output in step 3."
Reinstall after each change with the same command — the CLI will overwrite the previous version. See the install guide for more detail on the installation lifecycle.
Add scripts and references
For many skills, SKILL.md alone is enough. But two optional folders let you extend what a skill can do without bloating the main instruction file.
scripts/
Put executable helpers here when the skill needs to run shell commands that are too long or complex to describe inline. Scripts are not run automatically — you must tell Claude to run them in your SKILL.md instructions. Keep scripts POSIX-compliant when possible so they work on macOS and Linux without modification.
Good candidates for scripts: environment checks, dependency version validators, file format converters, report generators that require jq or awk.
references/
Put long reference documents here when Claude needs access to a spec, schema, or policy that would be too large to paste into SKILL.md. Reference files are not loaded automatically — instruct Claude to read the relevant file when it needs it: "If the API schema is needed, read references/api-schema.md."
Good candidates for references: OpenAPI specs trimmed to relevant endpoints, internal style guide excerpts, compliance checklists, data model definitions.
Publish to skills.sh
Once you are satisfied with local testing, publishing takes three steps.
1. Push to GitHub
Create a public repository with your skill folder at the root (or as a named subfolder if you are publishing multiple skills from one repo). The README.md will be shown on your skills.sh profile page, so make it clear and useful.
2. Run npx skills publish
npx skills publish
The CLI reads your metadata.json and SKILL.md frontmatter, packages the folder into a ZIP, and submits it to skills.sh. You will be prompted to authenticate with your GitHub account on the first publish.
3. The review process
skills.sh runs an automated quality check when a skill is submitted. The check validates that SKILL.md is present, that frontmatter is complete, and that no secrets or large binary files are included in the package. Skills that pass automatically are listed within a few minutes. Skills that fail the check receive a structured error response explaining what to fix.
Manual review is only triggered for skills flagged by the automated system or reported by users. There is no approval queue for clean submissions.
FAQ
Does SKILL.md need frontmatter?
Frontmatter is strongly recommended but not strictly required. Without it, skills.sh cannot index your skill's name, version, or description, so it won't appear correctly in search results or the directory. Always include at minimum name, description, and version fields.
Can a skill call external APIs?
Yes. A skill can instruct Claude to use tools like Bash, curl, or fetch to reach external APIs. Just be explicit in your SKILL.md about what credentials or environment variables are needed. Users need to have those configured before the skill will work correctly.
How do I version my skill?
Use semantic versioning (e.g. 1.0.0, 1.1.0, 2.0.0) in the frontmatter version field and in metadata.json. Increment the patch version for small fixes, the minor version for new capabilities, and the major version for breaking changes to the interface or output format.
What's the difference between a skill and a CLAUDE.md?
CLAUDE.md is a project-level instruction file that Claude reads automatically in any project that contains it — it sets persistent context, rules, and preferences for that codebase. A skill is an on-demand module you install and invoke explicitly with a slash command. Skills are portable and shareable; CLAUDE.md is project-specific.