AI EngineeringZero to ProductionHome·About·What’s new·Contact
Anthropic Skills · Chapter K4

Agent Skills

Package reusable know-how as Skills Claude loads on demand: SKILL.md, triggering descriptions, progressive disclosure (with a cost model), bundled helpers, distribution, and an org Skills library.

⏱️ ~2.5 hours🧪 6 labs🎯 Beginner→Tech-lead

Learning objectives

  • Explain what an Agent Skill is and when it beats a prompt or CLAUDE.md.
  • Write a SKILL.md with a triggering description and bundled files.
  • Understand progressive disclosure and why it keeps Skills cheap.
  • Distribute and govern Skills across a team.
▶ Runnable companionCode saved under code/ak4-agent-skills/. Python runs offline; configs are ready to use.

1 · What a Skill is essential

You've explained the same thing to Claude fifteen times this month. "Write the incident report the way we do it — timeline in UTC, cite every claim, no blame language, action items with owners." You paste that paragraph into a fresh chat, tweak it, paste it again next week. It's tribal knowledge trapped in your head and your clipboard, and every teammate re-invents their own slightly-different version. A Skill is the fix: you write that know-how down once, in a file, and from then on Claude reaches for it automatically whenever the task shows up.

Here's the analogy that makes it click. Think of a Skill as a recipe card in a kitchen's recipe box. The chef doesn't memorise every dish or keep all the cards open on the counter — that would be chaos. Instead each card has a title ("Beef Wellington") they can glance at, and only when tonight's order matches does the chef pull that one card and follow it step by step. The full recipe — the technique, the timings, the reference photo — stays folded away until it's actually needed. A Skill works exactly this way: a short label Claude can scan cheaply, and a detailed body it opens only on a match.

