One SKILL.md for every agent: the 2026 compatibility matrix

Which frontmatter fields Claude Code, Cursor, Codex, GitHub Copilot, Gemini CLI, and the rest actually honor, where each one reads skills from, and a portable template that loads unchanged in all of them.

Contents

The Agent Skills specification is small enough that the entire required surface is two fields. That is why a skill written for Claude Code loads in Cursor, and a skill written for Codex loads in GitHub Copilot. It is also why people get surprised: each agent layers its own optional fields, its own directories, and its own invocation syntax on top, and none of them document what the others do.

This is the reference that fills that gap. Three matrices (directories, frontmatter, invocation), a note on what each agent does with unknown fields, and a template that loads unchanged everywhere.

The spec baseline

From agentskills.io, the fields every conforming agent understands:

FieldRequiredConstraint
nameYes1 to 64 chars; lowercase letters, digits, hyphens; no leading, trailing, or double hyphens; equals the folder name
descriptionYes1 to 1,024 chars; what it does and when to use it
licenseNoLicense name or path to a bundled license file
compatibilityNoUp to 500 chars of environment requirements
metadataNoString-to-string map
allowed-toolsNoExperimental; space-separated pre-approved tools

Progressive disclosure is universal: name and description load at startup (about 100 tokens per skill), the body loads on activation (recommended under 500 lines and about 5,000 tokens), and scripts/, references/, assets/ load on demand.

Matrix 1: where each agent reads skills

AgentProject scopePersonal scopeAlso scans
Claude Code.claude/skills (plus parents to repo root, nested subfolders on first touch)~/.claude/skillsPlugins, managed settings dir, ~/.claude/skills/synced
Cursor.cursor/skills, .agents/skills~/.cursor/skills, ~/.agents/skillsClaude and Codex dirs in the repo
OpenAI Codex.agents/skills (walks parents to repo root)~/.agents/skills/etc/codex/skills, built-ins
GitHub Copilot.github/skills, .claude/skills, .agents/skills~/.copilot/skills, ~/.agents/skills
Gemini CLI.agents/skills~/.gemini/skills
Antigravity.agents/skills~/.gemini/antigravity/skills
Windsurf.windsurf/skills~/.codeium/windsurf/skills
Cline.agents/skills~/.agents/skills
Roo Code.roo/skills~/.roo/skills
OpenCode.opencode/skills~/.config/opencode/skills
Goose.goose/skills~/.config/goose/skills
Amp.agents/skills~/.config/agents/skills
Warp.agents/skills~/.agents/skills
Kiro.kiro/skills~/.kiro/skills

Two paths cover most of the ecosystem. .claude/skills reaches Claude Code, Cursor, and Copilot. .agents/skills reaches Cursor, Codex, Copilot, Gemini CLI, Antigravity, Cline, Amp, Warp, and most newer independent agents. No single path reaches everything, which is the problem a multi-target installer solves:

npm i -g skillmds
skillmd add anthropic/skill-creator          # writes to every agent detected on this machine
skillmd add anthropic/skill-creator -a cursor -a codex
skillmd add anthropic/skill-creator -g       # personal scope for each detected agent

The full 60-plus-agent table with a machine-readable guide per agent lives at skillmd.com/agents.

Matrix 2: frontmatter fields by agent

Read means the field changes behavior. Ignored means it loads fine and does nothing. Rejected means the file fails to load.

FieldClaude Codeclaude.ai uploadCursorCodexCopilot
nameReadReadReadReadRead
descriptionReadReadReadReadRead
licenseReadReadIgnoredIgnoredIgnored
compatibilityReadReadIgnoredIgnoredIgnored
metadataReadReadReadIgnoredIgnored
allowed-toolsRead (per-turn grant)ReadIgnoredIgnoredIgnored
disable-model-invocationReadRejectedReadIgnored (use openai.yaml)Ignored
user-invocableReadRejectedIgnoredIgnoredIgnored
disallowed-toolsReadRejectedIgnoredIgnoredIgnored
argument-hintReadRejectedIgnoredIgnoredIgnored
modelReadRejectedIgnoredIgnoredIgnored
context: fork, agent, backgroundReadRejectedIgnoredIgnoredIgnored
hooksReadRejectedIgnoredIgnoredIgnored
paths (globs)IgnoredRejectedReadIgnoredIgnored
icon, colorIgnoredRejectedReadIgnoredIgnored

The claude.ai column is the one that surprises people. Claude Code is permissive, but uploads to claude.ai, the Skills API, and packaging with package_skill.py from anthropics/skills accept only the six spec fields and fail with an “Unexpected key(s) in SKILL.md frontmatter” error for anything else. If a skill is meant for both Claude Code and claude.ai, it has to be spec-clean.

Codex keeps its extensions out of the frontmatter entirely. A sidecar agents/openai.yaml inside the skill folder carries interface (display name, icons, brand color), policy.allow_implicit_invocation, and dependencies.tools for MCP requirements. Other agents ignore the sidecar.

Matrix 3: invocation and control

