Agent Skills Are Speed-Running Package Management
In four months skills went from loose markdown to registries, installers and a content-hash lockfile. My own machine has 67 entries in ~/.claude/skills and 61 of them are broken symlinks pointing at a source that no longer exists. The ecosystem is rediscovering npm's primitives in npm's original order, which puts provenance last.

Here is the state of the skills directory on the machine I do most of my work on.
$ ls -1 ~/.claude/skills | wc -l67$ cd ~/.claude/skills && for f in *; do [ -e "$f" ] || echo "$f"; done | wc -l61Sixty-seven entries, sixty-one of which are symlinks into a directory that no longer has anything in it. I installed those in May from a source I did not record, and I could not now tell you what any of them contained, who wrote them, or what version I got. The six that resolve are five skills I wrote by hand and one I installed in August.
That directory is a fair picture of where this ecosystem is. Skills went from a convention for organising markdown to a distributed artifact class with registries, installers and a lockfile in about four months, and they are arriving at each primitive in roughly the order npm arrived at them. That order put distribution first and provenance last, and it is the reason npm spent fifteen years cleaning up after itself.
The distribution layer showed up first, as it always does#
Anthropic publishes a public registry. Google publishes a second one covering GKE, BigQuery, Spanner, Cloud Run, the Ads API and a few dozen others. A format stops being one vendor’s local convention at the moment a competitor adopts it, and that has happened.
The install path is the interesting part. Google’s registry does not ship its own installer. The documented command is:
npx skills add google/skillsThat is vercel-labs/skills, a third party’s CLI, which describes itself as “the CLI for the open agent skills ecosystem” and supports 76 or so agents. So one vendor’s skills reach your disk through another vendor’s installer, from a git URL, with the client deciding what to trust. Aggregation arrived on schedule too: agentic-awesome-skills indexes over 2,000 skills and calls itself a control plane, with a catalogue, a selection step and a durable aas-stack.json manifest, because once there are enough packages you need tooling to decide which ones to install.
Registry, installer, aggregator, manifest. Four of npm’s five load-bearing pieces, in four months.
The lockfile has already arrived, and it is version 3#
I went looking for the missing fifth piece expecting to find nothing, and found this instead:
{ "version": 3, "skills": { "humanizer": { "source": "blader/humanizer", "sourceType": "github", "sourceUrl": "https://github.com/blader/humanizer.git", "skillPath": "SKILL.md", "skillFolderHash": "523374dee72d67c7b2b5f858ea0094ffda49c3ac", "installedAt": "2026-08-06T06:39:45.397Z" } }, "dismissed": {}}A source URL, a content hash over the skill folder, an install timestamp. That is a lockfile, and the schema is already on its third revision, which tells you how fast this is moving. The plugin path has similar bookkeeping: of the five plugins installed on this machine, four record both a semantic version and a gitCommitSha, and one records "version": "unknown" with no commit at all.
So the reasonable version of my claim is not that skills have no package management. They have most of it. The gap is narrower and worse.
A content hash is not provenance#
skillFolderHash tells me the humanizer skill has not changed since the sixth of August. It tells me nothing whatsoever about whether it was safe on the sixth of August. It is trust on first use, recorded faithfully. Every integrity guarantee in that file is anchored to a decision I made in one second, with no signature, no publisher identity, and no way to check the artifact against anything except its past self.
That is exactly the property npm had for most of its life, and it is the property that supply-chain attacks are built to exploit. Pinning defends you against a package changing under you. It does nothing at all when the malicious version is the first version you ever install, and nothing when a legitimate maintainer’s credentials are used to publish it.
Look at what that failure mode does at scale in a mature registry. On the fourth of August the Shai-Hulud worm compromised keyv and a group of packages around it: keyv 6.0.0 at 604M installs a month, flat-cache 6.1.24 at 580M, file-entry-cache 11.1.6 at 571M. Aikido’s follow-up puts it at “at least 444 packages (across 1381 versions) … with a combined total of over 2 billion monthly installs”. The payload harvests npm tokens from .npmrc, GitHub tokens in three formats, AWS credentials, Kubernetes service account tokens, Vault tokens, Stripe keys and Slack tokens, encrypts the bundle under the attacker’s RSA public key, and then republishes itself using whatever publish rights the stolen tokens carry. Lockfiles were everywhere in that ecosystem and did not stop it, because the compromised versions were published by the real maintainers’ tokens.
The research on skills specifically is already in#
This is the part I did not expect when I started reading, and it is why I think platform teams have less runway than they assume.
Snyk’s researchers ran what they describe as the first comprehensive audit of the ecosystem, scanning 3,984 skills from ClawHub and skills.sh. Their numbers: 36.82% have at least one security flaw, 13.4% (534 skills) carry at least one critical-level issue, and 76 confirmed malicious payloads built for credential theft, backdoor installation and data exfiltration. Eight of those were still publicly downloadable at publication. Separately, 10.9% of ClawHub skills contained hardcoded secrets.
The detection side looks worse. A team at the Hong Kong University of Science and Technology built SkillCloak to test whether scanners actually catch this class of thing, using 1,613 genuine malicious skills pulled from a marketplace archive. Rewriting suspicious constructs into equivalent runtime forms defeated more than 80% of static scanners. Packing payloads into directories scanners skip beat every scanner they tested more than 90% of the time, and one hybrid tool 96% of the time. Their proposed fix, SkillDetonate, gives up on static analysis and runs the skill in a sandbox to watch its syscalls.
Meanwhile the standards moment came and went. On the sixth of August, OpenAI, Amazon, Microsoft, Cursor and Vercel agreed on a common plugin standard. The scope is candid: it “defines how a plugin is packaged and found, and little else”, and “marketplaces, installation, permissions, sandboxing, and trust all stay with each client”. Five of the largest vendors in this market sat down together and explicitly declined to standardise the security properties. Whatever your platform team does about this, nobody is coming to do it for them.
The objection I would raise, and why I think it fails#
The strongest counter is that skills are markdown, so the npm comparison is category error. There is no postinstall, no arbitrary code, just instructions.
Two things are wrong with it. The first is that skills are not only markdown. Anthropic’s own repository describes skills as folders of “instructions, scripts, and resources”, and its document skills ship real implementations for DOCX, PDF, PPTX and XLSX generation. The claude-seo plugin, which is 25 sub-skills and 18 sub-agents in one install, documents its manual path as bash claude-seo/install.sh and, on Windows, powershell -ExecutionPolicy Bypass -File claude-seo\install.ps1. Telling users to bypass the execution policy is a very old shape.
The second is that even for a skill that genuinely is only prose, the analogy holds better than the objection admits, because of where the prose gets executed. Snyk found that 91% of confirmed malicious skills used prompt injection, against 0.0% of the top hundred legitimate ones. A skill does not need to carry a payload when it can instruct an agent that already holds your cloud credentials, your git remotes and a shell. postinstall needed code because npm had no interpreter standing by with your AWS keys. Skills have one. That makes plain instructions a weaker delivery mechanism in some ways and a considerably stronger one in others.
Where this loses#
I am overreading a small sample on my own machine. Five plugins is not a study, and 61 broken symlinks are evidence that I was careless in May, not evidence of a compromise. Nothing I found on my disk was malicious, and I want to be clear that I am describing hygiene, not an incident.
The analogy also breaks in a place that matters. npm’s real horror was transitive: one direct dependency dragging in nine hundred you never chose. Skills mostly do not do that yet. They are shallow, usually a folder and a file, and claude-seo’s 25 sub-skills are vendored inside one repository rather than resolved from a graph. Until skills routinely depend on other skills by reference, the blast radius is closer to a curl-to-bash than to a dependency tree, and those are different problems with different fixes.
There is a fairness point too. The lockfile exists, the plugin manifest records commit SHAs for most installs, and both of those landed faster than the equivalents did in any package ecosystem I have used. The trajectory is better than npm’s was at the same age. My argument is about ordering and about what is still missing at the end of the queue, not that nobody is doing anything.
And the honest limit on my proposed fix: pinning and vendoring would not have stopped Shai-Hulud, which I used above as the cautionary example. Signature and publisher verification might have. That is the primitive nobody in this ecosystem has shipped, and I cannot point at a skills implementation of it because there is not one to point at.
The takeaway#
Treat skills as a dependency class today, before anything forces you to. Vendor them into the repository, pin them to a commit rather than a branch, put changes to them through the same review path as a package.json diff, and require that an installed skill can answer where it came from. That last one is the cheapest and the one I failed: not one of my 61 dead symlinks can tell me its origin.
The ecosystem will get to signatures and publisher identity, because every registry eventually does. It will get there after the incident that makes it unavoidable, because every registry does that too. The work worth doing now is making sure that when it happens, you can enumerate what you installed and answer where each piece came from. I currently cannot, on the machine I am writing this on, and I would bet most teams shipping agents cannot either.
I build and run agent infrastructure for a living, including the unglamorous parts like this one. If you want the same read on your own stack, here is what I do.