You’ve heard about agent skills. Maybe you’ve installed a few. But building your own? That’s where most people stall out โ not because it’s hard, but because nobody walks through the actual process from empty directory to working skill.
This tutorial fixes that. In about 15 minutes, you’ll build a real, functional agent skill that you can use immediately and publish to AgentSkillExchange or share with your team. No prior skill-building experience required โ just a text editor and a terminal.
What We’re Building
We’ll create a commit message generator skill. When activated, it reads your staged Git changes and writes a well-formatted conventional commit message. It’s simple enough to build quickly, useful enough to actually keep, and complex enough to demonstrate every important concept.
Here’s what the finished skill does:
- Reads the output of
git diff --staged - Analyzes the type of change (feature, fix, refactor, docs, etc.)
- Generates a commit message following Conventional Commits format
- Handles edge cases like large diffs, binary files, and merge commits
By the end, you’ll understand frontmatter, description optimization, file layout, gotchas sections, and progressive disclosure โ the building blocks of every good skill.
Step 1: Create the Directory Structure
Open your terminal and set up the skeleton:
mkdir -p commit-message-generator/references
mkdir -p commit-message-generator/scripts
touch commit-message-generator/SKILL.md
Your directory looks like this:
commit-message-generator/
โโโ SKILL.md
โโโ references/
โโโ scripts/
Three directories, one file. That’s the standard layout from the AgentSkills.io specification:
- SKILL.md โ the core file (required). Contains frontmatter metadata and instructions.
- references/ โ supplementary docs loaded on demand (optional). Keeps SKILL.md lean.
- scripts/ โ executable code for deterministic operations (optional). Bash, Python, whatever you need.
Some skills also include an assets/ directory for templates, icons, or other non-code files, and a config.json for user-specific settings. We won’t need those for this skill, but know they exist.
Step 2: Write the Frontmatter
Open SKILL.md and start with the YAML frontmatter. This is the metadata block that agents read before deciding whether to load your skill:
---
name: commit-message-generator
description: >
Generate conventional commit messages from staged Git changes.
Use when: "write a commit message", "generate commit msg",
"what should I commit this as", "help me commit",
"conventional commit for these changes".
NOT for: writing changelogs (use changelog-generator),
squashing commits, or interactive rebase.
---
Two fields. Both required. Both critical. Here’s what matters about each:
The name field
Must match your directory name exactly. Lowercase, hyphens for spaces. The agent uses this as the skill’s identifier, so commit-message-generator the directory needs commit-message-generator the name.
The description field
This is the most important text in your entire skill. It’s not a summary for humans โ it’s a trigger description for the model. The agent reads every installed skill’s description to decide which one to activate for a given request.
Notice the pattern: we include the exact phrases someone might type (“write a commit message”, “generate commit msg”), and we explicitly exclude what the skill is not for. As Thariq from Anthropic explained, the description field determines whether your skill ever gets used. A vague description means the agent can’t tell when to activate it.
Common mistake: writing description: A tool for generating commit messages. That’s too generic. Include trigger phrases, error messages users might paste, and explicit exclusions.
Step 3: Write the Core Instructions
Below the frontmatter, add the skill body in Markdown. This is what the agent reads after deciding to activate your skill:
# Commit Message Generator
Generate well-structured conventional commit messages from staged Git changes.
## Workflow
1. Run `git diff --staged --stat` to get an overview of changed files
2. Run `git diff --staged` to see actual changes (limit to first 200 lines if diff is large)
3. Determine the change type from the diff content:
- `feat`: new functionality
- `fix`: bug fix
- `refactor`: code restructure without behavior change
- `docs`: documentation only
- `test`: adding or updating tests
- `chore`: build process, dependencies, config
- `style`: formatting, whitespace, semicolons
- `perf`: performance improvement
- `ci`: CI/CD configuration
4. Identify the scope from the primary directory or module changed
5. Write a subject line: `type(scope): imperative description` (max 72 chars)
6. If the change is non-trivial, add a body explaining **why**, not what
7. Present the message and ask for confirmation before committing
## Output Format
```
type(scope): short imperative description
Optional body explaining motivation and context.
Wrap at 72 characters per line.
Optional footer for breaking changes or issue references:
BREAKING CHANGE: description
Closes #123
```
A few things to notice here:
- Numbered steps, not prose. Agents parse structured instructions more reliably than paragraphs of text.
- Specific commands. We tell the agent exactly what to run (
git diff --staged --stat), not “check the staged changes.” - Concrete output format. Including a template removes ambiguity about what the result should look like.
- Flexibility where it matters. Step 6 says “if the change is non-trivial” โ the agent decides, not a rigid rule.
This is the balance Anthropic’s team recommends: provide enough structure that the agent doesn’t waste time figuring out the workflow, but enough flexibility that it can adapt to unusual situations.
Step 4: Add the Gotchas Section
If you read our post on writing skills that actually work, you know the gotchas section is the highest-signal content in any skill. It captures the failure modes that an agent will hit repeatedly โ the things it’ll get wrong without explicit guidance.
Add this below the workflow:
## Gotchas
- `git diff --staged` returns nothing if no files are staged. Check for empty
output FIRST and tell the user to stage files with `git add` before asking
for a commit message. Do not guess or generate a message from unstaged changes.
- Binary files (images, compiled assets) appear in `--stat` but have no readable
diff. Mention them in the commit body ("Added logo.png") but don't try to
describe their contents from diff output.
- For diffs longer than 200 lines, read `--stat` for the overview and only read
the full diff of the 3 most-changed files. Summarizing a 2,000-line diff
wastes context window and produces vague commit messages.
- The subject line MUST be 72 characters or fewer. Agents consistently generate
80-100 character subjects without this constraint. Count characters explicitly.
- Scope should be a single word. "api" not "api-endpoints". "auth" not
"authentication-module". If changes span multiple scopes, use the parent
directory or omit scope entirely: `feat: add user preferences`.
- Do NOT start the subject with a capital letter after the colon.
Wrong: `fix(auth): Fix token expiry`
Right: `fix(auth): fix token expiry`
- Merge commits and initial commits have no meaningful diff. For merge commits,
use `merge: branch-name into target`. For initial commits, use
`chore: initial commit` with a body listing the project structure.
Every entry here comes from a real failure pattern. Agents genuinely do generate 90-character subject lines. They genuinely do try to read 2,000-line diffs. They genuinely do capitalize after the colon. If you’ve used an AI coding assistant for commits, you’ve probably seen every one of these mistakes.
Start with 3-5 gotchas when you first create a skill. Add more as you discover new failure modes through actual use. A good gotchas section grows over time.
Step 5: Add a Helper Script
For tasks that need deterministic reliability, include a script rather than relying on the agent to write code every time. Create scripts/staged-summary.sh:
#!/bin/bash
# scripts/staged-summary.sh
# Quick summary of staged changes for commit message generation
STAT=$(git diff --staged --stat 2>&1)
if [ -z "$STAT" ]; then
echo "ERROR: No staged changes found. Run 'git add' first."
exit 1
fi
echo "=== Staged Files ==="
echo "$STAT"
echo ""
echo "=== Diff (first 200 lines) ==="
git diff --staged | head -200
TOTAL_LINES=$(git diff --staged | wc -l)
if [ "$TOTAL_LINES" -gt 200 ]; then
echo ""
echo "[... truncated: $TOTAL_LINES total lines. Showing first 200.]"
fi
Make it executable:
chmod +x commit-message-generator/scripts/staged-summary.sh
Now update your SKILL.md workflow to reference the script:
## Workflow
1. Run `scripts/staged-summary.sh` to get the staged diff overview
- If it prints "No staged changes found", tell the user to stage files first
2. Analyze the output to determine change type and scope
...
Scripts provide three advantages over inline instructions: they’re deterministic (same input, same output), token-efficient (the agent runs the script instead of writing equivalent code), and testable (you can run them yourself to verify behavior).
Step 6: Add Reference Documentation
If your skill has detailed reference material โ API docs, style guides, extensive examples โ put it in references/ instead of bloating SKILL.md. This is progressive disclosure: the agent loads your core instructions first, and pulls in reference files only when it needs them.
Create references/conventional-commits.md:
# Conventional Commits Reference
## Type Prefixes (with examples)
| Type | Use When | Example |
|------|----------|---------|
| feat | New user-facing functionality | feat(cart): add quantity selector |
| fix | Bug fix | fix(auth): handle expired refresh tokens |
| refactor | Internal restructure, no behavior change | refactor(db): extract query builder |
| docs | Documentation changes only | docs(api): add rate limit section |
| test | Adding or modifying tests | test(cart): add edge case for empty cart |
| chore | Build, deps, config, tooling | chore(deps): bump express to 4.19 |
| style | Formatting, whitespace, linting | style: fix indentation in utils |
| perf | Performance improvement | perf(query): add index on user_id |
| ci | CI/CD pipeline changes | ci: add Node 22 to test matrix |
## Breaking Changes
Add `BREAKING CHANGE:` footer or `!` after type:
```
feat(api)!: change authentication to OAuth2
BREAKING CHANGE: Bearer token format changed from JWT to opaque tokens.
Migration guide: https://docs.example.com/migrate-auth
```
## Multi-Scope Changes
When a commit touches multiple areas equally, either:
- Omit scope: `feat: add dark mode support`
- Use the parent scope: `refactor(ui): reorganize component structure`
- Split into multiple commits (preferred when changes are separable)
In your SKILL.md, add a pointer:
## Reference
For detailed type definitions and examples, see `references/conventional-commits.md`.
The agent reads this reference file only when it encounters an ambiguous case โ say, deciding between refactor and chore for a dependency version bump. Most of the time, the core instructions are enough, and those reference tokens stay available for actual work.
Step 7: Test It
Before publishing, actually use the skill. The fastest way to test depends on your agent platform:
Claude Code / OpenClaw:
# Copy to your skills directory
cp -r commit-message-generator/ ~/.openclaw/workspace/skills/
# Or for Claude Code
cp -r commit-message-generator/ .claude/skills/
Quick smoke test:
- Stage some changes in a Git repo:
git add -A - Ask your agent: “Write a commit message for my staged changes”
- Check: Does it run the script? Does the subject line stay under 72 chars? Does it pick the right type?
- Try an edge case: stage a binary file, or create a 500-line diff
Testing isn’t optional. Thariq’s team at Anthropic builds gotchas sections from test results โ they run the skill, watch it fail, and add the failure to the gotchas. Your first test run will almost certainly reveal something your instructions didn’t cover. That’s the point.
The Complete SKILL.md
Here’s the finished file, all sections assembled:
---
name: commit-message-generator
description: >
Generate conventional commit messages from staged Git changes.
Use when: "write a commit message", "generate commit msg",
"what should I commit this as", "help me commit",
"conventional commit for these changes".
NOT for: writing changelogs (use changelog-generator),
squashing commits, or interactive rebase.
---
# Commit Message Generator
Generate well-structured conventional commit messages from staged
Git changes.
## Workflow
1. Run `scripts/staged-summary.sh` to get the staged diff overview
- If it prints "No staged changes found", tell the user to
stage files first
2. Determine the change type from the diff content:
- `feat`, `fix`, `refactor`, `docs`, `test`, `chore`,
`style`, `perf`, `ci`
3. Identify the scope from the primary directory or module changed
4. Write a subject line: `type(scope): imperative description`
(max 72 chars)
5. If the change is non-trivial, add a body explaining **why**
6. Present the message and ask for confirmation before committing
## Output Format
```
type(scope): short imperative description
Optional body explaining motivation and context.
Wrap at 72 characters per line.
BREAKING CHANGE: description (if applicable)
Closes #123
```
## Gotchas
- `git diff --staged` returns nothing if no files are staged.
Check FIRST and tell the user to run `git add`.
- Binary files show in `--stat` but have no readable diff.
Mention them in the body, don't describe their contents.
- For diffs over 200 lines, use `--stat` overview and read
only the 3 most-changed files in full.
- Subject line MUST be โค72 characters. Count explicitly.
- Scope is a single word: "api" not "api-endpoints".
- Do NOT capitalize after the colon: `fix(auth): fix token`
not `fix(auth): Fix token`.
- Merge commits: use `merge: branch into target`.
Initial commits: use `chore: initial commit`.
## Reference
For detailed type definitions, breaking change format, and
multi-scope guidance, see `references/conventional-commits.md`.
Under 60 lines. No filler. Every line either tells the agent what to do or prevents a specific failure. That’s what a good skill looks like.
Step 8: Publish It
Once you’ve tested and refined your skill, you have several options for sharing it:
Team distribution: Check the skill directory into your repo under .claude/skills/ or .openclaw/skills/. Anyone who clones the repo gets the skill automatically.
ClawHub: Publish to the ClawHub marketplace where others can install with a single command:
clawhub publish commit-message-generator/
AgentSkillExchange: Submit to ASE for review and listing. We verify skills against quality standards โ including checking for a real gotchas section, proper description optimization, and progressive disclosure where appropriate.
Common Mistakes to Avoid
After reviewing hundreds of skill submissions on AgentSkillExchange, these are the patterns we see most often:
- Restating common knowledge. Your agent already knows what Git is and how commits work. The skill should cover what it doesn’t know: your specific formatting rules, edge cases, and failure modes.
- Dumping everything into SKILL.md. If your file is over 500 lines, split it. Use
references/for detailed documentation andscripts/for executable code. The agent loads SKILL.md into its context window on activation โ every unnecessary line competes with the actual work. - Writing rigid step-by-step scripts. “First do A, then do B, then do C” breaks when the agent encounters something unexpected. Provide goals, constraints, and decision frameworks instead. Let the agent use judgment โ that’s what it’s good at.
- Skipping the gotchas section. This is the highest-value content in any skill. Without it, your skill works for the exact scenario you tested and fails everywhere else.
- Vague descriptions.
description: A skill for Git operationswill never activate because the agent can’t distinguish it from dozens of other Git-related skills. Include specific trigger phrases and exclusions.
What Makes a Skill Worth Publishing
Before you hit publish, run through this checklist:
- โ Does it contain non-obvious information? If the agent can figure it out without the skill, the skill doesn’t need to exist.
- โ Is the description field optimized for activation? Include trigger phrases, common phrasings, and explicit NOT-for exclusions.
- โ Does it have a gotchas section? At least 3 entries, each from a real failure mode.
- โ Is the file structure right? Core instructions in SKILL.md, details in references/, scripts in scripts/.
- โ Have you actually tested it? Run it against real tasks, including edge cases.
- โ Is it portable? No hardcoded paths, API keys, or team-specific values in the skill itself. Use config.json for anything environment-specific.
Frequently Asked Questions
How long should a SKILL.md file be?
Keep it under 500 lines. The agent loads the entire file into context on activation, so every line competes with the actual work. Use references/ for anything the agent only needs occasionally.
Can a skill reference other skills?
Yes. Skills can reference other skills by name in their description or instructions. For example, our commit message skill could say “for changelog generation, use the changelog-generator skill” โ and the agent will switch skills when appropriate.
Do I need to write skills differently for Claude Code vs. OpenClaw vs. Codex?
The core SKILL.md format works across platforms. The AgentSkills.io standard defines a portable format that any compatible agent can read. Platform-specific differences are mostly about installation paths, not skill content.
What if my skill needs API keys or credentials?
Document required environment variables in a setup section, and use a config.json for non-sensitive settings. Never hardcode credentials in the skill itself โ it makes the skill unusable for anyone else and creates a security risk if published.
Next Steps
You’ve built a working skill. Here’s where to go from here:
- Read our deep dive on skill best practices from Anthropic’s Thariq
- Explore the official Claude Code skills documentation
- Take the Anthropic Skilljar course on agent skills
- Browse existing skills on ASE to see how others structure theirs
- Read the 9 Categories of Agent Skills to find where your skill fits in the ecosystem
The skills ecosystem is growing fast โ 150+ skills on AgentSkillExchange and counting. The best time to start building was yesterday. The second best time is now. Open your terminal, create that directory, and ship something.