Magic Tools
Claude GuidesBy CooconJuly 28, 2026327 views3 min read

Claude Code Skills: Turn Repeated Workflows into a Slash Command with SKILL.md

If you find yourself giving Claude Code the same long instruction every week — "pull the data first, then format the report like this, and watch out for these three gotchas" — what you need is not a better prompt. It's a Skill.

A Skill is a reusable instruction package for Claude Code: write a workflow into a SKILL.md file in a conventional directory, and you can invoke it manually with /skill-name or let Claude load it automatically when it recognizes a matching task. Skills solve the "expert knowledge never gets captured" problem: the workflow you spent hours refining now travels with the project, available to every teammate and every fresh session.

The file structure: one folder, one SKILL.md

A minimal skill looks like this:

.claude/skills/
└── deploy-check/
    └── SKILL.md

SKILL.md has two parts — frontmatter and body:

---
name: deploy-check
description: Pre-deploy checklist. Use when the user says "ready to deploy",
  "pre-release check", or asks to ship.
---

Run these checks in order. Stop and report if any step fails:

1. Run `npm run typecheck` and confirm there are no type errors
2. Run `npm run build` and confirm the build passes
3. Check git status and list uncommitted files
4. Confirm the version number in CHANGELOG has been bumped

There are two locations with different scopes:

  • Project level: .claude/skills/<name>/SKILL.md — lives in the repo, shared with the team
  • Personal level: ~/.claude/skills/<name>/SKILL.md — works across all your projects, visible only to you

The description field is everything: it controls auto-loading

Skills trigger in two ways. Manual is obvious: type /deploy-check in a session. The clever part is automatic triggering — on every turn, Claude compares the task at hand against every skill's description and loads the matching SKILL.md on its own.

So do not write the description as a feature summary. Write it as a list of trigger conditions:

# ❌ Weak description: Claude has no idea when to use it
description: GA4 analytics skill

# ✅ Strong description: spell out what the user might actually say
description: Use when analyzing the site's GA4 traffic. Triggers include
  "check pageviews", "which page is hottest", "traffic sources",
  "did the redesign work", pageviews, traffic.

This is the opposite of writing docs for humans. Human docs explain what it is; a description written for Claude must enumerate when to use it.

Progressive loading: skills are a context-management tool

The key difference between Skills and CLAUDE.md is load timing. CLAUDE.md goes into context in full at the start of every session, so a long one burns tokens continuously. A skill keeps only its name and description resident — the body loads only when triggered.

That suggests a practical architecture rule:

  • CLAUDE.md holds rules that always apply: code style, build commands, hard constraints
  • Skills hold scenario-specific procedures: release checks, analytics runs, report generation, the operating manual for one subsystem

A skill folder can also carry companion files (reference docs, scripts) that SKILL.md points to. Claude reads them only when needed, so even documentation-heavy workflows will not blow up your context window.

Skills vs hooks vs subagents: who does what

These three mechanisms get mixed up constantly. Sorting them by determinism makes it clear:

Mechanism What it is When to use
Hooks Deterministic shell commands that always run at an event Lint before commit, auto-format after file writes
Skills On-demand instructions that Claude follows Multi-step procedures, domain playbooks
Subagents Separate-context workers that report back Broad searches, parallel exploration, heavy isolated work

The rule of thumb: if it must happen every single time, use a hook; if it needs Claude's judgment and adaptation, use a skill; if it would pollute the main context, hand it to a subagent. They compose, too — a skill's body can legitimately say "delegate this step to a subagent."

Three skills you can copy today

1. Deploy check (deploy-check): the example above. Its value is moving "what to check before shipping" out of one person's head and into the repo.

2. Weekly report (weekly-report):

---
name: weekly-report
description: Use when generating the weekly report. Triggers include
  "weekly report", "this week's numbers".
---

1. Run `npm run ga:report -- top-pages --days 7`
2. Compare against last week and flag pages that moved more than 20%
3. Lead with the conclusion: one-sentence summary first, data table after
4. Analytics lag 24-48 hours — always note the data cutoff date at the end

3. Debug playbook (debug-build): capture your project's specific traps — "if the build fails, check the Node version is 20+ first", "on Prisma errors, run db:generate before anything else." New teammates (and new sessions) stop re-learning the same lessons.

