DEV Community

xiaoru chen
xiaoru chen

Posted on

Agent Skills Have No Provenance. A Content Hash Helps.

TL;DR: everything below was verified on my own laptop on 2026-09-17 against bl 1.22.0, including one command I assumed was side-effect-free and wasn't. The article, its two figures, and every pasted output came out of running the thing it describes.

The question nobody's tooling answers

The hard part of agent skills was never writing one.

The hard part is answering: what exactly did I just install?

I run three coding agents on one laptop. A year of accumulated skills, plugins, and hand-edited instruction files, and until last week I could not tell you which came from a registry, which I copied off a blog, and which I wrote myself. On disk they are indistinguishable. They load identically. One of them had been edited by an update I don't remember approving.

In a recent two-week Hacker News window, the highest-engagement post in the whole skills category was a one-line question with two comments: has anyone measured how often agents use the skills you ship? The tooling posts (a package manager, an inspector, a context-cost auditor, a risk-scanned catalog) all sat between two and four points. We are building skill infrastructure faster than we are building trust in it.

So when I found a first-party registry that stores a SHA-256 hash per installed skill, I took it apart. Here's what holds up, and one thing that doesn't.

What the registry records

Alibaba Cloud Model Studio ships a CLI called bl. Its skill group is five commands, and the surprise is that none of them need an API key. List, install, update, and remove all run without authentication. Grab the CLI from the install page if you want to follow along.

bl skill list diffs the registry index against local installs. Fifteen skills, five states. The states are the interesting part:

bailian-gen        installed
bailian-sandbox    installed
spark-video        not-installed
Enter fullscreen mode Exit fullscreen mode

missing means the lockfile knows the skill but the directory is gone. untracked means a directory exists that the lockfile has never heard of, usually something you copied in by hand. That distinction is the first real diagnostic I've seen in skill tooling: it separates "I installed this and it vanished" from "something unmanaged is sitting here."

The lockfile is where it gets good. Each installed skill records:

{
  "contentHash": "sha256:d56618ed7fbd14cc4a22830f6df364566c5b725c614faf99c5bbd5a209961044",
  "publishedAt": "2026-09-17T14:04:49+08:00",
  "installedAt": "2026-09-17T07:22:38.894Z",
  "sourceType": "oss",
  "links": [
    "/Users/me/.copilot/skills/bailian-docs-llm-wiki",
    "/Users/me/.qoder/skills/bailian-docs-llm-wiki",
    "/Users/me/.qwen/skills/bailian-docs-llm-wiki"
  ]
}
Enter fullscreen mode Exit fullscreen mode

Four fields, four questions answered. contentHash: are my bytes the published bytes? Checkable now, not assumed. sourceType: vendor object storage, not someone's repo. publishedAt vs installedAt: two timestamps, so "am I behind?" is a comparison. links: every host pointing at this skill, which is why removal reports a count instead of deleting whatever it finds.

I'm not citing the circulating skill-security percentages. They come from different scans over different corpora and don't compare. A hash I can recompute myself is a weaker headline and stronger evidence.

One copy, three hosts

Every entry in all three host skill directories is a symlink to one canonical copy:

lrwxr-xr-x  bailian-gen -> /Users/me/.bailian/skills/bailian-gen
Enter fullscreen mode Exit fullscreen mode

Two consequences I'd assumed were unsolvable. Updates are atomic across hosts: bl skill update patches the single copy and all three see it; I ran it, ten entries, all up-to-date. Removal is accountable: the lockfile enumerates links, so uninstall reported removedLinks: 3, and two skills I keep by hand in one host survived untouched.

This is the missing piece in the "skills are the asset, the harness is replaceable" argument. Portability only becomes cheap when the asset is stored once and referenced many.

The bug I hit: --dry-run isn't dry here

bl --help lists --dry-run as a global flag, described in three words. Nothing says which groups honor it. So I did the polite thing:

bl skill add --name spark-video --dry-run
Enter fullscreen mode Exit fullscreen mode
{ "skills": [ { "name": "spark-video", "status": "installed" } ] }
Enter fullscreen mode Exit fullscreen mode

installed. Not "would install."

I checked disk immediately: the skill existed in all four locations. Before the command, all four were absent and bl skill list said not-installed. One command with the dry-run flag in between. The skill group silently ignores --dry-run and installs for real.

Recovery is clean, which is why this is a footnote and not a warning label:

bl skill remove --name spark-video
# { "skills": [ { "name": "spark-video", "status": "removed", "removedLinks": 3 } ] }
Enter fullscreen mode Exit fullscreen mode

All four paths gone, unmanaged skills untouched. If you want a zero-write preview, read the agents field from a --dry-run response (that part is real), but use bl skill list for the view that truly touches nothing.

What you get

bl skill init installs the ten bailian-* skills; the five scenario skills need an explicit --name. The payoff is in one description: bailian-gen names five command groups verbatim: bl image, bl video, bl speech, bl vision describe, bl omni. One skill wires image generation, video, TTS, ASR, and image/video understanding into whichever agents the CLI detected. On my machine: GitHub Copilot, Qoder, Qwen Code.

Caveat, stated plainly: the registry also ships bailian-sandbox, whose command group doesn't exist in CLI 1.22.0. Installing it doesn't error; using it would. Wait for an update or run bl update yourself.

Everything above is free and keyless. The first paid model call happens when you ask the agent to generate something; you'll need an API key from here at that point, and quota is something to check in your own console, because the commands that read it need a browser login I can't do for you.

Which skills to delete

There's a real camp deleting skills now: base models improve, so skills that teach the model how to think get absorbed and just burn context. They're half right. Prompt-class skills (choreography, formatting, reasoning scaffolds) are exactly what model progress obsoletes. Capability-class skills are not. No base model calls an image API on its own. Those abilities live in endpoints, not weights.

My test is one line: after installing, did the agent gain a paragraph of instructions, or a set of commands? Instructions expire. Commands don't.

Your turn

The compressed version:

npm install -g bailian-cli   # skip if you have bl
bl skill list
bl skill init
bl skill update
bl skill remove --name all
Enter fullscreen mode Exit fullscreen mode

If you run this and hit something I got wrong (a state I misread, a host the CLI fails to detect, a lockfile field that lies), I want the report; that's how the next post happens. Issues and PRs welcome. And if you'd rather explore the platform itself first, the entry point is here.

Top comments (0)