SKILL.md: The Cross-Agent Open Standard
For a few years every coding agent had its own file: .cursorrules, CLAUDE.md, Codex system prompts, Gemini instructions, a dozen more. Then Anthropic quietly turned their internal Skills format into an open spec โ and within 48 hours the biggest agents in the world were reading each other's files. Today one directory called code-reviewer/ with a SKILL.md inside runs unchanged in Claude Code, Codex CLI, ChatGPT, Gemini CLI, Junie, Kiro, Goose and Cursor. This is the closest the agent world has come to a shared plug.
This page is the practical field guide: what the standard actually is at the byte level, the one clever trick (progressive disclosure) that makes 100-skill installs cheap, exactly which fields break portability the moment you touch them, the honest security picture, and a copy-pasteable portable skill you can ship today.
- Understand what SKILL.md is at the file-format level โ required fields, optional fields, directory layout
- Understand progressive disclosure: why 100 skills cost ~10K tokens at startup, not 100ร the body
- Know the exact vendor extensions that silently break portability across agents
- Write a skill that runs unchanged in Claude Code, Codex CLI and Gemini CLI
- Weigh the security trade-off honestly before installing skills from any marketplace
What the standard actually isโ
Strip away the marketing and the Agent Skills open standard is small enough to hold in your head:
- A directory whose name is the skill's
name - A required
SKILL.mdfile inside it โ YAML frontmatter, then Markdown body - Optional siblings:
scripts/(executables the skill can run),references/(docs the skill can pull in on demand),assets/(templates, images, prompt files), and โ added later โagents/for opt-in vendor-specific config
That's the whole surface area. Two required frontmatter fields do most of the work:
nameโ up to 64 characters,lowercase-with-hyphens, must match the parent directorydescriptionโ up to 1,024 characters, the sentence the agent uses to decide whether to load this skill for the current task
Everything else โ license, compatibility, metadata, and the still-experimental allowed-tools โ is optional and safely ignored by tools that don't understand it. Bodies are Markdown; the community convention is to keep them under ~5,000 tokens, and real-world skills mostly do: median skill size on the largest marketplace is about 1,414 tokens with 90% under 3,935 tokens.
The one clever trick: progressive disclosureโ
The reason SKILL.md works at scale isn't the file format โ it's how agents load it. All conformant agents implement three tiers:
- The agent walks the skills directory and reads only the frontmatter of every SKILL.md. That's roughly 100 tokens per skill. Install 100 skills and you've spent ~10K tokens of context before your first prompt โ cheaper than a single long system message.
- When the model decides (from the descriptions) that a skill is relevant to the current turn, the runtime reads the SKILL.md body into context. Now the model sees the actual instructions โ the checklist, the do/don't, the invocation examples.
- Files under scripts/, references/ and assets/ are NOT eagerly loaded. They come in only when the skill's body tells the model to read them (or run them). A giant reference doc costs zero tokens until the moment it's needed.
This is why the spec caps description so tightly and treats it as a first-class field: it's the only text the model sees when choosing whether to activate the skill. A vague description is the single most common reason a skill that "should work" never fires.
:::tip Write the description last, and rewrite it Once the body of a skill is solid, go back and treat the description as your ad copy. It has one job: help the model recognize the shape of a task that this skill should own. "Reviews pull requests" is bad. "Reviews a PR diff for logic bugs, missing tests, and violated project conventions; use whenever the user asks for a review, code review, or 'look at this PR'" is good. :::
The universal directoryโ
Every conformant agent expects the same layout. This one works everywhere:
code-reviewer/
โโโ SKILL.md # required โ the instructions the agent reads
โโโ scripts/ # optional โ executables the skill can invoke
โ โโโ run-linters.sh
โโโ references/ # optional โ long docs the skill pulls on demand
โ โโโ style-guide.md
โโโ assets/ # optional โ templates, prompt files, snippets
โ โโโ pr-comment-template.md
โโโ agents/ # optional โ VENDOR-SPECIFIC, opt-in only
โโโ openai.yaml # ignored by every non-Codex agent
The agents/ subdirectory is the safety valve for the standard: it lets vendors ship extensions without contaminating the portable core. A file at agents/openai.yaml is Codex-specific and every other agent will simply ignore it. Use it when you need extra power; know it costs you portability.
What actually travels vs what silently doesn'tโ
The whole spec was designed for portability, but real skills in the wild have three failure modes.
| What you use | Portable? | Why |
|---|---|---|
name, description, Markdown body | โ Yes | Core spec. Every conformant agent reads these identically. |
scripts/, references/, assets/ referenced from the body | โ Yes | Directory layout is part of the spec; agents will read them when the body says to. |
license, metadata | โ Yes (safe to ignore) | Optional fields โ non-supporting agents skip without erroring. |
allowed-tools frontmatter | โ ๏ธ Partial | Marked experimental in the spec; syntax across agents is not standardized. Claude Code honors one form, Codex CLI another, most others ignore it entirely. |
Claude Code's when_to_use list | โ Claude-only | Silently ignored by Codex, Gemini CLI and everyone else. |
Claude Code's context: fork subagent flag | โ Claude-only | Non-portable subagent execution semantics โ model behavior differs everywhere else. |
agents/openai.yaml extensions | โ Codex-only | Explicitly vendor-scoped by design. Portable because other agents ignore it. |
The lesson is blunt: stick to name + description + Markdown body + the three optional subdirectories and your skill runs everywhere. Reach into any frontmatter field beyond the core two and you're building for one agent. That's a legitimate choice โ some skills genuinely need it โ but do it deliberately, not because you copy-pasted a template.
How activation actually works (per agent)โ
The spec standardizes the file, not the decision. Each agent still runs its own activation logic on the descriptions it read at startup:
- Claude Code matches the model's read of the current turn against
descriptionand (if present) the Claude-specificwhen_to_uselist; activation is a model decision, not a keyword rule. - Codex CLI uses the same description-driven activation, with optional overrides in
agents/openai.yaml. - Gemini CLI likewise loads descriptions at startup and lets Gemini choose; behavior tracks Gemini's own tool-selection heuristics.
- Cursor, Junie, Kiro, Goose all implement description-driven activation with light variations in weighting.
Practical consequence: a skill that never fires on one agent but works on another almost always has a description problem, not a body problem. Rewrite the description to describe the user request shape, not the skill's internals, and the fire rate goes up on every agent at once.
A portable SKILL.md you can copyโ
Here is a minimal, actually-portable code-review skill. Drop it in ~/.agents/skills/code-reviewer/SKILL.md and it will run in Claude Code, Codex CLI, ChatGPT and Gemini CLI without modification.
code-reviewer/SKILL.md
--- name: code-reviewer description: Reviews a diff or pull request for logic bugs, security issues, missing tests, and violations of project conventions. Use whenever the user asks for a review, code review, PR review, or "look at this diff / patch / change". license: MIT --- # Code Reviewer You review code changes with the discipline of a staff engineer who cares about the codebase surviving contact with reality. You are opinionated but short. You never restate what the diff does โ the user can read it. ## What to look at 1. **Logic bugs** โ off-by-one, wrong operator, swapped arguments, unhandled error path, race, silent catch. 2. **Missing tests** โ any changed behavior without a test is a finding. 3. **Security** โ injection, secrets, missing auth checks, unsafe deserialization, unbounded input. 4. **Project conventions** โ if a CLAUDE.md, AGENTS.md, .cursorrules, or README exists in the repo root, load it and enforce what it says. 5. **Complexity that will hurt future readers** โ call it out, propose the simpler shape. ## What NOT to do - Do not comment on formatting the linter will catch. - Do not praise. No "great work" / "nice refactor". - Do not summarize the diff. Assume the reader read it. ## Output format For each finding, one line: `path:line โ <severity>: <problem>. <concrete fix>.` Severities: ๐ด blocker, ๐ important, ๐ก nit. End with a one-line verdict: "ship", "ship with fixes", or "rework".
Every line of that skill runs on every conformant agent. Nothing in the frontmatter is vendor-scoped. The body uses plain Markdown headings that any agent parses.
Now compare to a non-portable variant โ subtly, it's Claude-only:
Claude-only variant (do not use if you want portability)
--- name: code-reviewer description: Reviews a diff or pull request. when_to_use: - user asks for a review - user pastes a diff context: fork allowed-tools: [Bash, Read, Grep] ---
Three things break portability at once: when_to_use (Claude Code only), context: fork (Claude Code subagent semantics), and allowed-tools (experimental, not honored consistently). Codex will read the description as "Reviews a diff or pull request" โ which is so vague it will barely ever activate โ and ignore the rest.
The security picture (be honest with yourself)โ
The uncomfortable truth about installing skills from any marketplace: a skill is arbitrary instructions to a highly capable agent that runs in your environment with your permissions. The standard specifies no code signing, no sandboxing, no mandatory review, and no runtime permission model. It is by design a text-file spec, not a security spec.
The concrete numbers, from independent analyses of large public skill catalogs (verify at source before quoting):
- Roughly one in three publicly-shared skills contains at least one security-relevant flaw โ over-broad shell instructions, hardcoded secrets, calls to untrusted URLs, or
curl | sh-style bootstrap steps. - A smaller but non-zero set of skills has been flagged as outright malicious โ attempting exfiltration, credential harvesting, or destructive operations.
- Skills inherit whatever the agent inherits. If your agent can read
~/.ssh/, so can any skill you install.
Practical defenses that actually work:
- It is Markdown. It takes a minute. If the description says 'formats prose' and the body contains `curl` to a URL you don't recognize, that is the moment you stop.
- A skill with no scripts/ directory can only tell the model what to do โ it cannot run its own binary. That's a meaningfully smaller blast radius than a skill that ships a shell script.
- Skills are instructions the model can ignore under pressure. The only reliable enforcement lives in the agent's tool-permission layer โ Claude Code hooks, Codex sandboxing, OS-level policies. Treat skills as untrusted collaborators, not as trusted code.
- Vendor the skill directory into your own repo (or a private mirror) instead of chasing latest from a public marketplace. A skill that suddenly changed under you is the same supply-chain risk as an npm package.
For a deeper dive on how skills get compromised and what to check, see Vetting Agent Skills and Coding Agents Under Attack.
When to write a skill vs when to just promptโ
New maintainers of a skill catalog often over-produce them. A useful rule:
- Prompt for a one-off task or a shape you'll use in one project. Skills carry startup cost โ even if it's small โ and clutter your description budget.
- Write a skill when the same instructions apply across many chats or projects (code review, commit-message writing, changelog generation, invoice extraction) and the description would be unambiguous. If you can't write a crisp description, the skill won't fire reliably anyway.
- Reach for a subagent instead when the task needs its own tool set, its own model choice, or genuine parallelism. Skills instruct the main model; subagents run separately. See Subagents.
Related readingโ
- Skills in Claude Code โ the Claude-side surface: activation, tool scopes, hooks, on-disk conventions.
- Skills & Plugins for Pros โ production patterns, testing, catalogs.
- First Skill walkthrough โ hands-on from scratch.
- Coding Agent CLIs Compared โ the same landscape from the CLI angle.
- Porting Prompts Across Models โ the sister topic for the reasoning-layer side of portability.
Check your gripโ
Check yourself
0/4Sources & further readingโ
- agentskills.io โ the open specification and canonical directory.
- Agent Skills Open Standard Explained (paperclipped.de) โ release timeline, adopting tools, marketplace scale.
- Portable SKILL.md across Codex CLI, Claude Code, and 30+ Tools (codex.danielvaughan.com) โ extension surface and per-agent gotchas.
- SKILL.md: The Open Standard for AI Agent Skills (agensi.io) โ protocol view and file structure.
- Anthropic Agent Skills Cross-Vendor Guide (qcode.cc) โ per-agent activation and portability tips.
- AI Agent Skills Guide 2026 (thepromptindex.com) โ practical author-side patterns and security notes.