Craft · November 4, 2026 · 8 min read

Agent Skills: how to write a SKILL.md your agent actually loads

Agent Skills package instructions, scripts and reference files so an agent only pulls them in when a task calls for them. Here is how the loading works, how to write a description that triggers, and the portability and security traps to check before you ship one.

Some links are affiliate links; we may earn a commission at no extra cost to you. As an Amazon Associate I earn from qualifying purchases. Disclosure

If you have ever pasted the same three paragraphs of house rules into an agent's system prompt for the tenth time, Agent Skills are aimed at you. A skill is a folder with a SKILL.md file in it, plus whatever scripts, reference docs and templates the job needs. The agent sees a one-line summary of every installed skill up front, and only reads the rest when a task looks like a match. Anthropic introduced the format in an October 2025 engineering post, and it now has an open specification at agentskills.io that OpenAI's Codex and ChatGPT also build on, according to OpenAI's skills docs.

The format is simple enough that most people get a skill working in an afternoon. Getting one that the agent picks up at the right moment, stays cheap on context and doesn't break when you move it between products takes a bit more care. This piece walks through the parts that matter.

How loading actually works

The whole design rests on what the spec calls progressive disclosure. The specification describes three levels. First, the name and description from each skill's frontmatter are loaded at startup, at roughly 100 tokens per skill. Second, the full SKILL.md body is loaded when the agent decides to activate the skill, and the spec recommends keeping that under 5,000 tokens and under 500 lines. Third, files in scripts/, references/ or assets/ are loaded only when the instructions point the agent at them.

Anthropic's overview docs spell out the practical upshot. When Claude decides a skill fits, it reads SKILL.md from the filesystem with a bash command, and if the instructions mention a reference file it reads that too. Scripts are different: when Claude runs one, "the script code itself never enters context," and only its output costs tokens. A skill can bundle a long API reference or a big lookup table and pay nothing for it until the task needs it.

That has a direct cost angle. Everything you used to keep in the system prompt "just in case" is paid for on every single turn. We went through how that adds up in our piece on context compaction. Moving rarely used procedures out of the system prompt and into skills means the per-turn bill only carries the short descriptions.

There is a ceiling on the always-loaded part too, and it varies by host. OpenAI's docs say Codex limits its initial skills list to 2% of the model's context window by default, or 8,000 characters when the window size isn't known. When too many skills are installed it shortens descriptions first and may drop some from the list with a warning. You can raise the budget with skills.max_context_tokens, up to 10,000 tokens. Claude Code's skills docs truncate each skill's combined description and when_to_use text at 1,536 characters in the listing. If you install fifty skills, assume some descriptions get cut.

The frontmatter rules that bite

The spec requires two fields. name must be 1 to 64 characters of lowercase letters, numbers and hyphens, can't start or end with a hyphen, can't contain two hyphens in a row, and must match the parent directory name. description must be 1 to 1,024 characters and should say both what the skill does and when to use it. Optional fields are license, compatibility (up to 500 characters, for things like "Requires git, docker, jq, and access to the internet"), a string-to-string metadata map, and an experimental allowed-tools field listing pre-approved tools.

Anthropic adds two restrictions on its platform in the best practices guide. Names and descriptions can't contain XML tags, and names can't include the reserved words anthropic or claude. So claude-helper is out even though it passes the open spec's character rules.

The more common trap is product-specific fields. Claude Code accepts extras like disable-model-invocation, user-invocable, context: fork and model. Its docs are blunt about what happens when you take that same folder somewhere else: claude.ai uploads, the Skills API and the package_skill.py packager accept only the six spec fields, and anything else fails with a hard error rather than being ignored. The example error in the Claude Code docs reads "Unexpected key(s) in SKILL.md frontmatter: argument-hint." If a skill needs to travel, keep its frontmatter to the spec's six fields and put host-specific settings somewhere else. Codex does exactly that with an optional agents/openai.yaml file, which holds display details, dependency declarations and an allow_implicit_invocation policy.

Writing a description that triggers

The description is the only thing the agent sees when deciding whether to open your skill, so it does most of the work. Every vendor's guidance lands in the same place: say what the skill does, then say when to use it, with the words a user would actually type.

The spec's own good and bad examples make the point. "Helps with PDFs" is the poor one. The good one is "Extracts text and tables from PDF files, fills PDF forms, and merges multiple PDFs. Use when working with PDF documents or when the user mentions PDFs, forms, or document extraction." The second version names concrete actions and the trigger words.

Anthropic's best practices add one rule people miss: write the description in the third person. "Processes Excel files and generates reports" is right. "I can help you process Excel files" and "You can use this to process Excel files" are both flagged, because the description is injected into the system prompt and a mixed point of view can cause discovery problems. OpenAI's advice for Codex is to front-load the key use case and trigger words so the skill still matches after a host trims the description, which ties back to the truncation limits above.

