Skill library
🤖Agentic Automation 4.6 16 min read

skilld: Generate Version-Aware Skills From Your Own Dependencies

skilld generates version-aware skills from the npm dependencies you already have — pulling from docs, release notes, and GitHub issues — so your model stops writing last year's version of your library.

There is a specific kind of bug that I have learned to recognize on sight. The agent writes code that is clean, idiomatic, and confident — and completely wrong for the version of the library you actually have installed. It reaches for an import path that was reorganized two releases ago. It passes a config object that the framework renamed. It uses a hook that was deprecated, or a method that now returns a promise where it used to return a value. The code reads like it was written by someone who knows the library well. The problem is that they know last year's library well.

This is the training-cutoff staleness problem, and skilld is the first tool I've used that attacks it directly instead of working around it. Run npx -y skilld in your project and it reads your actual dependency tree, walks the docs and release notes and GitHub issues for the versions you have pinned, and writes skills that describe your stack — not the median of everything the model saw during training. In this piece I want to explain why the staleness problem is structural rather than incidental, exactly how skilld generates current guidance from your package.json, how to run and refresh it as your dependencies move, and how it fits alongside the other half of this story: skills that ship inside the package itself.

The training-cutoff staleness problem, in depth

Every model has a knowledge cutoff. That is not a flaw; it's a fact of how these systems are built. Training data is collected up to some date, the model is trained, and from that point forward the model's picture of the world is frozen. When a model tells you it "knows" React or Prisma or Tailwind, what it actually has is a statistical compression of an enormous amount of text about those libraries, weighted by how often each pattern appeared in the corpus.

That weighting is where the trouble starts. Consider what the corpus for a popular library looks like:

  • Years of accumulated tutorials, most of them old. A blog post written for version 3 does not get deleted when version 5 ships. It keeps ranking, keeps getting scraped, keeps voting for the old API.
  • Stack Overflow answers that span the entire history of the project. The highest-voted answer is often the oldest, because it has had the most years to accumulate votes — and it describes the API as it existed when the question was asked.
  • The library's own changelog, which by definition documents the past. Migration guides describe how things used to work in order to explain how they work now.

So even a model trained right up to a library's latest release will tend to regress toward the mean of that library's history. The newest API is, almost by construction, the least represented in the training data, because it has had the least time to generate text. The result is a subtle but persistent pull toward stale patterns — and it gets worse, not better, for the libraries that move fastest, because those are exactly the ones where the gap between "what the model saw most" and "what you have installed" is largest.

The model isn't wrong about the library. It's right about a previous library that happened to have the same name.

A few concrete failure modes I see constantly:

  1. Renamed exports. The function still exists, but it now lives at a different import path, or it was split into two. The agent imports the old path; the build fails or, worse, resolves to a shim that behaves differently.
  2. Changed defaults. A flag that used to default to false now defaults to true. The code looks identical to working code from a year ago, but the behavior flipped.
  3. Deprecated-then-removed APIs. The model confidently uses a method that printed a deprecation warning for three minor versions and then disappeared in the major you're on.
  4. New required configuration. A newer version needs an extra field in its config that simply did not exist when most of the training text was written, so the model never includes it.
  5. Peer-dependency mismatches. The model pairs a current version of one library with an incompatible version of another, because in its training distribution those two versions co-occurred.

None of these are reasoning failures. The model reasons fine. It's an information failure: the agent is operating on a snapshot of the ecosystem that does not match the snapshot on your disk. You cannot prompt your way out of an information gap. You have to close the gap by feeding the agent the current facts. That is the entire premise of skilld.

What "version-aware" actually means

A lot of tools claim to be "up to date." Usually that means someone, somewhere, periodically refreshes a docs index. Version-aware is a stronger and more specific claim. It means the guidance is generated against the exact versions resolved in your project — the ones in your lockfile, not the latest on the registry, and not the average across all versions ever published.

This distinction matters more than it sounds. "Latest" is its own trap: your project might be deliberately pinned two majors back because a migration is expensive, and guidance for the latest release would be just as wrong for you as stale training data — wrong in the opposite direction. Version-aware means the skill matches what node_modules actually contains.

Concretely, a version-aware skill for a dependency answers questions like:

  • What is the correct import path for this symbol in the version I have?
  • What are the current, non-deprecated APIs for the common tasks?
  • What changed between the version the model "remembers" and the version installed, that an agent is likely to get wrong?
  • What are the known footguns for this exact version, drawn from issues people actually filed?

That last point is the one most people underestimate, so it gets its own section.

How skilld reads your dependency tree and generates current guidance

When you run npx -y skilld in a project, it works in roughly four phases. Knowing the phases helps you understand what the output is and isn't.

Phase 1 — Resolve what you actually have

skilld starts from your project's dependency manifest and lockfile. The lockfile is the source of truth: it records the exact resolved version of every direct and transitive dependency, including the ones your direct dependencies pulled in. This is why a version-aware tool has to read the lockfile rather than just package.jsonpackage.json says "^5.0.0", but the lockfile says 5.4.2, and that difference is the whole point.

