2.1 Extending Agents with Skills
In 1.4 Setup MCP Servers and Skills, you installed your first skills using npx skills add. This lesson is the why behind that — what skills actually are, how they fit into the broader agent extension ecosystem, and how to think about when and what to put in one.
What Is an Agent Skill?
An Agent Skill is an organized folder of instructions, scripts, and resources that an agent discovers and loads dynamically. Think of it as an onboarding guide for a new hire: you don't give someone the entire company handbook on day one, but when they need to know the deploy procedure or the API style guide, they know exactly where to look. The model works the same way — skills sit on the shelf, ready to load when the task calls for them.
The format was created by Anthropic and published as an open standard with a home at agentskills.io. It has been adopted across a growing ecosystem of runtimes including OpenAI Codex, Google Gemini CLI, GitHub Copilot, and Cursor — the same skill works regardless of which agent you're running.
The skills you installed in 1.4 (agent-browser, web-design-guidelines, frontend-design) all follow this standard. You've already been using the open ecosystem — this lesson explains how it works under the hood.
The Three Axes of Agent Extension
Agents can be extended in three fundamentally different ways. Knowing which axis to reach for prevents over-engineering:
| Extension | What It Adds | Loaded How | Best For |
|---|---|---|---|
| Skills | Procedural workflows & domain knowledge | On demand, when relevant | Checklists, style guides, multi-step processes |
| MCP Servers | Live tool access to external systems | Persistent, per-session | Database queries, API calls, file system access |
| RAG / File Search | Factual recall from large corpora | Query-time retrieval | Searching codebases, product docs, knowledge bases |
Skills and MCP servers are complementary, not competing. A deploy skill might invoke a GitHub MCP server to check PR status — the skill provides the procedure, the MCP provides the tool.
Progressive Disclosure — Why Skills Stay Cheap
A well-authored skill costs almost nothing to have installed. The format defines three loading levels:
- Skill metadata (~100 tokens, always loaded): the skill's
nameanddescriptionfrom the directory index — just enough for the agent to know the skill exists and when to activate it - SKILL.md body (loaded on activation, recommended under 5,000 tokens): the full instructions, fetched only when the agent determines the skill is relevant for the current task
- Bundled references and assets (zero tokens until referenced): linked files in
references/andassets/load only when the SKILL.md body explicitly points to them
This means you can install dozens of skills with a minimal baseline context cost. You pay for a skill's knowledge only when it's actually doing the work.
What Should Be a Skill?
Not everything belongs in a skill. Here's the routing map:
| Content | Where It Goes | Reason |
|---|---|---|
| Procedural workflows — deploy checklists, release processes, review procedures | Skill | Only needed sometimes; loads on demand |
| Domain knowledge — API conventions, data models, style guides | Skill | Context-heavy; not always relevant |
| Standing facts — build commands, project layout, always/never rules | CLAUDE.md / AGENTS.md | Must always be visible; keep lean (under ~200 lines) |
| Deterministic enforcement — must-always-happen guardrails | Hook | Skill instructions are requests, not guarantees |
| Context isolation for big sub-tasks | Subagent | Skills don't isolate context; subagents do |
| One-off / exploratory work | Plain prompt | Don't build infrastructure for one-time needs |
The conversion signal: the third time you paste the same playbook into chat, factor it into a skill. Similarly, when a section of your CLAUDE.md has grown into a procedure rather than a fact, that section belongs in a skill.
Skills come in two content flavors:
| Type | Purpose | How Invoked |
|---|---|---|
| Reference | Background knowledge the agent applies inline | Auto-loaded when the task triggers it |
| Action / Task | Step-by-step procedure explicitly run | User invokes with /command |
Anatomy of a Skill
A skill is a directory with SKILL.md at its root:
my-skill/
├── SKILL.md ← Frontmatter + instructions (required)
├── references/ ← Knowledge files, loaded on demand
│ └── style-guide.md
├── scripts/ ← Executable code (never loaded into context)
│ └── transform.py
└── assets/ ← Templates, output formats, examples
└── report-template.md
Keep files one level deep inside each folder — nested subdirectories are not supported by the spec.
The SKILL.md Frontmatter
---
name: pdf-form-filler # Required: ≤64 chars, lowercase-hyphens, matches dir name
description: | # Required: ≤1024 chars; third-person, trigger-rich
Fills PDF forms from structured data. Use when the user needs to
populate a PDF template with values from a JSON or CSV source.
license: MIT # Optional
allowed-tools: Bash Read # Optional, experimental (space-separated)
---
Instructions for the agent go here in Markdown...
Key rules:
namemust match the directory name exactly — no "claude" or "anthropic" allowed (reserved namespaces)descriptionis the most important field for reliable triggering — write it in third person and describe both what the skill does and when to use it. Keep it concise: an overly verbose description clutters context and makes it harder for the agent to tell when your skill actually applies.allowed-toolsis experimental and behaves differently across runtimes; in Claude Code it pre-approves listed tools rather than restricts to them. The value is a space-separated string (e.g.,Bash Read Write), not a YAML list
Beyond these spec fields, individual harnesses have started adding their own frontmatter keys that aren't part of the open standard. A representative example is Claude Code's disable-model-invocation: true, which makes a skill user-invoke-only — the model can never auto-fire it, so it's handy for side-effecting workflows like /deploy or /commit where you want to own the timing. Codex has the same capability but expresses it differently and elsewhere: allow_implicit_invocation: false under a policy: block in a separate agents/openai.yaml sidecar file, not in the frontmatter at all.
These fields live outside the agentskills.io spec. A runtime that doesn't recognize a frontmatter key silently ignores it — so a skill that depends on disable-model-invocation to stay human-only will happily auto-fire on a harness that's never heard of the field. The spec fields (name, description) carry across runtimes; harness-specific extensions do not. If cross-harness portability matters, treat these as convenience features, not safety guarantees.
Scripts: The Deterministic, Context-Saving Layer
Scripts in scripts/ are executed, not read — their code never enters the context window. This matters for two reasons:
- Reliability: a script that parses a report and generates a diff runs with full precision every time, without the model reconstructing logic from memory across conversations
- Cost: context cost is zero regardless of script length — a 1,000-line Python script has the same context footprint as a 10-line one
OpenAI's framing is useful here: "interpretation, comparison, and reporting stay with the model; deterministic, repeated shell work goes in scripts/." Anthropic describes this as giving you "degrees of freedom" — choosing how much of a task is model-driven versus deterministic.
A Worked Example
pdf-skill/
├── SKILL.md ← Body references REFERENCE.md for field mappings
├── references/
│ └── REFERENCE.md ← Loads only when SKILL.md body references it
└── scripts/
└── fill_form.py ← Executed on demand; source never enters context
The SKILL.md body might say: "Refer to references/REFERENCE.md for field mapping conventions." That reference file loads only when those instructions are reached — not at skill activation time.