Think of it as the same job as writing a tool description, which we covered in writing tool descriptions and schemas. Here's a concrete example. Say your team has a release checklist. A description of "Release helper" will never trigger reliably. Something like "Prepares a versioned release: bumps the version, updates CHANGELOG.md, runs the test suite and drafts release notes. Use when the user asks to cut, tag or ship a release" gives the agent the verbs and nouns it needs to match.

Some workflows you don't want triggered on a hunch at all, like a production deploy. Claude Code lets you set disable-model-invocation: true so the skill runs only when someone types /name. Codex's allow_implicit_invocation: false does the same thing, and explicit $skill mentions still work. That's a cheap guard to put on anything destructive, on top of the approval gates you already have around risky tool calls.

What goes in the body, and what goes in files

Anthropic's guide opens with "Concise is key," and its default assumption is that the model is already smart. Only add what it doesn't already know. The example contrasts a roughly 50-token snippet showing which PDF library to call with a roughly 150-token version that first explains what a PDF is. Your conventions, your table names and your weird edge cases earn their tokens. A tutorial on the file format doesn't.

The same guide frames detail as degrees of freedom. Code review can be loose guidance, because many approaches work. A database migration should be low freedom, along the lines of "Run exactly this script" and "Do not modify the command or add additional flags." Match how strict the wording is to how badly things go if the agent improvises.

When the body grows, split it. The spec and Anthropic's guide both say to keep file references one level deep from SKILL.md. Anthropic explains why: when a referenced file points to yet another file, Claude may only preview the nested one with something like head -100 and miss the rest. For reference files longer than 100 lines, put a short table of contents at the top so a partial read still shows what's in there. Organize by domain, so a question about sales only pulls in reference/sales.md and not the finance and marketing schemas sitting beside it.

Scripts are worth adding for anything that has to be done the same way every time. The Anthropic engineering post puts it plainly: sorting a list "via token generation is far more expensive than simply running a sorting algorithm." Make it clear whether the agent should run a script or read it as reference, have scripts handle their own errors instead of leaving that to the model, and give constants a comment saying why they have that value.

Test it like any other agent change

Anthropic recommends building evaluations before you write much of the skill. Run the agent on real tasks without the skill, note where it fails, write three scenarios that cover those gaps, measure a baseline, and then write just enough instructions to pass. The guide also notes there is no built-in way to run these evaluations yet, so you bring your own harness. The approach we laid out in evaluating agent tool calls works fine here. Check whether the skill fired when it should have, whether it stayed quiet when it shouldn't, and whether the task actually came out right.

Test across models, too. The same guide points out that a skill which works for a large model may need more detail for a small, fast one. If you route easy work to cheaper models, run your skill evals on those models as well.

If you want a broader grounding in evaluating and shipping LLM features, AI Engineering by Chip Huyen covers evaluation and production LLM systems in depth and pairs well with the vendor docs.

Treat third-party skills like software

A skill is instructions plus code that your agent will follow with whatever access it has, so installing one is closer to installing a package than reading a doc. Anthropic's overview says to use skills only from trusted sources and to audit everything bundled in one, including scripts and images, looking for unexpected network calls or file access that doesn't match the stated purpose. It also warns that skills which fetch from external URLs are especially risky, since fetched content can carry malicious instructions, and that a trustworthy skill can turn bad if its dependencies change later.

Where the skill runs changes the blast radius. On the Claude API, skills run in a sandboxed container with no network access and no runtime package installs. In Claude Code they get the same network access as any other program on your machine. A skill that's harmless in the API sandbox can do a lot more on a developer laptop. This is the same problem we covered in prompt injection defenses: text an agent reads is input to check, not orders to follow. And if your MCP servers are going to publish skills through the Skills extension, that extension's own rule is that reading a SKILL.md doesn't activate it by itself. The host still has to verify it and apply any user approval.

One last operational note. Skills don't sync between surfaces. Per Anthropic's docs, a skill uploaded to claude.ai isn't available in the API, API skills aren't in claude.ai, and Claude Code reads from ~/.claude/skills/ or a project's .claude/skills/. Codex scans .agents/skills from the working directory up to the repo root, plus user, admin and system locations. The simplest way to keep one source of truth is to check skills into the repo, stick to spec-only frontmatter, and publish to each surface from there.

Sources

Agent Skills specification, Anthropic: Equipping agents for the real world with Agent Skills, Claude docs: Agent Skills overview, Claude docs: Skill authoring best practices, Claude Code: Skills, OpenAI: Build skills for ChatGPT and Codex.

Newsletter

The daily agent toolkit.

New tools, MCP servers and frameworks, in one short email every morning. Free, no spam. Sign up and get the free AI agent cost cheat sheet (PDF).