Building Your First Skill
Create a skill from scratch — trigger definition, instructions, testing, iteration. A real deployment skill as the example.
You know what skills are. Time to build one.
We're going to create a deployment skill from scratch: run tests, build, push to production. Real example, not a toy.
Pick a workflow worth automating
Ask yourself: what do I keep telling Claude Code to do the same way every time? That repetition is your signal. Deployment pipelines, issue-fixing workflows, code review checklists, scaffolding routines. Anything where the steps are consistent and the order matters.
For this walkthrough: deployment. Run tests, build, push, verify. Same thing every time, perfect skill candidate.
Create the skill directory
Skills live in a directory with SKILL.md as the entrypoint. Personal skills go in ~/.claude/skills/<name>/SKILL.md (available everywhere). Project skills go in .claude/skills/<name>/SKILL.md (ships with your repo).
A deploy skill is project-specific, so project location makes sense.
mkdir -p .claude/skills/deploy
touch .claude/skills/deploy/SKILL.mdWrite the SKILL.md
YAML frontmatter at the top (when and how to use the skill), markdown instructions below (what to do).
The deploy skill:
---
name: deploy
description: Deploy the application to production
disable-model-invocation: true
---Minimal frontmatter on purpose. name is what you type after the slash. description helps Claude Code understand relevance. disable-model-invocation: true means it never fires on its own. You call /deploy explicitly or it doesn't run.
The instructions go below:
Deploy $ARGUMENTS to production following these steps:
1. Run the full test suite with `npm test`. If any test fails, stop and report the failure.
2. Run `npm run build` and confirm it completes without errors.
3. Run `git push origin main` to push the latest changes.
4. Run `./scripts/deploy.sh $ARGUMENTS` to execute the deployment.
5. After deployment, run `curl -s https://api.example.com/health` and verify the response includes `"status": "ok"`.
6. Report the deployment result including the environment that was deployed.$ARGUMENTS in steps 1 and 4 gets replaced when you invoke /deploy staging. For positional arguments, use $1, $2 (or $ARGUMENTS[0], $ARGUMENTS[1]). Most skills only need the simple $ARGUMENTS.
Two more substitutions: ${CLAUDE_SESSION_ID} gives you the session identifier, and ${CLAUDE_SKILL_DIR} resolves to the absolute path of the directory containing your SKILL.md. The second one is the useful one, especially when referencing supporting files.
Add supporting files
Keep SKILL.md under 500 lines. Detailed references, checklists, templates go in separate files alongside it.
.claude/skills/deploy/
SKILL.md
checklist.md
rollback-steps.mdThen in your SKILL.md instructions, tell Claude Code about them:
Before deploying, read the pre-deploy checklist at ${CLAUDE_SKILL_DIR}/checklist.md
and follow every item. If deployment fails, follow the rollback procedure at
${CLAUDE_SKILL_DIR}/rollback-steps.md.Main instructions stay focused. Claude Code reads supporting files into its context window like any other file, so keep those concise too.
Inject dynamic context
Sometimes you want live data pulled in every time the skill runs. The ! backtick syntax runs a shell command and injects the output before Claude Code sees the instructions.
Current git status:
!`git status --short`
Deploy $ARGUMENTS to production following these steps:
...Every /deploy invocation runs git status --short first and includes the result. Great for skills that need to adapt to current repo state.
Test your skill
Open Claude Code, type /deploy staging. Watch it. Does it follow steps in order? Substitute arguments correctly? Stop on failure?
If something's off, edit SKILL.md and try again. Skills reload every invocation. No restart needed. The iteration loop is tight: edit, run, observe, adjust.
Watch for these gotchas: Claude Code skipping steps because instructions were too vague, arguments not substituting because of a typo in the variable name, the skill triggering during normal conversation because you forgot disable-model-invocation: true. That last one will drive you nuts.
A second example: fix-issue
Same pattern, different workflow. A skill that fixes GitHub issues:
---
name: fix-issue
description: Fix a GitHub issue
disable-model-invocation: true
---
Fix GitHub issue $ARGUMENTS following our coding standards.
1. Read the issue description using `gh issue view $ARGUMENTS`.
2. Understand the requirements and acceptance criteria.
3. Implement the fix in the appropriate files.
4. Write tests that verify the fix.
5. Create a commit with a message referencing the issue number.The pattern scales to anything you can describe in steps.
Try it
Create a scaffolding skill. Make .claude/skills/new-feature/, write a SKILL.md that takes a feature name as $ARGUMENTS, and have it create a directory structure, boilerplate component, and test file. Set disable-model-invocation: true. Invoke with /new-feature user-profile. If the output is wrong, tweak the instructions and run again. That tight edit-run loop is the whole workflow.
If you're explaining the same process to Claude Code more than twice, write a skill. Put it in a directory with a SKILL.md, use $ARGUMENTS for dynamic input, offload detailed references to supporting files via ${CLAUDE_SKILL_DIR}, and always start with disable-model-invocation: true. Project skills in .claude/skills/, personal skills in ~/.claude/skills/. Test by running the command and iterating until it does what you want.
Mastering Claude Code
Lesson 46 of 70