Writing a SKILL.md that works across Claude Code, Codex, and more
Published 2026-05-18 by Owner
The SKILL.md format is now honored by Claude Code, Codex CLI, Gemini CLI, Copilot, Cursor, and several community tools. “Honored” is not the same as “identical,” so a skill that works everywhere is one written to the common subset on purpose, not by accident. For why this matters now, see Codex pulls skills into the @ menu.
The portable core
Every tool that reads SKILL.md agrees on exactly two things: YAML frontmatter with a name and a description, followed by Markdown instructions. That is the entire portable contract. Keep everything load-bearing in that body text, where every tool can see it.
---
name: changelog-entry
description: Add a changelog entry in the project's Keep a Changelog format
---
When asked to add a changelog entry:
1. Open CHANGELOG.md and find the `## [Unreleased]` section.
2. Add the entry under the correct subheading: Added, Changed, Fixed, or Removed.
3. Write one line, imperative mood, no trailing period.
4. Do not edit released version sections.
That skill runs unchanged on Claude Code and Codex because it relies on nothing but frontmatter and instructions. It is boring on purpose. Portable skills are boring.
The description is the routing signal
Across every tool, description is what the agent matches against to decide whether the skill applies to the current request. Write it as a trigger, not a title: state when to use the skill and what it produces. “Add a changelog entry in Keep a Changelog format” routes reliably because it names the situation. “Changelog helper” does not, because the agent cannot tell from it when the skill should fire. A skill that never triggers is not portable; it is just absent everywhere equally.
What varies by tool
Keep these out of the portable core, because they are where tools disagree:
- Scripts. Bundled executable scripts and how they are invoked are not uniform. If the skill must run code, describe the command in the instruction body so the agent runs it through its normal tool use, rather than depending on a tool-specific script-execution convention that silently does nothing elsewhere.
- Resource paths. How a skill references bundled files differs between tools. Prefer paths relative to the skill file and state them explicitly in the body so a human or an agent can resolve them without tool-specific magic.
- Placement. Most tools auto-discover skills in a known directory; Cursor currently needs the skill placed manually. Document the install location inside the skill’s own instructions so it can be placed correctly anywhere.
Anti-pattern: the single-tool hook
The fastest way to make a skill non-portable is to lean on one tool’s proprietary extension — a vendor-specific frontmatter key, an assumed built-in command, an environment only one agent provides. It works in the demo on the tool you wrote it for, and it silently does nothing in the next tool, with no error to tell you why. If a capability is not in the portable core, put it in the instructions as an explicit step the agent performs, not as a hook you assume the host provides for you.
Verify on two tools before you trust it
Portability is a claim you test, not one you assume because the frontmatter looks generic. Run the skill once on Claude Code and once on Codex against the same task. If the outcome differs, the difference is almost always one of two things: something you left in the frontmatter that only one tool reads, or an assumption about script execution. Move it into the instruction body and run both again. Two tools is the minimum that proves anything; one tool only proves the skill works on the tool you wrote it for, which was never in doubt.