# Skills: Teach the Agent Your Way of Working

Course: Agentic Coding: Run Coding Agents Like an Operator — Lesson 5 of 10

Package your repeated instructions as skills: the SKILL.md format, progressive disclosure, prompt vs router vs script-backed shapes, and how to install them safely.

> **The one line:** a skill is a folder with a `SKILL.md` in it, and its value is progressive disclosure: the name and description sit in context always, the body loads only when the agent needs it.

## A skill is a file convention

A skill directory holds `SKILL.md` plus optional `scripts/`, `references/` and `assets/`. `SKILL.md` is YAML frontmatter then markdown; paths inside are relative to the skill root.

```text
pr-issue/
├─ SKILL.md      # frontmatter + the router body
├─ pr.md         # loaded only when the request is a PR
└─ issue.md      # loaded only when the request is an issue
```

The format started at Anthropic and is now an open [standard](https://agentskills.io/specification) with roughly 45 clients, Codex, Cursor, Gemini CLI and OpenCode among them. Keep `SKILL.md` under 500 lines and references one level deep.

## Progressive disclosure

Three levels:

1. **Metadata.** `name` plus `description`, about 100 tokens per skill, in context from startup. The model scans this list for relevance.
2. **Body.** The rest of `SKILL.md`, loaded when the skill is invoked. Target under 5,000 tokens.
3. **Bundled files.** A reference table, `pr.md`, a script, read only if the body sends the agent there. Script *code* never enters context, only its stdout.

Every globally installed skill charges you level 1 in every session. Claude Code caps `description` plus `when_to_use` at 1,536 characters, Codex caps the whole list at 2 percent of the window. So install narrowly ([context budgeting](/courses/agentic-coding/own-your-context-window)).

## Frontmatter, annotated

The open spec allows six fields. Claude Code adds more, and those extras are a **hard error** on claude.ai uploads, the Skills API and `package_skill.py`. Other harnesses ignore them.

```yaml
---
# --- open spec: portable everywhere ---
name: session-report          # required; lowercase, must match the folder name
description: >-               # required, <=1024 chars; your matching signal
  Generate an HTML report of what is in a session's context window.
license: MIT                  # optional
compatibility: "claude-code"  # optional, <=500 chars
metadata: { version: "1.1.0" }# optional string->string map
allowed-tools: "Bash Read"    # optional, marked experimental in the spec

# --- Claude Code only: silently ignored by Codex, rejected by the Skills API ---
when_to_use: "when the user asks what is eating their context"
argument-hint: "[session-id]"
arguments: session_id
disable-model-invocation: true  # keeps it out of the startup listing entirely
model: opus
effort: high
---
```

Claude Code is looser on `name`: optional, display label only, and the command you type comes from the directory name.

`disable-model-invocation: true` drops the skill from the startup metadata, so only you can trigger it, by name. Use it for reports, generators, one-shot commands: anything aimed at you, not the agent. My `session-report` is set this way. Outside Anthropic's harness the flag does nothing, so on Codex your only lever is not installing the skill.

| Harness | Invoke a skill by name |
| :--- | :--- |
| Claude Code | `/skill-name`, with `$ARGUMENTS`, `$0`, `$name` in the body |
| Codex CLI and IDE | `$skill-name`, or `/skills` to browse |
| ChatGPT | `@` |

Codex's equivalent flag is `allow_implicit_invocation` in a per-skill `agents/openai.yaml`.

## Three shapes

**Pure prompt.** My `pr-issue` skill holds the templates every PR and issue follows: title as `area: summary`, then problem, solution, security impact, testing.

**Router.** That same skill is also a router. `SKILL.md` carries the shared rules, then branches:

```md
- Writing a pull request → [`pr.md`](pr.md)
- Writing an issue, ticket, or bug report → [`issue.md`](issue.md)
```

Only the matching file loads, so a long body of guidance costs you one short entry point.

**Script-backed.** `session-report/SKILL.md` is mostly instructions for running a TypeScript file that reads a session transcript and writes an HTML report:

```bash
node generate-report.ts "$session_id" --open
```

The model never reads that source, so a thousand lines of TypeScript cost nothing until stdout comes back. Keep scripts non-interactive, with `--help` and structured output.

## The security cost

A skill body can embed a command whose *output* lands in context: the agent sees the diff, not the `git diff`. Combined with bundled scripts that is a supply-chain problem: installing a skill installs software that runs with your permissions. Anthropic says to use trusted sources only, audit every bundled file, and treat skills that fetch external URLs as the highest risk. Read the `scripts/` directory before you install. Nothing stops one from reading `.env` and posting it somewhere.

## Distribution

The [skills CLI](https://github.com/vercel-labs/skills) is community-built by Vercel Labs, not Anthropic. It reads a GitHub repo of skills and installs the ones you pick:

```bash
bunx skills add Mark-Life/agent-skills   # or npx / pnpx
```

It asks three things. Which convention: `.agents/skills` works almost everywhere, `.claude/skills` for Claude Code. Which scope: project, versioned with the repo, or global, every session on the machine. And copy versus symlink. **Choose symlink**: one source of truth in `~/.agents/skills/`, linked into every harness directory, so an edit lands everywhere at once. The installer flags risky bundles; mine gets a mid-risk warning because it ships scripts.

My global set: `pr-issue`, `agent-to-human`, `human-to-agent`, `quality-code` for TypeScript, `new-project`, `product`, `context-doctor`. `observability` and Matt Pocock's codebase-architecture skills I install per project. A line in my global `AGENTS.md` pointing at `pr-issue` means "make a PR" reaches the template without me naming the skill.

## What to do

- Move the instruction you retype most often into `~/.agents/skills/<name>/SKILL.md`, symlinked to `~/.claude/skills/`.
- Spend your effort on `description`: it is all the model reads when deciding to load the skill.
- Split anything past a page into a short router body plus linked detail files.
- Set `disable-model-invocation: true` on skills meant for you, not the model.
- Read every bundled script before installing someone else's skill.
- Audit the global scope monthly and delete what you never invoke.

## Links

- Lesson page: https://andrey-markin.com/courses/agentic-coding/skills
- Course: https://andrey-markin.com/courses/agentic-coding.md
- Next lesson: https://andrey-markin.com/courses/agentic-coding/hooks.md
