Skills are one-offs. If you want an ecosystem, you need plugins.
updated
Confidence maps a debate still open; the layer model is my inference, the review system my own build
“I suppose it is tempting, if the only tool you have is a hammer, to treat everything as if it were a nail.” — Abraham Maslow
You wrote a skill. It’s good. Now you want it to lean on another skill — call it, require it, ship the two together so installing yours pulls in the one it depends on. So you go looking for a dependencies field.
There isn’t one.
That’s not an oversight you can route around. A skill has no dependency the platform resolves; the reuse unit for a skill, I’ll argue, is never another skill. The Agent Skills spec hands you a folder, a SKILL.md, and progressive-disclosure loading — plus a compatibility line that’s a prose hint (“requires Python 3.14+”), not something the platform resolves or installs. It hands you no way to say “this needs that skill, version 2 or higher.”
The first instinct is to copy skill B into your own plugin. That’s vendoring, and it holds right up until B moves: no version pin, silent drift, every update a manual fan-out across every copy. Reuse you can actually maintain lives somewhere with a version — and which layer you land on depends entirely on what you’re trying to reuse.
Bottom line up front
Skills are one-offs. If you want an ecosystem, you need plugins. And the useful decision isn’t “skill or plugin” — it’s picking the reuse layer by what you’re reusing:
| What you’re reusing | Layer | You get | You don’t get |
|---|---|---|---|
| Nothing — a bare skill | Agent Skill | Progressive disclosure | Any deps — the only portable move is probe-and-prompt |
| Deterministic / mechanical logic | A shared tool (npm/pip package) | Real semver (from the package manager) + cross-language over stdio | A server — you don’t need one |
| A bundle of skills/rules | A Claude Code plugin | Real deps + semver, auto-installed transitively | Skill-granular deps — it’s plugin-granular |
| A judgment handoff | A versioned schema + an orchestrator | Portable routing, no hard-named skills | Direct skill-to-skill calls |
| Stateful / networked capability | MCP | A running server, live state | Anything cheap |
Everything below is that table, with the receipts.
The bare skill: probe-and-prompt is the portable ceiling
A skill can’t depend on anything, so its only portable move is to look around at runtime and ask: check whether skill B is present and, if it isn’t, tell the user to install it. That’s probe-and-prompt. (A skill can also nudge the agent toward B in prose, but that nudge doesn’t travel across spec-compliant agents — more below.) Probe-and-prompt is the ceiling you can actually rely on.
Watch the limit, because it’s sharp. Probe-and-prompt handles presence, not version. A skill’s frontmatter can carry a version string, but there’s no standard, runtime-resolvable way for one skill to read another’s and act on it — no handshake, no resolver. You can learn that skill B is present. You can’t make the platform guarantee it’s the B you need. And the failure is quiet: the skill prints setup steps for engine v1, v2 renamed the command, the user follows stale instructions, and nothing errors. Accept that, or move up a layer.
Deterministic reuse: ship a tool
If the thing you’re reusing is mechanical — pure functions, same input same output — make it a tool and publish it as an npm or pip package. Yes, a skill has a scripts/ directory, and one skill dropping its code there is fine. It stops being fine the moment a second skill needs the same logic, or you want a version pin: then it’s a package the package manager resolves, not a file copied into every skill’s scripts/. Now you have real semver dependencies and no server to babysit. This is the right home for an engine’s plumbing: a review engine’s post-to-GitHub, or its diff→targets mapping. The tool speaks a JSON schema over stdin/stdout, so it doesn’t care what language called it. A Node skill can shell out to a Python tool and neither side has to know the other exists.
A bundle of skills or rules: ship a plugin
If what you’re reusing is a set of skills or rules that travel together, that’s a Claude Code plugin. Plugins have real dependencies with semver ranges, and a dependency is installed transitively — depend on plugin X and its plugins come with it.
One catch, and it’s load-bearing: the granularity is the plugin, not the skill. You can’t reach into another plugin and pull out one lone skill. If a skill needs to be shared, it goes in its own plugin (or a shared one) and you depend on that. Deps that cross marketplaces need an allowlist. Design the boundaries as plugins from the start and this is a non-event; retrofit it later and it’s surgery.
A judgment handoff: a schema and an orchestrator
Sometimes skill A doesn’t need skill B’s code — it needs B’s verdict. Don’t reach for the phone. Emit a typed artifact — a finding.v1 — and let a thin command, agent, or watcher route that artifact to whatever consumes the schema today.
Never hard-name skill B from inside skill A. There’s no portable, declared way for one skill to call a named other — an activated skill can nudge the agent toward B, but that behaviour doesn’t travel across spec-compliant agents (spec issue #95), and hard-naming rebuilds the dependency the platform left out — deliberately, I read it, given its stated composition-as-emergent posture. Route on the schema and you can swap the consumer without touching the producer.
A stateful or networked capability: MCP
Only now does a running server earn its keep — live state, a network resource, something that has to persist between calls. For reusing a pure function it’s absurd overhead. A server, a protocol, and a lifecycle to hold a function that could have been a fifteen-line package.
The receipt: one review system, three layers
Here’s the thing I actually built. It’s a code-review system, and it’s three decoupled layers on purpose — the model above isn’t a diagram I drew after the fact, it’s the shape the build forced.
1 — the engine is a tool. A CLI that lives outside the plugins folder and gets invoked as a subprocess. No server. Not vendored into a skill where it’d be trapped and unversioned. It’s the deterministic layer, so it’s a tool, full stop.
2 — a thin launcher plugin. It ships exactly one skill, and that skill’s entire job is to detect whether the engine is installed and print the setup steps if it isn’t. Probe-and-prompt, shipped in production. It checks presence, not version — the limitation named earlier, accepted rather than papered over.
3 — the rules live in domain plugins. Each declares the launcher in its dependencies map — the field skills lack, plugins have, with a semver range — validated before anything launches. The rules get provisioned into an isolated child agent — via --plugin-dir — and that child’s own top-level loop is what activates the rules skill. Nobody calls a skill from a skill. An orchestrator provisions; the child consumes. Judgment-handoff, with the wiring showing.
Concretely, the wiring is a manifest field plus a runtime check — the two artifacts a bare skill can’t give you:
// a domain plugin's manifest — declaring the dependency a skill has no field for
{ "name": "review-rules-web", "dependencies": { "review-launcher": "^2.0.0" } }
// the plugin system resolves the semver range and installs it transitively, before load.
// the launcher skill, at runtime — presence, not version (the ceiling from earlier):
if (!engineOnPath()) return tell("Engine not found — install it: npm i -g review-engine");
The manifest line is the plugin row; the runtime check is the bare-skill row — one system, both, each dependency declared exactly where the platform lets it be.
The launcher is the seam worth staring at. As a skill it has no deps — it just probes and prompts, the bare-skill row. As a plugin it’s the thing the domain plugins depend on, the plugin row. One artifact, both rows: the layers aren’t separate boxes, they’re where you attach the dependency you actually need.
The seam I like most isn’t in any language at all. The engine is Python. The review tool that drives it is Node. There is no import bridging them and there was never going to be — it’s solved at the process-and-schema boundary, JSON over stdio, each side monolingual and none the wiser. That seam is the argument in miniature: reuse didn’t come from sharing code, it came from picking the layer where the two halves could meet.
Why this is the answer today, not forever
Skill-to-skill composition is one of the most contested corners of the Agent Skills spec right now. There are competing proposals — soft prerequisite hints, hard versioned dependencies modelled on npm, “skill stacks,” package distribution — some open, some already floated and closed, none merged. A dedicated skill-composition PR was opened and closed. The platform’s stated posture is that composition is emergent, and that the heavy lifting belongs to MCP. So none of this is settled dogma. It’s the arrangement that works while the spec argues with itself — and when the argument resolves, the bare-skill row is the one most likely to grow a real requires. The other four layers were load-bearing before the debate started and will be after it ends.
Pick the layer by what you’re reusing. That’s the whole post.
How sure I am: This maps a live, unsettled debate as of mid-2026. The layer model and the “pick by what you’re reusing” rule are my inference; the three-layer review system is my own build and the lived evidence for it. The spec-issue positions are other people’s proposals, not decisions.
Sources
- Agent Skills spec — agentskills.io (note: no
requiresfield in the skill schema). - Anthropic, Equipping agents for the real world with Agent Skills (engineering blog, 16 Oct 2025) — composition-as-emergent / MCP-for-heavy-lifting posture.
- Claude Code plugin documentation — plugin dependencies and semver ranges; transitive install; cross-marketplace allowlist.
- Agent Skills spec-repo issues (agentskills/agentskills): #100 (best practice on a skill depending on another), #95 (inconsistent skill-to-skill invocation across implementations), #110 (skill dependencies with version validation), #28 (skill set / skill stack), #90 (prerequisite/related-skill fields — closed); plus the closed composition PR #89 (skill composition with type checking) and distribution RFCs #81 (npm) / #255 (
.well-knowndiscovery). - Model Context Protocol documentation (servers, state, lifecycle).
Related: Your Skills Are a Codebase, Not a Junk Drawer (the sibling — what to do once you have too many); A Pipeline Is What It Refuses to Forward (the same typed-artifact argument made for bandwidth rather than portability); Keep the Factory, Ship the Result (why the thing you distribute isn’t the thing you run).