AI

Claude Code Skills: Turning Repeated Prompts into Reusable Tools

A practical guide to Agent Skills in Claude Code, the SKILL.md format, frontmatter fields that matter, progressive disclosure, dynamic context injection, and when a skill beats a line in CLAUDE.md.

Ansh Gupta7 min read
Fig. 14AI

There is a moment in every project where you notice you have pasted the same paragraph into a chat for the fourth time. Maybe it is your release checklist. Maybe it is the seven things you always want reviewed before a PR goes up. Maybe it is the exact incantation for your deploy.

That paragraph wants to be a skill.

What a skill actually is

A skill is a folder with a SKILL.md file in it. The file has YAML frontmatter that tells Claude when the skill is relevant, and a markdown body containing the instructions to follow when it runs.

.claude/skills/pr-review/
└── SKILL.md
---
description: Reviews staged changes against our frontend conventions. Use before opening a PR, or when the user asks for a review.
---

## Instructions

Review the staged diff against these rules:

1. Every user-facing string goes through `src/i18n/` and exists in all six locales.
2. No new animation libraries. framer-motion and GSAP are already installed.
3. No `any` in TypeScript. Prefer `unknown` plus a narrowing check.
4. Tailwind tokens only. No raw hex values outside `globals.css`.

Report findings most severe first. If nothing is wrong, say so in one line.

Two ways it runs: you type /pr-review, or Claude notices the description matches what you asked for and loads it on its own.

The property that makes skills worth using

Here is the thing that makes skills structurally better than the alternative.

Everything in CLAUDE.md is loaded into context at the start of every session and costs tokens on every turn, whether or not it is relevant. A skill's body loads only when the skill is actually invoked. Until then, only the description is visible.

That means a 400-line reference document costs almost nothing until the moment you need it.

So the rule of thumb is simple:

  • A fact that is always trueCLAUDE.md. ("This project uses the Pages Router.")
  • A procedure you sometimes run → a skill. ("Here are the eleven steps of our release process.")

If a section of your CLAUDE.md has grown into a procedure rather than a fact, it has outgrown the file.

Where skills live

LocationPathApplies to
Personal~/.claude/skills/<name>/SKILL.mdAll your projects
Project.claude/skills/<name>/SKILL.mdThat project only
Plugin<plugin>/skills/<name>/SKILL.mdWherever the plugin is enabled

Project skills get committed, so your whole team gets them. Personal skills are your own habits and follow you between repos. Plugin skills are namespaced as plugin-name:skill-name, so they cannot collide with yours.

Worth knowing: .claude/commands/deploy.md and .claude/skills/deploy/SKILL.md both create /deploy and work the same way. Custom commands were merged into skills. Existing commands/ files keep working; skills just add the extra capabilities below.

Frontmatter that earns its place

Every field is optional. Only description is genuinely recommended, because that is what Claude uses to decide whether the skill is relevant. Put the key use case first: the description is truncated at 1,536 characters in the listing.

The fields I reach for most:

---
name: db-migrate
description: Generates and applies a database migration. Use when the user changes the Prisma schema or asks for a migration.
argument-hint: [migration-name]
allowed-tools: Read Grep Bash
disable-model-invocation: true
model: sonnet
effort: low
---

allowed-tools pre-approves tools for the turn that invokes the skill, so a routine workflow does not generate five permission prompts. The grant clears on your next message, which is the right default.

disable-model-invocation: true stops Claude loading the skill on its own. Use it for anything with side effects, deploys especially. You want those triggered deliberately, by a human typing /deploy, not inferred from a sentence that happened to mention shipping.

model and effort override the session settings while the skill runs. A formatting skill does not need your most expensive model; a gnarly migration analysis might want more. See models and effort levels for how to pick.

paths limits when a skill activates to files matching a glob. In a monorepo this stops your mobile skills firing while you are working on the web app.

Dynamic context injection

This is the feature that makes skills feel less like a saved prompt and more like a tool.

A line beginning with !`command` runs the command and substitutes its output into the skill content before Claude reads it.

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

## Current changes

!`git diff HEAD`

## Instructions

Summarize the changes above in two or three bullets, then list risks:
missing error handling, hardcoded values, tests that need updating.
If the diff is empty, say there are no uncommitted changes.

Claude does not have to decide to run git diff, and cannot forget. The instructions arrive with the actual diff already inlined. Grounding by construction rather than by hope.

Progressive disclosure with supporting files

A skill directory can hold more than SKILL.md. This is how you keep a skill small while giving it access to a lot of reference material.

design-system/
├── SKILL.md          # overview and navigation
├── tokens.md         # the full token table, loaded on demand
├── components.md     # component API reference
└── scripts/
    └── audit.py      # executed, never loaded into context

SKILL.md stays a map. It says what is in each file and when to open it, and Claude reads the detailed file only if the task needs it. The Python script is run, not read, so its length costs nothing at all.

This is the pattern that lets a skill encode genuinely large amounts of knowledge without paying for it up front.

Running a skill in a subagent

Set context: fork and the skill runs in a forked subagent with its own context window, returning only the result.

---
description: Audits the whole repo for unused exports and dead files.
context: fork
agent: Explore
---

Use this when the skill's work is verbose but its answer is short. A dependency audit reads hundreds of files and concludes with a list of nine. There is no reason for those hundreds of files to end up in your main conversation.

When a skill is the wrong tool

Some honesty about the limits.

Do not wrap a single command in a skill. If it is yarn build, just type yarn build. A skill that saves you four keystrokes is negative value once you account for maintaining it.

Do not encode something that changes weekly. A stale skill is worse than no skill, because it is confidently wrong and nobody remembers to check it.

Do not use a skill for a fact. Facts go in CLAUDE.md. Skills are for procedures.

Watch out for descriptions that are too broad. A skill described as "helps with code" will fire constantly and get in the way. If a skill triggers too often, the description is the thing to fix, not the body.

Getting started

Pick the thing you have explained three times this month. Write it down in a SKILL.md. Use it for a week and edit it every time it gets something wrong.

That iteration loop is the whole point. A skill is not documentation you write once. It is a place to put corrections so you stop having to repeat them, which is the same reason we write down conventions for humans.

Next: MCP servers for connecting Claude Code to systems outside your repo, and subagents and hooks for the automation layer around it.

  • #Claude Code
  • #AI
  • #Agent Skills
  • #Developer Tools
  • #Automation
AG

About Ansh

Frontend engineer with 4+ years building scalable SaaS products, design systems, CRM, analytics and omnichannel platforms.

More about me
02

Related reading