Write Once, Run Everywhere: Building Agent Skills (SKILL.md) That Work in Claude, Cursor, Copilot and Codex
In short
An Agent Skill is a portable SKILL.md folder that loads the same workflow into Claude Code, Cursor, Copilot, Codex, OpenCode, and Kiro without rewriting it per tool. The key is progressive disclosure: the description matches at discovery, the body loads at activation, and scripts or reference files load only at execution. Author to the portable subset and one skill serves every agent. See how I package this in AI agents and automation.

On this page
- What is a SKILL.md Agent Skill, exactly?
- How does progressive disclosure actually work in a skill?
- What does a real reusable client skill look like?
- Will the same SKILL.md really run in Claude, Cursor, Copilot, and Codex?
- Why is the open SKILL.md standard better than per-tool config?
- How do I test a skill so it fires when I want it to?
- What is the fastest way to start?
An Agent Skill is a folder with a SKILL.md file at its root: a Markdown document with YAML frontmatter that tells any compatible coding agent what the skill does, when to use it, and how to run it. The reason it matters in 2026 is that SKILL.md has become a shared open format, so the same skill folder loads in Claude Code, GitHub Copilot, Cursor, OpenCode, Codex, and Kiro without rewriting it per tool. In this post I walk through how I author one portable skill with progressive disclosure, show a real reusable skill I ship to clients, and explain why I stopped rebuilding the same workflow three times for three different agents.
What is a SKILL.md Agent Skill, exactly?
A SKILL.md skill is a self-contained folder that packages instructions, optional scripts, and reference files so an agent can load a procedure on demand instead of you re-explaining it every session. Think of it as a function the agent can call in plain language, except the "function body" is Markdown plus whatever files you bundle next to it.
The minimum is one file. A skill named pr-review lives at pr-review/SKILL.md, and that file has two parts: YAML frontmatter and a Markdown body.
---
name: changelog-entry
description: >
Generate a changelog entry from staged git changes following
Keep a Changelog format. Use when the user asks to update the
changelog, write release notes, or document changes for a release.
---
## Changelog Entry
When the user wants a changelog entry:
1. Run `git diff --staged --stat` to see what changed.
2. Group changes into Added, Changed, Fixed, Removed.
3. Write entries in past tense, user-facing language, one line each.
4. Insert them under the `## [Unreleased]` heading in CHANGELOG.md.
Skip internal refactors that have no user-visible effect.
That is a complete, working skill. The agent reads the description, decides whether the current request matches, and if it does, pulls the body into context and follows it. Everything else in this post is about making that loading smart instead of dumping everything at once.
How does progressive disclosure actually work in a skill?
Progressive disclosure means the agent only loads what it needs, in three stages: discovery, activation, and execution. This is the single most important idea in skill authoring, because context windows are finite and a skill that front-loads 4,000 tokens of instructions will get ignored or will crowd out the actual task.
Here is how the three stages map to what lives where:
| Stage | What loads | Token cost | Lives in |
| Discovery | name + description only | ~30-80 tokens | YAML frontmatter |
| Activation | Full SKILL.md body | a few hundred to ~2k tokens | Markdown body |
| Execution | Referenced files, scripts, templates | loaded only when read/run | sibling files |
| Concern | Portable choice | Tool-specific detail | |
| File name | SKILL.md at folder root | universal | |
| Required fields | name, description | universal | |
| Trigger logic | natural-language phrases in description | universal | |
| Bundled scripts | plain shell or Python, called by relative path | runtime must be present | |
| Install path | the skills directory the tool scans | differs per tool | |
| Extra frontmatter | avoid relying on it | some tools add their own keys |
My rule: write to the lowest common denominator. Put all trigger logic in the description as plain phrases, reference scripts by relative path, and never depend on a frontmatter key that only one tool reads. If a tool needs a vendor-specific field, I add it as an extra key the others will ignore, rather than restructuring the skill.
The one real portability risk is scripts. A skill that shells out to gh or python assumes that runtime exists wherever the skill runs. I keep scripts dependency-light and document the requirement in the body so the agent can degrade gracefully if a tool is missing.
Why is the open SKILL.md standard better than per-tool config?
Because you author the workflow once and it follows the developer instead of the tool. Before this format settled, the same "write release notes our way" workflow meant a Claude project instruction, a Cursor rule file, and a Copilot custom instruction, three copies that drifted out of sync the moment one changed. A single SKILL.md collapses that into one source of truth.
Three concrete payoffs I see in client work:
- Versioning. A skill is a folder. It goes in git, gets reviewed in a PR, and ships with the repo. Per-tool config usually lives in scattered settings that no one reviews.
- Onboarding. A new hire clones the repo and inherits every team skill automatically. There is no "and now configure your editor" step.
- No vendor lock. If a team moves from one agent to another, the skills come along. I have migrated clients between tools without rewriting a single skill body.
This is the same instinct behind treating agent infrastructure as portable assets rather than disposable config. If you are working at the protocol layer too, it pairs naturally with migrating a remote MCP server to the stateless spec ↗ and with auditing a third-party MCP server before you trust it ↗, since skills and MCP servers are the two halves of how I package reusable agent capability for clients.
How do I test a skill so it fires when I want it to?
Test the description first, because a skill that never activates is worse than no skill. The fastest check is to open a fresh session and phrase a request the way a real user would, then see if the agent picks the skill up without you naming it.
My checklist before I hand a skill to a client:
- Trigger test. Ask for the task in three different phrasings. If it only fires when I say the skill name, the
descriptionis too narrow. Add the phrasings that failed. - Anti-trigger test. Ask for something adjacent but wrong. If a
release-notesskill fires when I ask for a commit message, the description is too greedy. Tighten it. - Cold execution. Run the skill in a session with no prior context. The body must stand alone, since the agent has no memory of how I built it. This is the same constraint a sibling agent faces, which is why I write bodies as if explaining to someone who just walked in.
- Missing-runtime test. Run it where the bundled script's runtime is absent and confirm the body tells the agent what to do instead of failing silently.
I keep descriptions in a "Use when..." form because it reads as the matcher it actually is. "Use when the user asks to write release notes, prep a release announcement, or summarize what shipped this sprint" beats "Generates release notes" every time, because it hands the agent the exact phrases to match against.
If you want to render skill output inside a chat UI rather than just dropping Markdown, that overlaps with shipping an MCP app with interactive UI ↗, which is the path I take when a client wants the result to look like a product feature instead of a transcript.
What is the fastest way to start?
Make a folder, add one SKILL.md with a sharp description and a five-step body, and test it in a real session before adding anything else. Resist the urge to bundle scripts and reference files on day one. Most of my skills started as a single file and only grew a reference/ folder once the body got long enough to hurt activation.
The progression I recommend:
- One file, plain body, sharp description.
- Move long reference material to a sibling file the body reads on demand.
- Add a script only when the agent is doing repetitive deterministic work better handled by code.
- Commit the folder to the repo so the whole team and every tool inherits it.
If you are sitting on a workflow you explain to your agent the same way every week, that is a skill waiting to be written. I help teams turn those repeated explanations into portable, versioned skills and the agent infrastructure around them, and you can reach me through my contact page ↗ if you want a hand scoping the first few.
The short version: author to the portable subset, lean on progressive disclosure so activation stays cheap, and keep taste in reference files and logic in the body. Do that and one skill folder serves every agent your clients will ever use.
FAQ
What is a SKILL.md Agent Skill?
It is a self-contained folder with a SKILL.md file (YAML frontmatter plus a Markdown body) that tells any compatible agent what a workflow does, when to use it, and how to run it.
What is progressive disclosure in a skill?
It is loading only what the agent needs in three stages: the name and description at discovery, the full body at activation, and bundled files or scripts only at execution when the body tells the agent to read them.
Will the same SKILL.md run in Claude, Cursor, Copilot, and Codex?
Yes for the core format, since those tools adopted the open Agent Skills standard in early-to-mid 2026, though the install location and a few optional frontmatter fields differ per tool.
Why use the open SKILL.md standard instead of per-tool config?
Because you author the workflow once as a versioned git folder that follows the developer across tools, instead of maintaining drifting copies as Claude, Cursor, and Copilot config separately.
What is the most important part of a skill to get right?
The description field, because it is the matcher the agent reads at discovery, so it should list concrete trigger phrases in a Use-when form rather than a vague summary.
Working on something like this?
I build web apps, AI features, and mobile products for clients. If this article matches a problem you have, tell me about it.
Start a conversationMalik Hamza Shabbir · Full-Stack & AI Engineer
I build full-stack and AI products solo: a reputation SaaS in production, RAG pipelines, and React Native apps. I write from what I ship, not from documentation summaries.
Related articles
Claude Code vs Cursor vs Codex for Real Client Work 2026
Pricing converged at $20/$200 and SWE-bench scores sit within a point, so workflow decides. Real cost-per-feature numbers from paid client projects.
RAG, Fine-Tune, or Just Prompt? A 2026 Decision Tree for Million-Token Context Windows
Cheaper long context in 2026 broke the old always-RAG advice. Here is the decision tree I use: when full-context prompting beats a pipeline, when RAG is mandatory, when fine-tuning earns its keep, plus the hybrid stack and a cost and latency comparison.
On-Device or API? Shipping Structured Extraction With Apple 3rd-Gen Foundation Models vs a Cloud LLM
Apple's 3rd-gen on-device Foundation Models let mobile teams run classification, routing, and structured extraction for free, on-device, and offline. Here is the decision framework I use to choose on-device vs a cloud LLM, where on-device tops out, and the hybrid fallback pattern that sends only the hard cases to a paid API.