BehaviorClaude CodeCursorCodexChatGPTCopilot
Auto-trigger by descriptionYesYes (narrowable by paths)YesYesYes
Explicit trigger/name [args]/ picker (one message)$name@nameDescription-based; prompt files for explicit
Keep active for a sessionContent persists once loadedCustom Mode (Option/Alt+Enter)Mention againMention againRe-select
Manual-onlydisable-model-invocation: truedisable-model-invocation: trueopenai.yaml policyopenai.yaml policyNot available
Agent-only (hidden)user-invocable: falseNoNoNoNo
Arguments$ARGUMENTS, ${CLAUDE_SKILL_DIR}, ${CLAUDE_PROJECT_DIR}Free textFree textFree textFree text
Disable via configskillOverrides in settingsRemove folder[[skills.config]] enabled = falseRemove folder
Live reloadYesRe-open pickerRescan on start
Listing budgetNot publishedNot published2% of context or 8,000 charsSameNot published

What each agent does with unknown fields

Every major implementation ignores frontmatter keys it does not recognize. This is what makes cross-agent skills work in practice: a Claude skill with context: fork loads in Cursor and runs inline; a Cursor skill with paths loads in Codex and applies everywhere instead of only on matching files. The behavior degrades gracefully rather than failing.

The two exceptions: claude.ai uploads reject unknown keys (above), and any agent will reject a name that violates the spec’s character rules or does not match the folder. Run a linter before publishing:

skillmd lint ./my-skill

That checks name length and characters, description length, missing license, and a body that is too short or has no heading.

Cloud and remote behavior

The rule is identical across the three agents that document it:

AgentRemote surfacePersonal skills available?Repo skills available?
Claude CodeCloud sessions, Cowork, routinesNo (claude.ai-enabled skills sync instead)Yes
CursorCloud Agents, SSH, self-hosted workersNoYes
GitHub CopilotCloud coding agent, code reviewNoYes

Anything that must work remotely goes in the repository.

A template that loads everywhere

---
name: release-notes
description: "Drafts release notes from merged pull requests since the last tag, grouped by type (features, fixes, breaking changes), in this project's house style. Use when asked to write, draft, or generate release notes or a changelog entry."
license: MIT
metadata:
  author: your-handle
  version: "1.2"
---
## Steps
1. Find the most recent tag and list merged PRs since it.
2. Group by conventional-commit type. Breaking changes first.
3. Write one line per change in the imperative mood, linking the PR.
4. Read [references/style.md](references/style.md) for tone and banned words.
5. Output Markdown only. Do not commit or push.

## Edge cases
- No PRs since the last tag: say so instead of inventing entries.
- A PR with no conventional prefix: classify by reading its diff summary.

Why this loads unchanged in every agent:

  • Only spec fields in the frontmatter.
  • The folder is named release-notes, matching name.
  • The body is short, starts with the procedure, and pushes style rules to references/.
  • File references are relative and one level deep.
  • No ${CLAUDE_...} substitutions, no $ARGUMENTS, no tool grants.

To make it manual-only in the agents that support it, add disable-model-invocation: true (Claude Code, Cursor) and an agents/openai.yaml with policy: { allow_implicit_invocation: false } (Codex, ChatGPT). Everyone else will still auto-trigger it, so keep side effects out of the body or say so in the description.

Publishing for every agent

If the skill is for other people, publish it to a registry rather than a Gist. Registries index the description so people find the skill by task, show which agents authors tested against, and give installers a one-command path into whichever agent they use. SkillMD lists 25,000+ skills across 60+ agents, runs a safety review on every public listing, and exposes a JSON search API at api.skillmd.com/v1/search so agents can look skills up themselves. The publishing guide walks through the flow.

Further reading

Frequently asked questions

Which SKILL.md frontmatter fields work in every agent?

name, description, and license. The spec also defines compatibility, metadata, and allowed-tools, but only name and description are required and universally used for triggering. Everything beyond those is agent-specific and ignored elsewhere.

What is the safest directory to commit skills to for a mixed team?

.claude/skills is read natively by Claude Code, Cursor, and GitHub Copilot. .agents/skills is read by Cursor, Codex, Copilot, Gemini CLI, Cline, Warp, and many independent agents, but not Claude Code. Committing to .claude/skills and installing to other agents with a CLI covers the most tools.

Will agent-specific fields break a skill in other agents?

No. Every major implementation ignores frontmatter keys it does not recognize. The one exception is uploading to claude.ai or the Skills API, which rejects non-spec keys with an error. Keep Claude Code extras out of skills you also upload there.

How do I make a skill manual-only across agents?

Set disable-model-invocation: true in the frontmatter, which Claude Code and Cursor honor, and add policy.allow_implicit_invocation: false in agents/openai.yaml for Codex and ChatGPT. GitHub Copilot has no equivalent switch; use a prompt file there.

How do I install one skill into every agent at once?

The SkillMD CLI detects every supported agent on your machine and writes the skill to each one's directory: npm i -g skillmds, then skillmd add owner/name. Add -a agent-id to target one agent or -g for personal scope.