npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

agent-skills-manager

v0.0.1

Published

Programmatic skill workspace + agent-link manager for ACP coding agents. Wraps vercel-labs/skills for use as a library.

Readme

agent-skills-manager

[!WARNING] Alpha software. This package is in active development. The public API may change between minor versions without notice until 1.0.0. Pin exact versions; expect rough edges.

Programmatic workspace + agent-link manager for Anthropic-style SKILL.md bundles.

agent-skills-manager is built around seven primitives — add, link, unlink, remove, listSkills, listLinks, rescan — backed by a caller-supplied workspace directory and a versioned manifest stored inside it. It targets hosts (IDE plugins, desktop apps, internal tools) that need to manage agent skills on the user's behalf without shelling out to a CLI.

Library, not a CLI. If you just want to install skills on your own machine, use the skills CLI directly (skills.sh). This package is a programmatic API for embedders.

How this relates to skills.sh (vercel-labs/skills)

agent-skills-manager builds on top of the data model and filesystem layout defined by the official skills CLI (skills.sh). Specifically, this package vendors a small set of internals from upstream — the 53-agent catalog (agents.ts), the SKILL.md frontmatter parser (frontmatter.ts), the sanitizeName helper, and the AgentType / AgentConfig types — into src/_vendor/ under their original MIT license.

Why vendor instead of depending on skills as a package: the npm-published skills package is CLI-only — its package.json has no exports / main / types fields, so none of the upstream primitives are importable as a library. Vendoring is the only viable path to a programmatic API today.

What this means in practice:

  • Same agent catalog as skills.sh — every agent the CLI supports is supported here, with identical default install paths. When upstream adds an agent, we can pull the catalog forward with a deliberate vendor refresh.
  • Compatible on-disk layout — bundles installed by agent-skills-manager and bundles installed by the skills.sh CLI can coexist in the same workspace. listSkills({ scanUnmanaged: true }) will surface CLI-installed bundles; rescan({ mode: 'merge' }) adopts them into the manifest.
  • MIT attribution preserved — see THIRD_PARTY_NOTICES.md.

If vercel-labs/skills ever publishes a programmatic API, we'll revisit; until then this package owns the integration surface for embedders.

Mental model

