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

@patrity/skills

v0.2.1

Published

Assemble an opinionated Claude Code setup (.claude/ + CLAUDE.md) from skills.patrity.com bundles.

Readme

@patrity/skills

npm

Assembles a Claude Code setup, .claude/ plus CLAUDE.md, out of the bundles published on skills.patrity.com. One command, no install step.

Quick start

pnpx @patrity/skills

No install step: pnpx/npx/bunx all fetch and run the package straight from npm. With no subcommand it runs init, the interactive wizard. Node 22 or newer is required; Windows, macOS and Linux are all supported.

Commands

Every command accepts --dir <path> (default .), --registry <url> (default: the project's lockfile, else https://skills.patrity.com), --yes (take defaults, never prompt), --force (overwrite files and CLAUDE.md blocks edited since install) and --json (print one JSON object on stdout and nothing else, which implies non-interactive).

| Command | Aliases | Positional | What it does | | --- | --- | --- | --- | | init | none (default) | none | The wizard: asks the base questions, offers profiles and the bundle list grouped by tag, shows a dry-run plan, and applies it once confirmed. Also --profile <name>, --with <slugs> (repeatable/comma-separated), --answer <axis>=<option> (repeatable). Re-run it to edit a project, not to start it over. See below. | | add <slug…> | none | one or more bundle slugs | Adds bundles to an already-initialised project, re-rendering from the answers on record and pulling in anything the new bundles declare in dependsOn. | | remove <slug…> | rm | one or more bundle slugs | Removes a bundle's marker blocks and the files it owns. Files it did not create are left alone. | | update [slug…] | up | bundle slugs (optional) | Re-renders every installed bundle from the current registry. Naming slugs only narrows which must already be installed. The plan is always a full re-render, so upstream schema changes reach every bundle. | | diff | none | none | Compares local files against the lockfile's hashes (your hand edits) and the lockfile's recorded sha against the registry (upstream drift). | | list | ls | none | Prints the installed bundles, the recorded answers, and whether the install is behind the registry. |

add/remove/update all read the previous answers and bundle list from .claude/skills.lock.json, so re-run init (not add) to change an axis answer.

Re-running init on an initialised project edits it. The answers on record are the starting point. A --profile and any --answer flags override them, and interactively they come up pre-selected. Every installed bundle stays ticked, so a bundle you added later with add survives. Untick one in the wizard (or use remove) to take it out.

Two things the lockfile can outlive:

  • A bundle that is no longer published. update, add and remove warn (ghost is installed but no longer in the registry; removing its files) and remove its files rather than refusing to run. Naming it explicitly, as in add ghost, is still an error.
  • An answer the base no longer has. An axis that vanished upstream is dropped, an answer that is no longer one of its options falls back to the axis default, an axis added upstream gets its default, and each correction is reported and written back to the lockfile.

What it writes

Everything lands under the project root you point it at:

.claude/
├── skills/…               # bundle skills
├── rules/…                # bundle rules, globs rewritten for your app directory
├── hooks/…                # hook scripts, made executable
├── settings.json          # committed; deep-merged
├── settings.local.json    # gitignored; permission allowlists
├── .env.example           # committed; the variables the installed bundles read
└── skills.lock.json       # committed; what is installed and at which sha, plus your answers
CLAUDE.md
.gitignore                 # a managed block, regenerated in place

The .gitignore entries live in one managed block, between # >>> skills … and # <<< skills. It holds .claude/settings.local.json, .claude/.env when any installed bundle declares variables, and whatever paths the bundles themselves declare (a cache directory, say). Every run regenerates the block from the current selection and leaves every line outside it alone; the block goes away with the last entry. A bundle that declares variables also gets a group in .claude/.env.example, one commented line per variable with its description and a sample value. Copy it to .claude/.env and fill it in. The CLI never creates, reads or deletes that file. When the last bundle declaring variables is removed the example is deleted, unless you edited it, in which case it is left in place and reported.

CLAUDE.md is created with a title line if it does not exist yet. Each contribution is wrapped in a marker pair:

<!-- skills:bundle:nuxt -->
- Nuxt 4 uses `app/` as srcDir…
<!-- /skills:bundle:nuxt -->

Everything outside those markers is yours and is never touched.

settings.json and settings.local.json are treated differently because one is meant to be committed and the other is per-machine: bundle hooks are unioned into settings.json by matcher and command string (a changed timeout replaces the installed entry rather than duplicating it), and permissions.deny entries are merged there too; permissions.allow entries go into settings.local.json instead, and the CLI makes sure that file is gitignored.

Each bundle's contribution is recorded in the lockfile once per settings file, so remove takes its hooks and permissions back out of the file it merged them into, so a fail-closed hook never stays armed after its script is deleted, and update replaces its own entries instead of stacking new ones beside them. Anything you added by hand survives remove and update unless it is byte-identical to an entry the bundle contributed to that same file: an allow you keep in settings.json stays put when the bundle's copy leaves settings.local.json.

The lockfile

.claude/skills.lock.json records the registry a project was set up against, the answers given to every axis, which bundle owns which file (with its content hash), what each bundle merged into each of the two settings files, and the hash of every CLAUDE.md marker block. add, remove, update, diff and list all read it. There is no other place the CLI keeps state, and it is meant to be committed.

Updating

Every file and CLAUDE.md block the CLI wrote is hashed at install time. On a later run:

  • A bundle file whose content still matches the hash on record is unchanged, a no-op.
  • One that was edited by hand since install is protected: the CLI refuses to overwrite it and leaves it alone, unless you pass --force.
  • A file that already existed and was never installed by this CLI is a conflict: interactively you are asked, per file, to skip or overwrite it; non-interactively (--yes) it is always skipped. A skipped conflict is never recorded in the lockfile, so it stays entirely yours. The summary names every conflicting and protected path, one per line, and --json returns them in skipped.
  • A file a bundle used to ship and no longer does is deleted if it still matches its recorded hash, and kept with a warning if you edited it.
  • A CLAUDE.md block you edited by hand no longer matches its recorded hash, so it is kept as-is on update unless you pass --force to replace it with the upstream version.
pnpx @patrity/skills diff     # what drifted, locally and upstream. Nothing is written
pnpx @patrity/skills update   # re-render and apply, with a confirmation

Non-interactive use

Every prompt has a flag, so the wizard runs unattended in a script or a CI job:

pnpx @patrity/skills init --yes --profile nuxt-app

Start from a profile and override individual answers, or skip profiles entirely and list bundles by hand:

pnpx @patrity/skills init --yes \
  --profile library \
  --answer pm=npm \
  --answer deploy=vercel \
  --with nuxt,nuxt-ui

--answer is repeatable and takes axis=option pairs; --with takes a comma-separated list of bundle slugs (also repeatable). Add --json when a script needs to read the result instead of the human-readable summary.

Using another registry

The CLI talks to https://skills.patrity.com by default. Point it at any host that serves the same API: a fork, a staging deploy, or a local pnpm dev.

pnpx @patrity/skills init --registry http://localhost:3000

--registry works on every command. The registry a project was initialised against is recorded in .claude/skills.lock.json and used automatically by add/remove/update/diff/list after that, so you only need to pass it again to point the project somewhere else.

Releases

Published to npm as @patrity/skills. Releases are tagged cli-vX.Y.Z and built with npm provenance.

Full documentation also lives at skills.patrity.com/docs/cli.

Changelog

0.2.1

--help, every prompt and the run summary were rewritten in the same voice as the site: plainer questions, a summary that says what it did rather than what it touched, and none where a — placeholder used to stand. Nothing about what the CLI does changed, and no lockfile is rewritten by the upgrade.

0.2.0

The .gitignore line became a managed block: # >>> skills … # <<< skills, regenerated on every run from the current selection, with every line outside it left alone. A project set up with 0.1.0 keeps its old loose .claude/settings.local.json line above the block; it is harmless, and yours to delete. A block that was opened and never closed stops the CLI touching the file at all: it warns and moves on, because there is no telling where that block was meant to end.

Bundles declare gitignore paths and env variables in their frontmatter now. The variables are collected into .claude/.env.example, one commented line each, and the file is deleted again when the last bundle declaring any is removed. It is fully managed: edit it and the next run overwrites you. Copy it to .claude/.env and edit that instead; the CLI never creates, reads or deletes .claude/.env.

The lockfile carries bundles.<slug>.gitignore and bundles.<slug>.env, so remove subtracts exactly what a bundle added, and an envExample hash so an example you edited is left in place rather than deleted. A 0.1.0 lockfile still parses; it just has none of that until the next run records it.

The renderer is shared with the web builder at skills.patrity.com/build. Unzip a setup from there and it is already a project this CLI understands: diff reports no drift, and add, update and remove work without an init first.

License

MIT