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

rosie-skills

v0.7.3

Published

A fast, cross-platform package manager for AI agent skills

Readme

rosie-skills

A fast, cross-platform package manager for AI agent skills. Use as a CLI or as a typed JS library — same binary either way, via a native build on supported platforms or WebAssembly everywhere else.

CLI

npm install -g rosie-skills
rosie-skills install anthropics/skills

Or one-shot via npx:

npx rosie-skills install anthropics/skills

JavaScript API

The package is ESM-only. Use a namespace import:

import * as rosie from 'rosie-skills';

await rosie.install('anthropics/skills');

const skills = await rosie.list();
//   [{ name: 'pdf', source: 'anthropics/skills', ref: 'main', sha: '...', isReference: false }, ...]

const agents = await rosie.agents();
//   [{ name: 'claude', display: 'Claude Code', detected: true, installPath: '/home/.../skills' }, ...]

All functions return Promises. Failures throw Error with a descriptive message.

Install result

install, installFromLockfile, and update return an InstallResult:

interface InstallResult {
  skills: Array<{
    name: string;
    kind: "skill" | "reference";
    installedAgents: string[];     // e.g. ["claude", "cursor"]
    failedAgents: string[];        // agents the symlink couldn't reach
  }>;
  installedAgents: string[];       // deduped union across all skills
  failedAgents: string[];          // deduped union across all skills
  installedInstruction:            // file rosie wrote the references block to
    | "AGENTS.md"
    | "CLAUDE.md"
    | "GEMINI.md"
    | ".github/copilot-instructions.md"
    | null;                         // null for pure-skill installs
  audit: {                         // structured audit of every change + findings
    schemaVersion: 1;
    command: "install" | "update";
    findings: Array<{              // rosie's own warnings, e.g. tag_rewritten
      severity: "high";
      kind: "tag_rewritten" | string;
      skill: string;
      ref: string;
      oldSha: string;
      newSha: string;
    }>;
    changes: Array<{
      name: string;
      kind: "skill" | "reference";
      source: string;
      ref: string;
      sha: string;
      operation: "install" | "update";
      content: string | null;      // full sanitized body, first-install only
      diff: string | null;         // unified diff, updates only
    }>;
  };
}
const result = await rosie.install('anthropics/skills');
if (result.failedAgents.length > 0) {
  console.warn(`couldn't symlink into: ${result.failedAgents.join(', ')}`);
}

failedAgents is non-fatal: rosie tries every detected agent and reports the misses. The canonical install at .agents/skills/<name>/ still lands and the lockfile entry is still recorded, so a subsequent run after fixing permissions will retry the failed agents.

remove() returns void.

Targeted install

await rosie.install('vercel-labs/agent-skills', {
  agent: ['claude', 'cursor'],
  ref: false,
});

As a reference, not a skill

await rosie.install('vercel/next.js', { ref: true });

Observe progress

The library is silent by default. Pass onLog to receive log events:

await rosie.install('anthropics/skills', {
  onLog: ({ level, message }) => {
    if (level === 'error') console.error(message);
    else if (level === 'info') console.log(message);
    // 'warn' and 'debug' levels also available
  },
});

Remove / update

await rosie.remove('pdf');
await rosie.update();           // update everything in rosie.lock
await rosie.update('pdf');      // update just one

Security defenses

Every install applies content sanitization and structured auditing by default; see docs/security for the full threat model. Each defense can be disabled per call via InstallOptions:

await rosie.install('anthropics/skills', {
  stripComments: false,      // keep markdown comments in reference installs
  stripInvisible: false,     // keep zero-width / bidi / tag-block codepoints
  retagDetect: false,        // skip the tag-rewrite check on `rosie update`
  forceAudit: true,          // print audit on stdout regardless of context
  suppressAudit: true,       // never print audit on stdout (still in result)
});

forceAudit and suppressAudit are mutually exclusive; passing both throws. The audit field on the result is always populated regardless of the emission flags — those flags only control whether the wrapped text is written to stdout by the CLI / bin.ts launcher.

Working directory

Every function accepts a cwd option — equivalent to cd'ing into that directory before running. process.cwd() is restored on exit:

await rosie.install('owner/repo', { cwd: '/path/to/project' });

Mirrors the CLI's --cwd flag.

Skip the lockfile

For ad-hoc installs that shouldn't be recorded in .agents/rosie.lock:

await rosie.install('anthropics/skills', { lockfile: false });

Mirrors the CLI's --no-lockfile flag. Available on install, remove, and update.

Reinstall from lockfile

await rosie.installFromLockfile();

How it works

Three platform binaries (linux-x64, darwin-arm64, freebsd-x64) ship as optional dependencies. On those platforms the CLI execs the native binary directly. On everything else (Windows, linux-arm64, darwin-x64, etc.) the package falls back to an inlined WebAssembly build that does the same work in-process. The JS API always uses the WASM build so you can call it synchronously from Node code without spawning a subprocess.

Supported platforms

| Platform | CLI | JS API | |-----------------|------------|--------| | linux-x64 | native | WASM | | darwin-arm64 | native | WASM | | freebsd-x64 | native | WASM | | Everything else | WASM | WASM |

For native installs on platforms we don't ship a binary for:

  • Homebrew (macOS / Linux): brew tap matthewp/rosie && brew install rosie
  • Arch Linux: yay -S rosie
  • Debian/Ubuntu: see https://github.com/matthewp/rosie
  • Source: clone the repo and run cargo build --release

License

BSD-3-Clause