ES

Claude Skills, from the basics to building your own

Leo G.8 minLeer en español

A tool drawer with many different wrenches, each one a different size.
A tool drawer with many different wrenches, each one a different size.

You explain to Claude Code, every new session, how your team writes commit messages. Or how a PR summary is supposed to sound. Or your database schema, again. Every conversation starts from zero, so that explanation repeats.

A Skill is how you stop repeating it: a folder with instructions that Claude reads on its own, only when the task needs it, without taking up any space in the context in the meantime. You write it once and it’s there in every session after that.

Using one that already exists

Claude Code ships with a few out of the box — /run, /code-review, /doctor, /loop, among others — and you can see all of them with:

/skills

They’re used two ways. Type the request in plain language, and let Claude decide on its own whether it applies:

What did I change in this file?

Or invoke it directly, by name, like a command:

/summarize-changes

Both end up doing the same thing if the Skill is well written: the difference is whether you decide or Claude decides that it’s needed.

How Claude decides when to use one

This is why installing a lot of Skills doesn’t make a conversation slow or expensive: they don’t all load in full up front. They load in three levels, each more expensive than the last, and it only moves up a level if it needs to.

The three levels at which Claude reads a Skill 01 Metadata name + description always, ~100 tokens 02 Instructions the SKILL.md body on trigger, <5,000 tokens 03 Resources and scripts reference files, code only if read, 0 until then matches the request if SKILL.md mentions it
The name and description of every installed Skill are always in the context. Everything else is read only when needed, with bash, the same way you'd open any other file.

The field that decides everything is the description: it’s the only thing Claude compares against your request to choose which Skill to use, so it has to say two things — what it does and when to use it — not just the name. This one is good, taken from the official docs:

description: Extract text and tables from PDF files, fill forms, merge
  documents. Use when working with PDF files or when the user mentions
  PDFs, forms, or document extraction.

And these are bad, because they’re vague — Claude has nothing to decide with, whether they apply to your request or not:

description: Helps with documents
description: Processes data
description: Does stuff with files

Building your first Skill, step by step

Let’s build one that summarizes uncommitted changes, so you don’t have to ask for it by hand every time. First, the folder:

mkdir -p ~/.claude/skills/summarize-changes

~/.claude/skills/ is the personal folder: whatever you put there is available in all your projects, on this machine. If instead you want it available only to whoever clones this repository, it goes in .claude/skills/ inside the project itself, and gets checked into version control.

Inside it, a single file, SKILL.md:

---
description: Summarizes uncommitted changes and flags anything risky. Use when the user asks what changed, wants a commit message, or asks to review their diff.
---

## Current changes

!`git diff HEAD`

## Instructions

Summarize the changes above in two or three bullet points, then list any
risks you notice such as missing error handling, hardcoded values, or tests
that need updating. If the diff is empty, say there are no uncommitted
changes.

The line starting with ! isn’t text: it’s a command that runs before Claude sees anything, and its result — the real diff of your project at that moment — replaces that line. If the command fails, the whole Skill is cancelled right there, so it’s worth it being something reliable.

You test it both ways from before: standing in a repository with some uncommitted change, you type “what did I change?” and it should trigger on its own, or you type /summarize-changes to force it.

The frontmatter, from essential to advanced

The only two required fields are name and description. name only accepts lowercase letters, numbers, and hyphens, up to 64 characters, and can’t use the words “claude” or “anthropic”. description can’t be empty and has a maximum of 1,024 characters.

Everything else is optional, and each one solves something specific:

Field What it’s for
disable-model-invocation: true Only triggers by hand, with /name — Claude never picks it on its own
user-invocable: false The opposite: only Claude uses it, doesn’t show up in the / menu
allowed-tools: Bash(git add *) Pre-approves specific tools ahead of time, without asking every time
context: fork Runs it in a separate subagent, without the conversation history
argument-hint: [issue-number] The hint text that shows up when autocompleting in the / menu

For example, a deployment Skill makes sense with manual invocation only — you don’t want Claude deciding on its own when to deploy — and with the shell tools already approved, because they’re always the same:

---
name: deploy
description: Deploy the application to production
disable-model-invocation: true
allowed-tools: Bash(npm run build) Bash(npm run test) Bash(git *)
---

Advanced: a Skill with its own script

When the task is always the same, it’s better for a script to handle it than for Claude to write new code every time: it’s more reliable, and the script’s code never enters the context — only what it prints does. This is the structure of a Skill that builds a visual map of a repository:

~/.claude/skills/codebase-visualizer/
├── SKILL.md
└── scripts/
    └── visualize.py

SKILL.md doesn’t explain how the script works: it tells Claude to run it, and what to do with the result.

---
name: codebase-visualizer
description: Generate an interactive collapsible tree visualization of your codebase. Use when exploring a new repo, understanding project structure, or identifying large files.
allowed-tools: Bash(python3 *)
---

# Codebase Visualizer

Generate an interactive HTML tree view that shows your project's file structure.

## Usage

```bash
python3 ${CLAUDE_SKILL_DIR}/scripts/visualize.py .
```

This creates `codebase-map.html` in the current directory and opens it in
your browser.

${CLAUDE_SKILL_DIR} is a variable Claude resolves on its own, with that Skill’s exact folder — so the script gets found no matter which project you’re standing in when you use it.

How to write a good description

We already saw the good example and the bad ones. Two more rules, also from the official guide:

Write it in third person. The description gets inserted as-is into the system instructions, so if it’s in first person (“I can help you with…”) it sounds out of place there and confuses more than it helps.

Name the trigger, not just the action. “Analyzes data” doesn’t say when to use it. “Analyzes spreadsheets, builds pivot tables and charts. Use it with Excel files, spreadsheets, or .xlsx data” does: it gives Claude concrete words to match against the request.

One thing to check before installing someone else’s

A Skill gives Claude instructions and, if it has them enabled, tools to carry them out. A malicious one can get Claude to call tools or run code in ways that have nothing to do with what the Skill claims to do.

The official recommendation is simple: use only your own Skills or Anthropic’s, and if you need one from another source, audit the whole thing first — SKILL.md, any script, any image — looking for network calls, file access, or anything that doesn’t match what it says it does.

In this blog’s article about Archify we installed a real Skill, from a public repository, and before running anything we read the whole SKILL.md to understand exactly what it expected from us. It’s the same step, applied.

Where each Skill lives

Besides personal and project, there are a couple more places, and when two Skills share a name, whichever is higher on this list wins:

Location Path Scope
Enterprise centralized org configuration every user
Personal ~/.claude/skills/<name>/ you, in any project on this machine
Project .claude/skills/<name>/ whoever clones this repository
Nested <subfolder>/.claude/skills/<name>/ sessions inside that subfolder, with /subfolder:name
Plugin <plugin>/skills/<name>/ wherever the plugin is enabled

To confirm a Skill’s YAML is well-formed before sharing it, claude plugin validate checks it without needing to invoke it:

claude plugin validate ~/.claude/skills/my-skill

Comments