A skill is data, not code
An agent skill -- in the sense that's spread from Claude Code's .claude/skills/ convention to Cursor's project rules, Codex's AGENTS.md, and Windsurf's .windsurfrules -- is a plain text file: a short YAML frontmatter block (a name and a description) followed by markdown instructions. It contains no executable logic. It cannot call an API, read a file, or run a subprocess on its own. Everything a skill does, it does by being read into an LLM's context and followed as an instruction, the same way a human employee follows a runbook.
That single design choice -- skill as inert text, never as code -- is the whole architecture. Every property people actually want from a "skills" system (portability across tools, independent versioning, safe composition, auditability) falls out of keeping the skill decoupled from the runtime that executes it. This article works through why that separation matters, how the discovery/loading mechanism that makes it useful actually works, and where the pattern breaks down if you get the boundary wrong.
The coupling problem this pattern solves
Before portable skill files, the default place to put agent behavior was the system prompt: one large block of instructions, owned by whoever built the agent, baked into that specific application. This works until you need the same behavior in a second place -- a different tool, a different team's agent, a different host entirely -- and discover the instructions are welded to that first system prompt's assumptions about available tools, response format, and surrounding context.
The failure mode is familiar from software generally: logic that should be a reusable module ends up copy-pasted and drifting. A code-review methodology written into one product's system prompt gets copied into a second product's system prompt, and six months later the two have quietly diverged -- one catches a class of bug the other doesn't, and nobody notices until a customer does. The fix in software is the same fix here: extract the reusable part into its own artifact with a stable interface, and let multiple runtimes depend on that artifact instead of on each other's internals.
A skill file is that extraction. It has exactly two things a runtime needs to know about it from the outside -- a name and a description -- and everything else is opaque instruction text the runtime injects verbatim. The runtime doesn't parse the skill's logic, branch on it, or need to understand what's inside. That opacity is a feature: it's what lets a skill move between runtimes that share nothing else.
The three things decoupling actually buys
Portability. Because a skill only requires a host that can read text and inject it into a model's context, the same file works anywhere that minimal contract holds. This isn't a hypothetical: this site's own code-review skill ships with install notes for four different tools, and the file itself doesn't change between them -- only where you save it changes.
Independent versioning. Because the runtime treats a skill as an opaque dependency rather than inlined logic, a skill can be rewritten, re-scoped, or fixed without touching the runtime or any other skill. This is the same benefit a shared library gets from being a separate package instead of vendored, pasted-in code: one version bump, one changelog entry, every consumer picks it up the same way.
Composability without coordination. A runtime that has fifty skills installed doesn't need fifty special cases in its own code -- it needs one generic mechanism (match a request against each skill's description, load the best match's body into context) that works identically whether there are five skills or five hundred. The skills themselves don't need to know about each other either. Compare this to a monolithic system prompt trying to cover fifty scenarios: every addition risks interacting with every existing instruction, because they all share one undifferentiated block of text.