# Run it at the root of a project that has a node_modules and a lockfile
cd my-app
npx -y skilld

skilld typically lets you scope which dependencies it processes. You rarely want a skill for every transitive package — most of them you never touch directly. The dependencies worth generating skills for are the ones your team writes code against: the framework, the data layer, the validation library, the component kit, the test runner. A good mental model is "the libraries whose docs I have open in a browser tab while I work."

Phase 2 — Gather current sources for those exact versions

For each in-scope dependency at its resolved version, skilld pulls from the sources that actually reflect the current state of the library:

SourceWhat it contributesWhy it matters for staleness
Package docs (shipped + hosted)The canonical current API surfaceReflects the version, not the historical average
Release notes / changelogWhat changed and whenSurfaces renames, removals, new defaults
GitHub issuesReal footguns and workaroundsCaptures problems no doc mentions yet
Type definitions in node_modulesThe literal, on-disk API shapeThe ground truth — can't be out of date

The type definitions deserve emphasis. The .d.ts files inside node_modules are not a description of the library — they are the library's contract, on your disk, at your version. They cannot be stale relative to your install because they came with it. A version-aware generator that grounds itself in the installed types has a floor of correctness that no amount of scraped prose can provide.

Phase 3 — Synthesize a skill, not a doc dump

This is the step that separates skilld from "just give the model the docs." Dumping a library's entire documentation into context is expensive and counterproductive — it floods the model with the same historical noise that caused the problem, and it burns tokens. skilld synthesizes: it produces a compact SKILL.md-style document that says, in effect, "here is what is true now, here is what changed from what you probably remember, here is what to avoid." It's the difference between handing someone a library and handing them a briefing.

The synthesized skill is tuned for an agent's working style:

  • Short, imperative guidance the model can follow without re-deriving it.
  • Explicit "this changed" callouts that counteract the model's prior.
  • Current code patterns for the common tasks, using the real import paths.
  • A list of known footguns pulled from issues, phrased as "don't do X, do Y instead."

Phase 4 — Write the skills where your agent can find them

skilld writes the generated skills into your project — typically into a skills directory that your agent harness already loads — so they become part of the agent's working context without any further wiring. The output is plain Markdown with YAML frontmatter, which means you can read it, edit it, and commit it like any other file. That last property matters: these skills belong in version control next to the code they describe.

Why GitHub issues are the secret ingredient

Docs tell you how a library is supposed to work. Issues tell you how it actually behaves when people use it. The gap between those two is where most real debugging time goes, and it's exactly the gap that training data fills poorly, because the relevant issue might have been filed last month — long after the cutoff.

When skilld reads issues for a pinned version, it's mining for things like:

  • "Upgraded to 5.4 and X broke" threads that reveal undocumented breaking changes.
  • Maintainer comments that say "this is the supported way now" in response to confusion.
  • Recurring questions that signal a footgun the docs never addressed.
  • Workarounds for bugs that exist in your specific version and may be fixed in the next.

A skill that includes "in 5.4.x, calling foo() before init() silently no-ops — see issue #2210; call order matters" is worth more than ten paragraphs of correct-but-generic API description, because it stops a class of bug the model would otherwise walk straight into.

How to run and refresh it

The first run is the easy part. The discipline is in keeping the skills current as your dependencies move, because a version-aware skill is only as good as its match to your lockfile.

First generation

cd my-app
npx -y skilld
# review the generated skills, then commit them

Read the output before you commit it. skilld is generating from sources, and you are the human who knows which guidance is load-bearing for your team. Trim anything irrelevant, keep the "this changed" callouts, and commit the result so the whole team — and every agent run — gets the same grounding.

Refreshing after a dependency bump

The key rule: the skill is bound to a version, so regenerate when the version changes. Concretely, regenerate when:

  • You bump a major or minor of an in-scope dependency.
  • You run a dependency upgrade pass (Renovate, Dependabot, manual).
  • You notice the agent reaching for a pattern that no longer matches reality — that's a signal the skill has drifted from the lockfile.

A clean way to keep this honest is to treat skill regeneration as part of the upgrade itself, not a separate chore:

# as part of an upgrade PR
npm install some-lib@latest
npx -y skilld
git add .  # the lockfile change and the regenerated skills travel together

When the regenerated skill and the lockfile change land in the same commit, the skill can never silently fall behind the dependency. The diff on the skill file also becomes a surprisingly useful artifact during review: it shows, in plain language, what the upgrade changed about how you're supposed to use the library.

Patch bumps

For patch releases you usually don't need to regenerate — the API surface doesn't move. The exception is a patch that fixes a footgun your skill warns about; if issue #2210 got fixed in 5.4.3, the "call order matters" warning is now obsolete and a regeneration cleans it up. Low stakes either way.

How skilld complements package-shipped skills

skilld is one half of a two-part shift in how libraries teach agents to use them. The other half is skills that ship inside the package, versioned with each release. Both solve the staleness problem; they just attack it from different ends, and the strongest setup uses both.

The push model: maintainers ship skills with the package