The mistake beginners make is reaching for a Skill for everything, or confusing it with the tools they already know. A Skill is not a one-off instruction (that's just a prompt) and it's not always-on project context (that's CLAUDE.md). It's specifically for recurring, specific know-how — a task you do the same way again and again — that you want packaged so it can be versioned, reviewed, and shared like code, yet costs almost nothing when it's not in use. Get that distinction right and Skills become a superpower; get it wrong and you've just made a folder full of prompts nobody triggers. With that framing, here's the precise definition.

An Agent Skill is a folder with a SKILL.md that packages reusable know-how — instructions, and optionally scripts and reference files — that Claude loads on demand when a task matches. It turns "the way we do X" into a versioned, shareable capability.

Task arrives user request name+desc match? cheap check load SKILL.md body · on match use bundled files as needed
🗺️ How to read this diagram

This picture shows the life of a request when Skills are installed — and the one idea that makes Skills cheap: Claude does not read every Skill up front. It reads only a tiny label for each, and opens the full Skill only when your task actually matches it.

  • Box 1 · Task arrives — you send a normal request ("write me an incident report").
  • Box 2 · name+desc match? — for each installed Skill, Claude compares your task against just the Skill's name and one-line description. The caption calls this a "cheap check" because those labels are tiny (a few words), so checking them costs almost nothing even with dozens of Skills.
  • Box 3 · load SKILL.md body — only on a match does Claude read the full instructions. A Skill that doesn't match is never opened, so you don't pay for it.
  • Box 4 · use bundled files — once loaded, the Skill can pull in its extra files (templates, scripts) as the instructions call for them.
  • Read it left to right: each arrow is "next step". The flow narrows from "look at every Skill's label" down to "fully load just the one that fits".

In short: "Progressive disclosure" = reveal detail only when needed. Labels are always visible (cheap); the heavy body appears just-in-time. That is why a team can install many Skills without slowing every chat.

Skill vs CLAUDE.md vs promptPrompt: one-off. CLAUDE.md: always-on project context. Skill: reusable know-how for a recurring, specific task, loaded only when relevant — so you can have many without bloating every session.

2 · Anatomy of a Skill essential

The good news you're about to discover: there's no framework to learn here. People hear "Agent Skill" and brace for a config schema, a registry, a build step. There is none. A Skill is a folder with a Markdown file in it. If you can create a directory and write a to-do list, you can write a Skill — and that low ceremony is deliberate, because the whole point is that ordinary teammates author these, not just platform engineers.

Picture it like a labelled folder in a filing cabinet. On the front is a sticky note saying what's inside and when to grab it — that's the metadata. Inside are the actual documents: the main instructions, plus any supporting handouts and a calculator you keep clipped to it. The folder's name is the Skill's name; the sticky note is the trigger; the pages inside are what Claude reads and follows once it opens the folder. Nothing more exotic than that.

Two pieces do all the work, and it's worth naming them before you see the code so you know what to look for. First, the front-matter — a tiny header of name and description — which is the sticky note Claude scans to decide whether this Skill is relevant. Second, the body — plain Markdown instructions below the header — which is the how Claude follows once the Skill fires. The common mistake is pouring all your effort into a beautiful body while writing a lazy one-line description; but a Skill with a perfect body and a vague description is a recipe card with a blank title — it never gets pulled, so its brilliance is never seen. Treat the description as first-class. The layout and the SKILL.md below show both pieces in a real, minimal Skill.

the folder on disk incident-report/ SKILL.md (required) template.md (optional) scripts/… (optional) name = folder name inside SKILL.md front-matter name + description the trigger — "whether" body (Markdown) step-by-step instructions the procedure — "how" A Skill is a folder + one Markdown file. SKILL.md splits into front-matter (name + description — the trigger deciding whether to fire) and a body (the instructions for how); reference files and scripts ride along optionally.
🗺️ How to read this diagram

Read it left to right: the left box is what you create on disk; the arrow points to the right, which zooms inside the one required file.

  • The left folder incident-report/ is the whole Skill. Its folder name becomes the Skill's name. Inside sits the highlighted SKILL.md (required) plus an optional reference file and a scripts/ helper.
  • The top-right blue box is the front-matter — name + description. This is the sticky note Claude scans to decide whether the Skill is relevant.
  • The bottom-right green box is the body — plain Markdown steps Claude follows once the Skill fires: the how.
  • The payoff is the split itself: "whether" (front-matter) and "how" (body) are separate jobs, which is why a lazy description dooms even a perfect body.

In short: Folder = the Skill; SKILL.md = front-matter (trigger) + body (procedure). Two pieces, two different jobs.

Example code for learning — review, test, and adapt it before running against real or production systems. Commands can create, change, or delete resources. See the Terms & Disclaimer.
layout · a Skill folder
layout.txt.claude/skills/
└── incident-report/
    ├── SKILL.md            # instructions + trigger metadata
    ├── template.md         # a reference the body points to
    └── scripts/
        └── gather_logs.sh   # an optional helper the Skill can run
▶ How this works

A Skill is nothing exotic — it is just a folder on disk with a specific shape. This is a directory tree (the └── and ├── lines are branches, like a family tree of files). Reading it tells you exactly what files to create.

  1. .claude/skills/ is where Claude looks for Skills. Each Skill gets its own sub-folder — here incident-report/, whose name becomes the Skill's name.
  2. SKILL.md is the required file: the instructions plus the trigger metadata (covered next). Every Skill must have exactly one.
  3. template.md is an optional reference file — extra material the instructions can point to (a house format, a checklist). It loads only if the body asks for it.
  4. scripts/gather_logs.sh is an optional helper script the Skill can run. The # text after each file is just a comment explaining its purpose, not part of the name.

Try this: Recreate this tree yourself: mkdir -p .claude/skills/incident-report/scripts and add an empty SKILL.md. That empty folder is already a (do-nothing) Skill.

config · SKILL.md
SKILL.md---
name: incident-report
description: >
  Write a postmortem/incident report in our house format. Use whenever the user
  asks for an incident report, postmortem, or RCA writeup.
---

# Incident report
1. Use the structure in `template.md` (timeline, impact, root cause, actions).
2. If logs exist, run `scripts/gather_logs.sh <service>`.
3. Timeline entries are UTC, newest last; every claim cites a log line or ticket.
4. "Action items" need an owner and a due date each.
5. No blame language — describe systems and events, not people.
▶ How this works

This is the heart of a Skill: the SKILL.md file. It has two parts — a small metadata header (between the --- lines) that tells Claude when to use the Skill, and a Markdown body that tells Claude how to do the task.

  1. The block fenced by --- at top and bottom is YAML front-matter (a tiny key: value settings header). name identifies the Skill; description is the all-important trigger line.
  2. The description: > uses a > so the text can wrap onto several indented lines and still count as one value. Notice it says "Use whenever the user asks for an incident report, postmortem, or RCA..." — it names the exact words a user would say, which is what makes Claude fire the Skill.
  3. Everything below the closing --- is the body: ordinary Markdown instructions. The # Incident report is a heading; the numbered list is the step-by-step procedure Claude follows.
  4. The body can reference the bundled files: step 1 points at template.md and step 2 runs scripts/gather_logs.sh — the same files from the folder tree above. The rules (UTC timeline, cite every claim, owners on action items, no blame language) capture "how we do it" once, reusably.

What the output means: There is no program output here — SKILL.md is instructions, not code. Its effect is that asking Claude for a postmortem now produces one in exactly this house format.

Try this: Rewrite the description to be vague ("Writes reports") and you'll see the problem the lesson warns about — a vague description often never triggers. Keep the concrete "use whenever..." phrasing.

The description IS the triggerClaude decides whether to load a Skill from its name + description alone. Write the description around when to use it ("use whenever the user asks for X") — vague descriptions never fire; precise ones do.

3 · Why progressive disclosure matters intermediate

Imagine if your kitchen chef had to read every recipe card in the box, cover to cover, before cooking a single dish. Fifty cards, thousands of words, every night, whether or not any of them applied to tonight's order. The kitchen would grind to a halt — and worse, you'd pay for all that reading even on nights you only served toast. That is exactly the trap a naive Skills system would fall into: load every Skill's full instructions into context on every request. The clever idea that avoids it has a name — progressive disclosure — and it's the single reason a team can install dozens of Skills without every chat getting slower and more expensive.

The principle is simple: reveal detail only when it's needed. What Claude keeps in view at all times is just the sticky note — each Skill's name and one-line description, a handful of tokens apiece. Those tiny labels are enough to answer the only question that matters up front: is this Skill relevant to what the user just asked? If the answer is no, the Skill's full body is never opened, so you never pay for it. If the answer is yes, then Claude reads the full SKILL.md — and only then do any bundled reference files get pulled in, and only if the body actually points at them. It's a three-tier ladder of cost: labels always, body on match, extras on demand.

Why does this deserve its own section rather than a footnote? Because it inverts the intuition most people carry about context. Newcomers assume "more installed Skills = a heavier, slower agent," so they hoard know-how in their head to keep sessions lean — and defeat the whole purpose. The truth is the opposite: because dormant Skills cost only their label, adding the fifty-first Skill is nearly free until the day a task finally matches it. The common mistake, then, isn't installing too many Skills — it's writing bodies so bloated that when one does match, the on-match cost balloons. Keep bodies tight and lean on bundled files for the heavy detail, and the economics stay in your favour at any scale. The little cost model below turns this argument into concrete numbers. Only each Skill's name + description are always in context (tiny). The full body loads only on a match. That's what lets a team ship dozens of Skills without every session paying for all of them — the context-economy lesson from PE2.

what's in context — three tiers, growing cost Tier 0 · name + description ~20 tok each · ALWAYS Tier 1 · SKILL.md body ~500 tok · ON MATCH Tier 2 · bundled files ON DEMAND cost grows ↓ Progressive disclosure = a cost ladder. Every Skill's tiny label is always resident (Tier 0); the full body loads only when the task matches (Tier 1); bundled files load only when the body points at them (Tier 2). Dormant Skills cost only their label.
🗺️ How to read this diagram

Read it top to bottom as a ladder — each rung is a deeper tier of a Skill, and each is narrower to signal that it fires less often but costs more when it does.

  • The top green band is Tier 0: every installed Skill's name + description, a few tokens each, held in context always. This is the cheap "cheap check" from section 1.
  • The middle blue band is Tier 1: the full SKILL.md body (~500 tokens), loaded only on a match. A Skill that doesn't match never reaches this rung.
  • The bottom amber band is Tier 2: bundled reference files and scripts, pulled in only when the body actually points at them.
  • The payoff is the shrinking width plus the "cost grows ↓" label: dormant Skills sit at Tier 0 forever, so adding the fifty-first Skill is nearly free until a task finally hits it.

In short: Labels always, body on match, extras on demand — you pay for detail only when a task reaches for it.

Python · model progressive-disclosure cost (runs)
disclosure_cost.pydef context_cost(skills, matched):
    """Always-loaded: name+desc (~20 tokens each). Body (~500) only if matched."""
    always = sum(20 for _ in skills)
    bodies = sum(500 for s in skills if s in matched)
    return always + bodies

skills = ["incident-report", "release-notes", "code-review", "data-clean", "sql-style"]
print("all 5 skills, none matched:", context_cost(skills, set()), "tokens (just metadata)")
print("all 5, one matched:       ", context_cost(skills, {"incident-report"}), "tokens")
print("if bodies always loaded:  ", 5*520, "tokens (5x waste)")
all 5 skills, none matched: 100 tokens (just metadata)
all 5, one matched:        600 tokens
if bodies always loaded:   2600 tokens (5x waste)
▶ How this works

This tiny program puts numbers on why progressive disclosure (the diagram above) saves money. It's a made-up but realistic cost model: it counts context tokens — the units Claude reads and you pay for — under different scenarios.

  1. context_cost(skills, matched) is a function taking a list of Skill names and the set of ones that matched this task. The docstring states the assumption: each Skill's name+desc costs ~20 tokens (always loaded), each full body ~500 tokens (loaded only on a match).
  2. always = sum(20 for _ in skills) adds 20 for every Skill — the cheap labels that are always present. bodies = sum(500 for s in skills if s in matched) adds 500 only for the matched ones. The total is always + bodies.
  3. The three print lines run three what-ifs: 5 Skills with none matched (labels only), 5 Skills with one matched, and the wasteful world where all 5 bodies load every time (5*520).

What the output means: none matched: 100 tokens (just 5×20 labels); one matched: 600 (100 labels + one 500 body); always loaded: 2600. The point: 100 vs 2600 — loading bodies only on demand is roughly a 5× saving.

Try this: Change matched to two Skills, e.g. {"incident-report","code-review"}, and predict the number before running (100 + 2×500 = 1100). More matches cost more — but you still skip the Skills that didn't match.

4 · Advanced — a Skill that bundles a script advanced

Would you ask a brilliant colleague to add up a column of two hundred numbers in their head? Of course not — you'd hand them a calculator. Yet that's exactly what you're doing when you ask a language model to count criticals in a log dump, sort timestamps, or tally null rates by eyeballing text. It can do it, mostly, but it's slow, it's probabilistic, and one day it will quietly miscount and you won't notice. The fix is to let the model do what it's genuinely great at — reasoning and narrating — and hand the exact, mechanical work to code. Skills let you ship that code inside the Skill itself.

A bundled script is the calculator clipped to the recipe card. When the Skill's instructions say "run scripts/summarize.py on the CSV," Claude executes real, deterministic code and reads back a trustworthy result — the same answer every single time, no drift, no hallucinated totals. Then the model reasons over that reliable output and writes the human-facing summary. You get the best of both worlds: the precision of a program and the fluency of a model, glued together by the Skill. And thanks to progressive disclosure, the script sits idle at zero cost until the body actually references it (that's the Tier-2 loading from the last section) — so bundling helpers never bloats your context, it only pays off when used.

The habit to build — and the mistake to avoid — is treating the helper like throwaway glue. It isn't; it runs with your agent's permissions and it runs unattended, so write it as a clean, testable unit you'd be comfortable importing anywhere (the same discipline as any command-line tool in DF1). Give it a clear input and output, no hidden side effects, and a shape you can unit-test on its own before a Skill ever calls it. A sloppy helper that crashes on odd input turns a helpful Skill into a landmine. The example below is a helper an incident-report Skill might ship — deliberately small, pure, and runnable on its own so you can see exactly what "clean and testable" looks like.

raw data logs · CSV · events bundled script count · sort · tally exact · same every run model reasons over reliable output writes the summary deterministic computation fluent narration Split the work: code counts, model narrates. The bundled script does the exact, mechanical part (counting criticals, sorting timestamps) and returns the same answer every run; the model reasons over that trustworthy result to write the human-facing summary.
🗺️ How to read this diagram

Follow the arrows left to right — it's a small pipeline that hands each job to whoever is best at it.

  • The left box is the messy input — a log dump, a CSV, a list of events — the fiddly stuff you don't want a model eyeballing.
  • The middle green box is the bundled script: real code that counts, sorts, and tallies. Its label "exact · same every run" is the whole point — deterministic, no drift, no hallucinated totals.
  • The right blue box is the model: it reads the script's trustworthy output and does what it's genuinely great at — reasoning and writing the readable summary.
  • The payoff is the division of labour under the boxes: deterministic computation on the left, fluent narration on the right — the precision of a program glued to the fluency of a model.

In short: Hand the exact counting to code and the wording to the model — you get reliable numbers and a good write-up.

Python · a bundled skill helper (runs)
skill_helper.py# scripts/summarize_incidents.py — a helper the incident-report Skill calls
def summarize(events):
    """events: [(ts, service, severity)] -> a timeline + a headline count."""
    events = sorted(events)                       # chronological
    crit = sum(1 for _,_,sev in events if sev == "critical")
    timeline = [f"{ts} UTC — {svc} ({sev})" for ts, svc, sev in events]
    return {"critical_count": crit, "timeline": timeline}

r = summarize([("10:05","api","critical"), ("10:01","db","warning"), ("10:12","api","critical")])
print("criticals:", r["critical_count"])
for line in r["timeline"]: print(" ", line)
criticals: 2
  10:01 UTC — db (warning)
  10:05 UTC — api (critical)
  10:12 UTC — api (critical)
▶ How this works

This is an example of the bundled helper script a Skill can ship (the scripts/ file from the folder tree). The point is that a Skill isn't limited to prose — it can carry real, runnable code that does the fiddly work reliably every time.

  1. summarize(events) takes a list of incident events. The docstring shows the shape: each event is a tuple (ts, service, severity) — a timestamp, a service name, and how bad it was.
  2. events = sorted(events) puts them in chronological order (sorting tuples sorts by the first item, the timestamp). This guarantees a correct timeline no matter what order they arrived.
  3. crit = sum(1 for _,_,sev in events if sev == "critical") counts how many were critical by adding 1 for each match — the headline count. The timeline line builds a readable string per event with an f-string.
  4. It returns a dictionary with both results. The code below the function calls it on three sample events and prints the critical count, then each timeline line.

What the output means: criticals: 2 (two of the three events were critical), followed by the three events printed in time order — 10:01 before 10:05 before 10:12 — proving the sorted() worked even though 10:01 was listed second in the input.

Try this: Add a fourth event like ("10:08","db","critical") to the list and re-run: the count becomes 3 and the new line slots into the right chronological spot automatically.

5 · Distributing Skills advanced

A Skill that lives only on your laptop helps exactly one person. You wrote the perfect incident-report Skill, it fires beautifully, your postmortems are consistent and fast — and your five teammates still each hand-roll their own, because they've never seen yours. The whole value proposition of Skills is that know-how becomes shared: "the way we do X" turns into a default the whole team inherits without a meeting. That only happens if the Skill lands somewhere everyone's Claude can find it — which is what distribution is about.

The key idea is scope: where a Skill lives determines who gets it, and it maps cleanly onto how a company shares anything. A Skill committed into a repo's .claude/skills/ is like a document in the team's shared drive — clone the repo and it's just there, same version for everyone. A personal Skill in your own user config is like a note in your private notebook — it travels with you across every project but nobody else sees it. And a plugin-bundled Skill is like a published library on an internal registry — anyone across the org who installs the bundle picks it up. Same file, three different blast radii, chosen by where you put it.

The mistake here is thinking of distribution as a mechanical afterthought — just git add and move on. It's actually a governance decision, and picking the wrong scope has real consequences. Commit a half-baked Skill to the project scope and you've foisted your experiment on everyone's session; keep a genuinely useful one personal and the team keeps duplicating it. There's also a security dimension the moment a Skill leaves your machine: a shared Skill's bundled scripts run with each installer's agent permissions, so distributing one is closer to publishing a dependency than emailing a doc — it deserves the same review. The table below lays the three scopes side by side; match the scope to how widely the know-how should actually travel.

where you put it decides who gets it — growing blast radius Personal · just you Project · everyone on the repo Plugin · anyone who installs the bundle same file · three blast radii Scope = blast radius. A personal Skill travels with you alone; a project Skill in the repo's .claude/skills/ ships to everyone who clones it; a plugin-bundled Skill reaches anyone across the org who installs it. Same file, chosen reach.
🗺️ How to read this diagram

Read it top to bottom: each bar is one scope, and each is wider than the one above to show a bigger audience — its "blast radius".

  • The narrow top bar is Personal: a Skill in your own user config. It follows you across every project, but no teammate sees it.
  • The middle bar is Project: committed into a repo's .claude/skills/. Clone the repo and it's just there — same version for everyone on that repo.
  • The widest bottom bar is Plugin: bundled and published so anyone across the org who installs it picks it up.
  • The payoff is that the same Skill file gets a different reach purely by where you place it — so choosing scope is a governance decision, not an afterthought.

In short: Personal → you; Project → your repo; Plugin → the org. Match the width to how far the know-how should really travel.

ScopeLocationWho gets it
Project.claude/skills/ (in the repo)everyone on the repo
Personalyour user Claude configyou, everywhere
Plugina shared plugin bundleanyone who installs it

6 · Professional — write a triggering description professional

Here's the most heartbreaking way a Skill fails: it works perfectly and never runs. The body is flawless, the bundled script is tested, the folder is committed — and then it just… sits there. Weeks pass. Nobody's postmortems improve. The Skill is dormant, because the one line that decides whether Claude ever opens it — the description — was too vague to match anything. All that effort, invisible. This is far and away the number-one Skill bug in practice, and the whole cure lives in a single sentence you have to get right.

Recall from the anatomy section that the description is the only part of a Skill always in context — the sticky note on the folder. That makes it the entire trigger signal: Claude fires the Skill by matching your task against that one line and nothing else. So the description isn't a summary, it's a trigger, and those are different jobs. A summary answers "what is this?" ("Helps with spreadsheets"). A trigger answers "when should I reach for this?" ("Use whenever the user asks to create, edit, or export an Excel file"). The failing descriptions are the ones written as summaries — they describe a capability floating in the abstract, giving Claude no situational cue for when it applies, so it never applies.

The reliable pattern is to name the situation in the user's own words: lead with "use when" or "use whenever the user asks for…" and then list the concrete nouns a real person would type — report, review, summary, postmortem, RCA, clean, format. Those task words are the hooks Claude latches onto. The opposite mistake, worth guarding against too, is a description so broad it fires on everything and collides with your other Skills — a trigger that's always on is as useless as one that's never on. Aim for the narrow band in between: specific enough to fire exactly when it should, and not a token more. The lab below is a small "linter" that scores a description on precisely these traits, so you can catch a dead trigger before you ship it rather than months later.

the task: "write me an incident report" summary — vague "Helps with spreadsheets" no situational cue never fires · dormant trigger — precise "use whenever … report" names concrete task nouns fires at the right moment A description is a trigger, not a summary. "Helps with spreadsheets" describes a capability floating in the abstract and never matches; "use whenever the user asks for a report/RCA…" names the situation in the user's own words, so Claude fires it exactly when it applies.
🗺️ How to read this diagram

Two side-by-side panels answer the same question — "does this Skill fire on the task at the top?" — with opposite outcomes.

  • The left red panel is a description written as a summary: "Helps with spreadsheets." It says what the Skill is but gives no cue for when to use it, so the arrow leads to "never fires · dormant".
  • The right green panel is a description written as a trigger: "use whenever the user asks for a report…". It names the concrete nouns a real person types, so the arrow leads to "fires at the right moment".
  • The colours carry the verdict: red = the heartbreaking dead trigger, green = the working one. The only difference is phrasing.

In short: Write the description around when ("use whenever the user asks for X") with real task words — that is the entire difference between a Skill that runs and one that silently never does.

Python · score a Skill description (runs)
desc_score.pydef score_description(desc):
    d = desc.lower(); score, notes = 0, []
    if "use when" in d or "use whenever" in d: score += 1
    else: notes.append("say WHEN to use it (\"use whenever...\")")
    if len(desc) >= 40: score += 1
    else: notes.append("too short — name concrete triggers")
    if any(w in d for w in ["report","review","summary","writeup","clean","format"]):
        score += 1
    else: notes.append("name the task nouns users will say")
    return score, notes

print(score_description("Writes stuff"))
print(score_description("Write an incident report/postmortem. Use whenever the user asks for an RCA or postmortem writeup."))
(0, ['say WHEN to use it ("use whenever...")', 'too short — name concrete triggers', 'name the task nouns users will say'])
(3, [])
▶ How this works

The lesson's biggest warning is that a Skill with a weak description never triggers. This little program is a linter for descriptions — it scores one out of 3 and tells you what's missing, so you can fix a trigger before shipping it.

  1. d = desc.lower() makes a lowercase copy so the checks are case-insensitive. score, notes = 0, [] starts the tally at 0 with an empty list of complaints.
  2. Each if awards one point for a good trait: it contains "use when/whenever" (says when to fire); it's at least 40 characters (specific, not a stub); and it mentions a concrete task noun (report, review, summary...). When a check fails, the else appends a note explaining the fix.
  3. It returns the pair (score, notes). The two print lines score a deliberately bad description ("Writes stuff") and a good one.

What the output means: (0, [...three complaints...]) for "Writes stuff" — it earns no points and gets told exactly what to add. The concrete one scores (3, []): full marks, no complaints. The exercise asks you to reach a score of at least 2.

Try this: Paste your own draft description into a third print(score_description(...)) and aim for 3. Adding the words "use whenever the user asks for a ... report" usually flips all three checks to pass at once.

7 · Tech-lead — a Skills library for the org tech-lead

Think about what walks out the door every time a senior engineer leaves. The way they wrote incident reports, the SQL conventions they enforced in review, the release-note format everyone quietly copied from them — years of "how we do things here" that lived only in their habits. Onboarding a new hire means someone re-teaching all of it by osmosis, imperfectly, over months. A curated Skills library is the tech-lead's answer to that leak: it captures the team's recurring know-how as code you can commit, so it survives turnover and every new person inherits it on day one instead of year one.

The mental model that matters at this altitude is that a Skills library is a shared codebase, and it needs the same governance. A folder of uncoordinated Skills rots exactly like a folder of uncoordinated scripts: nobody owns them, two of them quietly overlap and fight to trigger on the same task, and half of them stopped firing months ago and no one noticed. So the lead's job isn't to write every Skill — it's to run the library like a maintainer runs a repo. One clear owner per Skill. Descriptions deliberately kept non-overlapping so triggering stays predictable and two Skills never collide. Review before merge, versioning, and a quiet deprecation path for Skills that have gone dark.

The judgement call underneath all of it — and the common mistake juniors make — is deciding what even deserves to be a Skill. The temptation is to skill-ify everything, which just recreates the sprawl you were trying to avoid. The discipline is a decision rule: promote know-how to a Skill only when it recurs, is situation-specific enough to write a clean trigger for, and ideally benefits from a deterministic bundled step. One-off work is cheaper as a direct instruction; borderline cases often belong in a slash command or a line of CLAUDE.md, not a full Skill. Get that gate right and the library stays lean and trustworthy; skip it and you're back to tribal knowledge, just with more folders. The exercises that follow put both halves — the decision rule and the governance policy — into practice.

what deserves to be a Skill? — a decision gate know-how recurs? same task, repeatedly no direct instruction yes specific / needs code? clean trigger · code step yes → a Skill borderline slash / CLAUDE.md A gate keeps the library lean. One-off work → a plain instruction. Recurring and situation-specific (or needing a deterministic step) → a Skill. Borderline → a slash command or a line of CLAUDE.md. The gate is what stops skill-ifying everything.
🗺️ How to read this diagram

Follow the arrows from the top box down — it's a two-question filter that routes each piece of know-how to the right home.

  • The top box asks the first question: does this recur? If no, the arrow goes left to a red box — it's cheaper as a one-off direct instruction, not a Skill.
  • If yes, you drop to the second question: is it situation-specific enough for a clean trigger, or does it need a deterministic (code) step?
  • A clear yes routes to the green → a Skill box — this is the only path that earns a full Skill.
  • A borderline case routes to the amber box: a slash command or a line of CLAUDE.md — lighter than a full Skill.
  • The payoff is that most know-how doesn't reach the green box, which is exactly what keeps the org library from sprawling.

In short: Recurs + specific/needs-code → Skill; one-off → prompt; in-between → slash command or CLAUDE.md.

Skills are institutional memory as codeWhen "how we write incident reports" or "our SQL style" lives in a committed, reviewed Skill, it survives turnover and stays consistent. A lead who curates that library turns tribal knowledge into a durable, shared asset.

Exercise AK4.1 — Author & score a Skill

Context: Authoring a real skill forces the two things that make skills work: a description specific enough to trigger reliably, and a bundled helper that does deterministic work the model can reason over.

Your task: Author a SKILL.md for a recurring task with a precise trigger (score it ≥2 with desc_score), bundle one reference file and one runnable helper, and confirm it fires only when it should.

Requirements:

  • The skill targets a recurring task you already do a particular way
  • The description is a precise trigger — it scores ≥2 with desc_score
  • It bundles one reference file and one runnable helper script, and the helper is tested
  • Confirm the skill fires when you ask for that task
  • Confirm it stays dormant on unrelated tasks

💡 Hint: Test both directions — that it triggers on the target task and that it stays quiet otherwise — a skill that always fires is as broken as one that never does.

🪜 Practice ladder beginner → industry

Six graded exercises, easy to real-world. Try each before opening its solution.

Exercise 1 · Write a minimal SKILL.mdBeginner

Context: A Skill is just a folder with a SKILL.md: frontmatter that says what it is and when to load it, plus a body of guidance — the minimum viable unit of reusable know-how.

Your task: Write a minimal SKILL.md for a skill that formats commit messages, including its name and description frontmatter.

Requirements:

  • The skill is a folder containing a SKILL.md (e.g. .claude/skills/…/SKILL.md)
  • Frontmatter includes a name and a description
  • The description says when to load the skill, not just what it does
  • The body holds the actual guidance (the commit-message format rules)
  • Verify the exact frontmatter keys and folder location in the docs

💡 Hint: Name + description + body is the whole minimum — the description is what tells Claude to reach for it.

Show solution

The whole skill is a folder plus a SKILL.md with frontmatter + body:

# .claude/skills/commit-style/SKILL.md
---
name: commit-style
description: Write conventional-commit messages. Use when composing a git
  commit message from a diff.
---

Format: `type(scope): summary` where type is feat|fix|docs|refactor|test.
- Summary in imperative mood, <=72 chars, no trailing period.
- Add a body only when the "why" isn't obvious from the summary.

The name identifies the skill and the description tells Claude when to load it; the body is the actual guidance. That is the minimum viable skill. Verify the exact frontmatter keys and folder location in the docs.

Exercise 2 · Why progressive disclosure mattersIntermediate

Context: Progressive disclosure is how a large skill library stays cheap: only the one-line description sits in context by default, and detail loads on demand.

Your task: Explain the progressive-disclosure tiers and model which parts of a skill are in context at each stage.

Requirements:

  • Tier 0 (always): only the skill's description line is resident
  • Tier 1 (on use): the full SKILL.md body loads when the task matches
  • Tier 2 (on demand): bundled files/scripts load only when the body references them
  • Model the context cost per stage (idle vs triggered vs deep)
  • Explain the payoff: you pay for detail on demand, not up front

💡 Hint: Three stages, growing context: description only, then + body, then + referenced files.

Show solution

Progressive disclosure keeps only the description resident until the skill is needed:

Tier 0 (always):  the skill's `description` line only  -> cheap, always in context
Tier 1 (on use):  the full SKILL.md body                -> loaded when relevant
Tier 2 (on demand): bundled files/scripts the body points to -> read as needed

def context_cost(stage):
    return {"idle": "description only",
            "triggered": "description + SKILL.md body",
            "deep": "description + body + referenced files"}[stage]
print(context_cost("idle"))       # description only
print(context_cost("triggered"))  # description + SKILL.md body

Only the one-line description sits in context by default; the body loads when the task matches, and bundled files load only when the body references them. That is how a large skill library stays cheap — you pay for detail on demand, not up front.

Exercise 3 · Bundle a script with a skillAdvanced

Context: Bundling a script beside a skill lets it do deterministic work — parsing, stats — instead of asking the model to eyeball it, and the script costs nothing until the body references it (Tier 2).

Your task: Sketch a skill folder that bundles a Python helper script and references it from SKILL.md.

Requirements:

  • The folder holds SKILL.md plus a bundled script (e.g. under scripts/)
  • The SKILL.md body tells the model to run the script and how to invoke it
  • The script does deterministic work; the model reasons over its reliable output
  • The script loads only when the body references it (Tier 2), so it's free until used
  • Verify path conventions in the docs

💡 Hint: Let the script do the exact computation and let the model narrate its output — point to it from the body so it stays lazy-loaded.

Show solution

Bundle the script beside SKILL.md and point to it from the body:

.claude/skills/csv-report/
  SKILL.md
  scripts/summarize.py       <- bundled helper

# SKILL.md body excerpt:
To summarize a CSV, run the bundled script:
    python scripts/summarize.py <path-to-csv>
It prints row count, column types, and per-column null rates.
Read its output, then write the narrative summary.

Bundling code lets the skill do deterministic work (parsing, stats) instead of asking the model to eyeball it — the model runs the script and reasons over reliable output. The script loads only when the body references it (Tier 2), so it costs nothing until used. Verify path conventions in the docs.

Exercise 4 · Write a triggering descriptionExpert

Context: Because the description is the only part always in context, it is the entire trigger signal — a skill that names the situation fires precisely, while a vague one sits unused or fires on the wrong task.

Your task: Write a strong versus weak skill description and explain why the strong one triggers correctly.

Requirements:

  • The weak version is vague about capability and gives no situational cue
  • The strong version names concrete triggering situations (what the user asks for)
  • It prescribes when to use the skill, not only what it does
  • Explain that the description is the only always-in-context part, so it is the whole trigger
  • Tie the specificity to firing at the right moment and not on the wrong task

💡 Hint: Describe the user's situation the skill answers ("when the user asks to…"), not the feature list.

Show solution

The description must name the situation, not just the capability:

Weak:   description: "Helps with spreadsheets."
        -> too vague; the model can't tell when it applies.

Strong: description: "Generate .xlsx spreadsheets with formulas and charts.
         Use when the user asks to create, edit, or export an Excel file
         or a report as a spreadsheet."
        -> names concrete triggers (create/edit/export .xlsx), so the
           model loads it exactly when relevant.

Because the description is the only part always in context, it is the entire trigger signal. Prescribe when to use the skill (the user-facing situations) — not just what it does — so it fires precisely and doesn't sit unused or fire on the wrong task.

Exercise 5 · Distribute a skill safelyProfessional

Context: A distributed skill runs with your agent's permissions, so vetting its bundled scripts is a security step, not a formality; versioning and pinning stop an upstream change from silently altering everyone's behavior.

Your task: Decide the packaging, versioning, and pre-install checks for sharing a skill across the org.

Requirements:

  • The skill is a self-contained folder (SKILL.md + any scripts)
  • The description is specific enough to trigger correctly
  • Bundled scripts are reviewed like code — they run with the agent's permissions
  • No secrets and no calls to untrusted hosts inside the scripts
  • Versioned in a shared repo/registry and pinned on install
  • Ships with a short README: what it does, when it triggers, what it can touch
  • Verify the current distribution/registry mechanism in the docs

💡 Hint: Treat it like importing a dependency that runs as you — review the code, pin the version, document the blast radius.

Show solution

Package it as a versioned folder and review it like code:

Distribution checklist:
  [ ] Skill is a self-contained folder (SKILL.md + any scripts).
  [ ] Description is specific enough to trigger correctly (see expert rung).
  [ ] Bundled scripts are reviewed — they run with the agent's permissions.
  [ ] No secrets, no network calls to untrusted hosts inside scripts.
  [ ] Versioned in a shared repo / registry; pin a version when installing.
  [ ] A short README: what it does, when it triggers, what it can touch.

A distributed skill runs with your agent's permissions, so vetting the bundled scripts is a security step, not a formality. Version and pin it so an upstream change can't silently alter behavior for everyone. Verify the current distribution/registry mechanism in the docs.

Exercise 6 · A Skills library for the org (tech-lead)Industry scenario

Context: A skill earns its place when the know-how recurs and is clearly triggerable; the library's health depends on non-overlapping descriptions so two skills don't fight to trigger, plus single ownership and review.

Your task: As tech lead, write the decision rule for what becomes a skill and the governance policy for an org Skills library.

Requirements:

  • The decision rule keys on: repeated, situation-specific, and whether it needs a deterministic step
  • One-off work is not a skill — a direct instruction is cheaper
  • Recurring + clearly-triggered → yes (bundle a script if deterministic work is needed)
  • Borderline cases may be a slash command or a CLAUDE.md line instead of a full skill
  • Governance: one owner per skill, non-overlapping descriptions, review + version in a shared repo, deprecate skills that stop triggering

💡 Hint: Two tests decide it: does the know-how recur, and can you write a description that won't collide with another skill's trigger?

Show solution

Make skills for repeated, situation-specific know-how; govern to avoid sprawl:

def is_skill_worthy(repeated, situation_specific, needs_deterministic_step):
    if not repeated:
        return "NO — one-off; a direct instruction is cheaper than a skill"
    if situation_specific or needs_deterministic_step:
        return "YES — recurring, clearly-triggered; bundle a script if it "\
               "needs deterministic work"
    return "MAYBE — could be a slash command instead of a full skill"

print(is_skill_worthy(True, True, True))    # YES
print(is_skill_worthy(False, True, False))  # NO

# Governance: one owner per skill; non-overlapping descriptions (so two
# skills don't fight to trigger); review + version in a shared repo;
# deprecate skills that stop triggering.

A skill earns its place when the know-how recurs and is clearly triggerable; otherwise a slash command or a line in CLAUDE.md is lighter. The library's health depends on non-overlapping descriptions (so triggering stays predictable), single ownership, and review — the same discipline as a shared code library.

✓ Checkpoint — you can move on when you can…

  • Explain when a Skill beats a prompt/CLAUDE.md.
  • Write a valid SKILL.md with a triggering description.
  • Explain progressive disclosure and its cost model.
  • Distribute Skills and curate an org library.

Knowledge check check yourself

✓ Knowledge check

How does progressive disclosure keep Agent Skills cheap, and what is loaded into context before a Skill matches?

Show answer
Only each Skill's name and description (tiny metadata labels) stay in context at all times; the full SKILL.md body loads only when a task matches. So comparing five Skills with none matched costs only the metadata (~100 tokens) instead of ~2600 tokens if every body were loaded.
✓ Knowledge check

Why is the description in a Skill's YAML front-matter considered the trigger, and what makes one reliable versus one that never fires?

Show answer
Claude decides whether to load a Skill by matching the task against its description, so the description is what actually fires it. A reliable one phrases it as "use when/whenever the user asks for [X]" with concrete task nouns (report, review, summary, clean, format); a vague description never matches and the Skill stays dormant.
© 2026 studybydoing.in · AI Engineering: Zero to Production · All rights reserved. · About · Privacy Policy · Terms · Contact
Educational content, provided as-is and without warranty. Code samples are examples — review, test, and adapt them before using in production. See the Terms of Use & Disclaimer. Use at your own risk.
© studybydoing.in