There are two layers, with a clear split of responsibility:

  • Workspace (yours): a directory you own that holds the original SKILL.md bundles AND a .manifest.json recording what you added, from where, when, and which agents you've linked it to. add() writes here; listSkills() reads it.
  • Agent skills dirs (the user's): ~/.claude/skills, ~/.codex/skills, etc. link() writes symlinks here; unlink() removes them; listLinks() reports the ones the manifest knows about, verified against disk. Foreign content at those paths is never touched.

The manifest is authoritative for intent and metadata (what, from where, when, which agents); the filesystem is authoritative for current state (is it still there?). Every list call cross-checks the two and flags drift via broken: true. On-disk entries the manifest doesn't know about can be surfaced via the opt-in { scanUnmanaged: true } flag and adopted into the manifest via rescan({ mode: 'merge' }).

Install

bun add agent-skills-manager
# or
npm install agent-skills-manager

Quickstart

import { createSkillsManager } from 'agent-skills-manager'

const mgr = createSkillsManager({ workspaceDir: '/path/to/your/store' })

// 1. Pull a skill into the workspace.
const { added } = await mgr.add({ source: 'vercel-labs/skills' })
//                                       ^ owner/repo, full git URL, or an existing local path

// 2. Wire it to specific agents. Use the lookup key returned by add().
const skillName = added[0].name
await mgr.link({ skillName, agent: 'claude-code' })
await mgr.link({ skillName, agent: 'codex' })

// 3. Discover what's installed.
const skills = await mgr.listSkills()
//   [{ name, description, workspacePath, source, addedAt, broken?, unmanaged? }, …]

const links = await mgr.listLinks()
//   [{ skillName, name, agent, linkPath, workspacePath, broken?, unmanaged? }, …]

// 4. Tear down.
await mgr.unlink({ skillName, agent: 'codex' })
await mgr.removeWithLinks({ skillName })

API

createSkillsManager(options?)SkillsManager

| option | type | default | notes | |---|---|---|---| | workspaceDir | string | ~/.skills | Absolute path. Created on demand. | | agentSkillsDirs | Partial<Record<AgentId, string>> | {} | Per-agent override for the link target dir. Useful for project-scoped installs and tests. |

add({ source, skillNames?, localMode? })

Pull a skill (or every skill in a repo) into the workspace. Sources accepted:

  • owner/repo — github shorthand
  • owner/repo#ref — github shorthand with tag/branch
  • https://github.com/owner/repo[.git][#ref] — github URL
  • any other *.git URL — generic git URL
  • any path that exists on disk — local directory (absolute or relative to process.cwd())

For local sources, localMode: 'symlink' symlinks the source into the workspace (great for live editing); default 'copy' copies the bundle in.

Does not create any agent symlinks — call link() for each agent you want.

link({ skillName, agent, agentSkillsDir? })

Symlink an in-workspace skill into a specific agent's skills directory. Idempotent — if a correctly-pointing link already exists, returns { created: false }. Throws ForeignPathError if a non-symlink occupies the target path; we never overwrite foreign content.

Pass agentSkillsDir to override the default location (e.g. for project-scoped installs).

unlink({ skillName, agent, agentSkillsDir? })

Remove the agent's symlink for this skill — but only if the manifest recorded it. Hand-rolled symlinks the user created return { removed: false, unmanaged: true } and are left intact. Non-symlink content at the same path returns { removed: false, foreign: true }.

remove({ skillName })

Delete the workspace bundle. Does not touch agent symlinks — the next listLinks() will report orphaned links as broken: true. Use removeWithLinks for a full teardown.

removeWithLinks({ skillName })

Walk all manifest-recorded links for the skill, unlink() each, then remove() the workspace bundle. Returns the list of links that were unwound.

listSkills(opts?)InstalledSkill[]

Enumerate skills the manager tracks. Reads the manifest (fast) and verifies each entry by lstat-ing its SKILL.md. Manifest entries whose bundle is gone are returned with broken: true.

| option | default | notes | |---|---|---| | scanUnmanaged | false | Also scan workspaceDir for SKILL.md directories not in the manifest and report them with unmanaged: true. |

listLinks(opts?)SkillLink[]

Enumerate per-agent links the manager tracks. For each manifest-recorded link, lstat + readlink to verify the symlink still exists and points where we recorded. Drifted entries are returned with broken: true.

| option | default | notes | |---|---|---| | agents | (all) | Filter to a subset of agents. | | skillNames | (all) | Filter to a subset of skill names. | | scanUnmanaged | false | Also walk each agent's skills dir for symlinks-into-workspace not in the manifest, and report them with unmanaged: true. |

rescan(opts?)RescanResult

Rebuild the manifest by walking the workspace and the agent skills dirs.

| option | default | notes | |---|---|---| | mode | 'merge' | Preserve existing manifest metadata for rediscovered entries; add fresh entries for what the scan finds. | | mode: 'replace' | | Discard the existing manifest and reseed from disk only. Loses source URLs / addedAt timestamps. |

Use cases: corruption recovery, migrating from an older fs-only deployment, adopting unmanaged entries the user created manually.

Discovery helpers

import { listSupportedAgents, detectInstalledAgents, isAgentSupported, resolveAgentSkillsDir } from 'agent-skills-manager'

listSupportedAgents()         // → AgentInfo[]
await detectInstalledAgents() // → AgentId[] (subset that's actually installed)
isAgentSupported('claude-code')   // → boolean
resolveAgentSkillsDir('claude-code')  // → '/Users/you/.claude/skills'

Safety guarantees

  • unlink() only removes symlinks the manifest recorded. Hand-rolled symlinks-into-workspace are reported as unmanaged: true and never deleted; use rescan({ mode: 'merge' }) to adopt them.
  • Foreign (non-symlink) content at agent paths is never touched.
  • add() writes only inside workspaceDir.
  • remove() does not walk agent dirs — use removeWithLinks() for the full teardown. Stale agent symlinks after a bare remove() show up in listLinks() as broken: true.

Manifest format

A versioned JSON file at ${workspaceDir}/.manifest.json:

{
  "version": 1,
  "skills": {
    "<sanitized-dir-name>": {
      "name": "<frontmatter-name>",
      "description": "<from-frontmatter-at-add-time>",
      "source": { "kind": "github", "ownerRepo": "owner/repo", "ref": "v1.2.3" },
      "addedAt": "2026-05-11T19:56:00.000Z",
      "links": {
        "claude-code": {
          "linkPath": "/Users/dani/.claude/skills/<dir-name>",
          "workspacePath": "/Users/dani/.skills/<dir-name>",
          "createdAt": "2026-05-11T19:56:00.000Z"
        }
      }
    }
  }
}

Writes are atomic (temp-file + rename). Within a process, manifest mutations are serialized per SkillsManager instance; cross-process file locking is a documented v2 follow-up.

Telemetry

DO_NOT_TRACK=1 is set defensively at import time. The vendored bits of vercel-labs/skills we use don't call telemetry today, but the guard covers us if a future vendored update introduces one. Opt back in with process.env.DO_NOT_TRACK = '0' before importing.

License

MIT — see LICENSE.