The cleanest possible answer to "is this guidance current?" is for the library's own maintainer to write a SKILL.md, put it inside the npm package, and version it with the release. When you install version 5.4.2, you get the 5.4.2 skill, authored by the people who wrote the breaking change. There is no scraping, no synthesis, no guessing — the guidance and the code are the same artifact, shipped together. @tanstack/intent is the implementation of this idea I point people to: it lets maintainers bundle SKILL.md files inside their package so the instructions ride along with each version. I wrote about this pattern in depth in Ship Skills With Your Package, because I think it's where the ecosystem is heading.

The limitation is obvious: it only works for libraries whose maintainers opt in. Today that's a small minority. For everything else, you're on your own.

The pull model: skilld generates skills for everything else

That's the gap skilld fills. Most of your node_modules does not ship a skill and never will. skilld doesn't wait for maintainers — it generates the skill from the outside, from the same sources a careful human would consult. It's the pull complement to the package-shipped push model.

The two compose naturally:

  • For dependencies that do ship a skill, use theirs — it's authoritative.
  • For dependencies that don't, generate one with skilld.
  • Either way, the skills live in your project, load into your agent, and stay pinned to the versions you actually run.

Where the distribution layer fits

There's a third tool worth knowing in this neighborhood, because it solves the orthogonal problem of distribution. The Vercel skills CLI (npx skills) installs skills across 70-plus different agent harnesses, normalizing the per-agent differences in where skills live and how they're formatted. skilld and package-shipped skills are about authoring current guidance; the Vercel CLI is about delivering it consistently to whatever agent your team happens to use. If half your team is on one agent and half on another, that delivery layer is what keeps everyone on the same skills.

Put the three together and you have a complete picture:

  1. Generate version-aware skills from your real dependencies (skilld) and consume any that maintainers ship (the package-shipped model).
  2. Distribute them consistently across every agent your team uses (Vercel skills CLI).
  3. Refresh them as your lockfile moves, so the guidance never drifts from the code.

Framework skills: why this matters most for frontend

The reason I think framework skills are the most interesting development for frontend developers specifically is the velocity. Frontend stacks move faster than almost anything else in the industry, and they move in ways that are precisely the kind of thing models get wrong: import reorganizations, config-format changes, new defaults, the steady churn of meta-frameworks reinventing their routing and data-loading conventions every couple of major versions.

A generic "knows React" model is decreasingly useful as the surrounding stack — the router, the data layer, the build tool, the component library, the styling system — all move underneath it. What you actually want is a skill that knows your router at your version, paired with your data layer at its version, with the peer-dependency relationships between them correct. That's not something a training cutoff can give you. It's something you generate from your own dependency tree, which is exactly what skilld does.

This is also why I treat skilld output as a team artifact rather than a personal convenience. When the version-aware skills are committed to the repo, every developer's agent and every CI run shares the same grounding. New team members' agents are correct on day one. The skill becomes part of the project's definition of "how we use this stack," living right next to the code, moving with it through version control.

A realistic workflow

Here's how I actually fold this into a project, end to end:

  1. Initial pass. Run npx -y skilld at the repo root. Scope it to the libraries the team writes against directly — framework, data layer, validation, UI kit, test runner. Review and commit.
  2. Check for shipped skills. For each of those libraries, see whether it ships its own SKILL.md (the @tanstack/intent pattern). Prefer the maintainer's skill where it exists; let skilld cover the rest.
  3. Wire distribution. If the team spans multiple agents, run the Vercel skills CLI so everyone gets the same skills regardless of harness.
  4. Bind regeneration to upgrades. Add npx -y skilld to the upgrade routine so the lockfile change and the regenerated skill always land in the same commit.
  5. Watch for drift. When the agent suggests a stale pattern, treat it as a signal to regenerate — the skill has fallen behind the lockfile, or a new issue-driven footgun has emerged.

That's the whole loop. It's not heavy. The discipline is just remembering that a version-aware skill is pinned to a version, and versions move.

What to avoid

A few failure modes I've watched people walk into:

  • Generating skills for your entire dependency tree. You'll drown in skills for transitive packages you never touch. Scope to what you write against.
  • Treating the output as final. skilld synthesizes from sources; you are the editor. Read it, trim it, keep the load-bearing callouts.
  • Letting skills rot after upgrades. A version-aware skill that's three majors behind the lockfile is worse than no skill, because it's confidently wrong in a way the agent will trust. Bind regeneration to your upgrade process.
  • Skipping the lockfile commit. If you regenerate skills but don't commit them with the dependency change, the next person's agent gets the old guidance. Travel together.
  • Assuming "latest" is always right. If you're pinned back on purpose, generate against your pinned version, not the newest release.

The throughline is simple: the agent's job is to write code for the library you have, and the only way it can do that reliably is if something feeds it current, version-specific facts. The training cutoff guarantees the model can't do that alone. skilld closes the gap by reading the dependency tree you already have and writing down what's true today.

External tools and references:

Related skills and guides on this site:

Keep reading

More Agentic Automation skills