How to start

Begin with whatever instruction you have repeated more than twice in the past week: paste it verbatim into a SKILL.md, write the trigger conditions, and invoke it with /skill-name next time. Polish the steps after the first successful run. Skills compound — every one you capture pays out in every future session.

For more advanced Claude Code capabilities, continue with our "10 Advanced Claude Code Techniques" and "Claude Code Memory and Commands" guides on this site.

Related Articles

Blocking rm -rf in Claude Code: A Deny Rule Stopped 14 Deletes in Two Weeks, 7 Other Spellings Still Get Through, and a Hook That Closes the Gap

To keep Claude Code from deleting things by accident, I added a deny rule, Bash(rm -rf *), to my global settings. Across my sessions from October 7 to 21 it blocked 14 deletes. After each denial the model picked a new directory name 8 times and dropped the delete 6 times. It never tried another spelling. Then I replayed 22 delete commands verbatim against Claude Code 2.1.285 through a stub. rm -fr, rm -r -f, rm -Rf and rm -r deleted the directory in manual, auto and bypass mode alike. /bin/rm, find -delete and bash -c deleted it in manual and bypass mode. In auto mode, rm -fr inside the working directory skips the classifier because it 'would be allowed in acceptEdits mode'. A second, built-in dangerous-rm check fires on targets like $D/*, even in bypass mode, but loses track of a variable assignment when a heredoc comes earlier in the same command. The post ends with a PreToolUse hook that blocks every recursive spelling in all three modes and tells the model what to do instead.

claude-codehooks+5
pitfallsOct 21, 20268 min
208

Claude Code Auto Mode with DeepSeek, GLM or Kimi: What Each "temporarily unavailable" Reason Means and When Retrying Is Pointless (Fault-Injection Test)

On a third-party model, Claude Code auto mode sends one extra classifier request per side-effecting action, from your session model to the same backend: a 132,470-character system prompt, about 29.7K input tokens per check. When it fails, you see "xxx is temporarily unavailable, so auto mode cannot determine the safety of Bash". We injected faults and recorded each message: 500 (server error), 429 (rate-limited), 529 (overloaded) and connection resets (connection failed) are retried 5 times; no reply in 60 s gives (timed out). **No parentheses means a 4xx rejection: tried once, and retrying never helps.** A reply with no verdict gives "could not evaluate"; three in a row bring back manual approval. CLAUDE_CODE_AUTO_MODE_MODEL has no effect. Claude Code 2.1.285, real DeepSeek v4-pro and MiMo v2.5 backends.

claude-codedeepseek+7
pitfallsOct 11, 202612 min
422

Claude Code "Prompt is too long" vs "maximum context length": Why Auto-Compact Works for One and Not the Other (Tested)

Claude Code decides a request was too long by matching the error text. If the backend says prompt is too long or input is too long for requested model, it auto-compacts the conversation and retries — invisible to you. DeepSeek and OpenAI-style gateways say This model's maximum context length is …, which it doesn't recognize: you get API Error: 400 on every turn. Manual /compact works; the better fix is to declare the real window with CLAUDE_CODE_MAX_CONTEXT_TOKENS (non-claude- model IDs) or CLAUDE_CODE_AUTO_COMPACT_WINDOW (claude- IDs) so it compacts before hitting the limit. Tested on Claude Code 2.1.285 against a local stub.

claude-codedeepseek+6
pitfallsOct 5, 20267 min
437

Claude Code Stuck on a Spinner With No Response: It Waits 6 Minutes per Attempt, and 10 Retries Can Hang It for Over an Hour (Tested)

When Claude Code spins without output or sits at Retrying in 0s, the backend is usually not sending anything. Tested on 2.1.285 (API key + ANTHROPIC_BASE_URL): with no response headers it waits 6 minutes (360 s) per attempt before timing out — setting API_TIMEOUT_MS to 600000 or 900000 doesn't change that; only lower values work. With the default 10 retries it can hang for over an hour. A gateway that buffers the reply until generation finishes will never deliver a reply that takes over 6 minutes. Press Esc to interrupt. All tested against a local stub.

claude-codetroubleshooting+5
pitfallsOct 5, 20269 min
377

Published by Magic Tools