Claude Code — Part 5 — Creating a Custom Skill
A Skill packages a repeatable procedure so it runs on demand instead of being re-explained in chat, and a working Windows Event Log triage skill to build one for real.
SKILL.md file inside it. Claude loads the description into every session and only loads the full instructions when the skill actually runs.
The one required file. YAML frontmatter tells Claude when to use it, markdown content tells it what to do.
Invoke a skill directly by typing its name, or let Claude load it automatically when relevant.
Unlike CLAUDE.md, a skill’s full body costs nothing until the moment it is actually used.
Introduction
Part 4 covered CLAUDE.md: facts and standing rules that should be true in every session. A Skill is for the other kind of thing you keep repeating, a procedure. If you find yourself pasting the same checklist or the same multi-step instructions into chat every time you do a particular task, that is the signal to build a Skill instead.
What Is a Skill?
A Skill is a directory containing a SKILL.md file: YAML frontmatter that tells Claude when to use it, followed by markdown instructions for what to do when it runs. Claude can invoke it automatically when your request matches the description, or you can invoke it directly by typing /skill-name.
Think of a Skill as a runbook you hand to whoever is on call. CLAUDE.md is the standing knowledge everyone should already have. A Skill is the specific procedure you pull out when the specific situation comes up, and you would rather not re-type it from memory under pressure.
Where Skills Live
| Location | Path (Windows) | Applies To |
|---|---|---|
| Personal | %USERPROFILE%\.claude\skills\<name>\SKILL.md | All your projects |
| Project | .claude\skills\<name>\SKILL.md | This project only, shared via source control |
| Enterprise | Managed settings | All users in the organisation |
A personal skill under your user profile is available in every project you work in, useful for something like a log-triage procedure you want regardless of which script library you happen to be sitting in. A project skill lives in .claude\skills\ and is shared with your team through source control, useful for a procedure specific to that particular codebase or toolkit.
Anatomy of a SKILL.md
Only description is really required in practice, since it is what Claude matches against your request to decide whether to load the skill. A handful of other frontmatter fields cover most day-to-day needs.
| Field | What It Does |
|---|---|
description | What the skill does and when to use it. Put the key use case first, this is what Claude matches against your request. |
disable-model-invocation | Set to true so only you can trigger it with /name, never Claude on its own. Use for anything with side effects. |
allowed-tools | Tools Claude can use without an extra approval prompt while this skill is active. |
argument-hint | Autocomplete hint for expected arguments, such as [log-name]. |
shell | Which shell runs inline !`command` blocks. Defaults to bash; set to powershell on Windows. |
shell: powershell requires the CLAUDE_CODE_USE_POWERSHELL_TOOL environment variable set to 1. Without it, inline commands in a skill still run through Bash.
A Worked Example: Event Log Triage
This skill pulls the last 50 System log entries, filters to errors and warnings, and asks Claude to summarise what needs attention, the same pattern as piping a log file into a one-off query, but saved as a reusable procedure.
# Save to %USERPROFILE%\.claude\skills\check-eventlog\SKILL.md
---
name: check-eventlog
description: Summarizes recent errors and warnings from a Windows Event Log and flags anything worth investigating. Use when asked to check the event log, review recent errors, or find out what broke.
shell: powershell
---
## Recent System log errors and warnings
!`Get-WinEvent -LogName System -MaxEvents 50 | Where-Object { $_.LevelDisplayName -in 'Error','Warning' } | Select-Object TimeCreated, Id, LevelDisplayName, Message | Format-List`
## Instructions
Summarize the events above in a short list grouped by likely cause. Flag anything that repeats more than twice, and call out any event ID that commonly indicates a hardware, disk, or service failure. If there are no errors or warnings, say the log is clean.
The !`command` syntax runs before Claude ever sees the skill content. Claude Code executes the PowerShell command, drops the actual output in place of the placeholder, and only then hands the rendered file to Claude. Claude is reasoning over real, current event log data, not guessing at what a System log might contain.
Testing It
Save the file, then test both invocation paths from inside a session.
what broke on this server recently?
That should trigger the skill automatically, since it matches the description. To run it explicitly instead:
/check-eventlog
Controlling Who Invokes It
By default, both you and Claude can trigger a skill. For anything with a real side effect, restricting invocation to only yourself is worth doing deliberately.
---
name: restart-print-spooler
description: Restart the Print Spooler service
disable-model-invocation: true
---
Restart the Print Spooler service and confirm it returns to a Running state.
With disable-model-invocation: true set, Claude never decides on its own that now is a good time to restart a service. You still can, by typing /restart-print-spooler whenever you actually want it to happen.
Final Thoughts
Skills are one of the easiest ways to get consistent, repeatable behaviour out of Claude Code, and building one does not require anything beyond a markdown file and a description that says clearly what it is for. Start with a procedure you already run manually and know well, since that is the easiest one to get right the first time.
A single skill running inline in your own session covers most needs. The next step up is delegating a task to a separate agent entirely, one that runs in its own context and reports back instead of cluttering your main conversation.
disable-model-invocation: true to anything with a real side effect.
Next, we look at subagents: running a task in an isolated context so a deep investigation does not fill up your main session with intermediate noise.