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

@pskills/cli

v0.4.1

Published

Sync agent skills from a privateaiskills.com workspace to your local agents (Claude Code, Cursor, etc.).

Readme

pskills

Sync agent skills from a PrivateAISkills workspace down to your local agent (Claude Code, Cursor, etc.). Skill content is end-to-end encrypted; the server never sees plaintext, and the CLI decrypts on your machine before writing to disk.

Skills are edited in the dashboard. The CLI is sync-only as of 0.3.0. Binary supporting files (images, PDFs, etc.) sync byte-for-byte starting in 0.4.0.

Install

npm i -g pskills

Or run without installing:

npx pskills <command>

Requires Node 18 or newer. Works on macOS, Linux, and Windows.

Quick start

pskills init    # interactive: pastes your API key, picks groups to sync
pskills sync    # pulls every skill in your selected groups, decrypts, writes to disk
pskills watch   # sync once, then poll every 30s
pskills status  # report drift between local and remote (read-only)

Commands

| Command | What it does | |---|---| | pskills init [path] | Interactive setup. Prompts for your API key and lists your workspace's groups, lets you pick which groups to sync, asks for your encryption key and a target directory, and writes the settings file (defaults to ./pskills.settings.json). | | pskills sync | Pulls every skill in your selected groups, decrypts locally with your encryption key, and writes the bundle to the target directory. Variables defined at the org or project level in the dashboard are decrypted and interpolated locally by the CLI at sync time, after the server delivers ciphertext — manage them in the dashboard. | | pskills watch [--interval 30] | Sync once, then re-sync every N seconds. | | pskills status [--json] | Compare local synced skills to the remote workspace. Read-only — never writes. Default output is human-readable; --json emits a structured report you can parse in CI to decide whether to fail a build (the exit code is only about command success, not drift). |

Flags: --config <path>, --target <path>, --verbose.

Configuration

Settings file (default: ./pskills.settings.json):

{
    "apiKey": "hsk_...",
    "encryptionKey": "hsk-key-v1_...",
    "target": ".claude/skills",
    "groups": ["deploy-skills", "research-skills"]
}
  • apiKey — Issued from the workspace settings page. SHA-256 hashed at rest. Optionally scoped to specific groups in the web app.
  • encryptionKey — Your workspace's symmetric AES-GCM key, shown once at workspace creation. Without it, ciphertext cannot be decrypted. Save it to a password manager — it cannot be recovered.
  • target — Directory the CLI writes skills into. .claude/skills is the conventional location for Claude Code; use whatever path your agent reads from.
  • groups — Required, non-empty. The CLI syncs by group; pick the groups you want on this machine. Run pskills init to list available groups.

How it works

  1. For each group in settings.json, the CLI fetches /api/v1/groups/<slug> — this returns slugs and SHA-256 checksums of ciphertext.
  2. Skills appearing in multiple groups are deduped by slug and written once.
  3. Variables (org-level + project-level, with project overriding org) are pulled once from /api/v1/sync as ciphertext, decrypted locally, and held in memory for this run.
  4. Each checksum is compared against <target>/.pskills-state.json. If the variable set changed since the last sync, every skill is re-rendered even when its ciphertext checksum is unchanged — the on-disk interpolated output would otherwise be stale.
  5. For changed skills, the CLI fetches the full body and decrypts with encryptionKey (AES-GCM, IV is the first 12 bytes of the ciphertext blob).
  6. ${VAR_NAME} placeholders in SKILL.md and supporting text files are substituted with the matching variable value. Escape with a backslash (\${VAR}) to keep the literal text. Undefined references are left untouched and surfaced as a single warning at the end of the run. Files flagged binary by the server (isBinary: true) skip interpolation and are written byte-for-byte after AES-GCM decryption.
  7. The CLI writes each skill into <target>/<slug>/SKILL.md plus any supporting files at their relative paths, preserving the executable bit.
  8. Skills that disappeared from the manifest are removed locally.

FAQ

I lost my encryption key — can I recover my skills? No. The server only ever stores ciphertext; the key is generated client-side at workspace creation and shown once. If lost, the encrypted skills become unreadable and you'll need to recreate the workspace. Save it to a password manager.

pskills sync says nothing changed, but I just edited a skill in the web app. Make sure the save finished — the editor shows the save state at the top right. The CLI sees the new checksum only after the server has the new ciphertext.

How do variables work? Define them under your project's Variables card (or your org's settings for cross-project values — project values override org values with the same name). They're stored encrypted with the same workspace key as your skills, fetched at sync time, decrypted locally, and substituted into any ${VAR_NAME} placeholders in SKILL.md or supporting files. Only the CLI ever sees the plaintext.

The CLI warned that some variables are undefined — what now? The warning lists each missing name and where it was referenced (e.g. deploy-checks:scripts/run.sh). The placeholder is left as-is in the output. Either define the variable in the dashboard or remove the reference from the skill. Use a leading backslash (\${VAR}) when you actually want the literal text.

Can a skill ship binary files (images, PDFs, model weights)? Yes, since 0.4.0. Drop them into the skill folder in the dashboard, or include them in a GitHub-imported skill — the server flags them on ingest, encrypts them with the same workspace key as the rest of the bundle, and the CLI writes the decrypted bytes verbatim to disk. They skip variable interpolation. There's a 1 MB per-file ceiling enforced server-side.

I get 401 Unauthorized. The API key is wrong, was revoked, or doesn't match the endpoint. Re-run pskills init and paste a fresh key.

I get group not found. The slug in settings.json is mistyped, or the group was deleted/renamed. Run pskills init again to refresh the group list.

Same skills on multiple machines? Install the CLI on each machine, run pskills init, paste the same API key + encryption key, and pick the same target. The CLI is stateless — same inputs produce the same output.

Different agents (Claude Code, Cursor, Cline)? Each agent reads from a different directory. Run pskills init in each project root and set target accordingly (.claude/skills, .cursor/skills, …). One settings.json per project.

How do I rotate the API key? Revoke the current key in the web app, generate a new one, and run pskills init again. Confirm overwrite when prompted.

How do I rotate the encryption key? You can't rotate in place — the key is the workspace's identity. To change it, create a new workspace, re-encrypt your skills against the new key, and re-init the CLI.

Does this work on Windows? Yes. The CLI is plain Node — runs in PowerShell, cmd, and WSL. Path separators are normalized.

Where does pskills sync store its state? In <target>/.pskills-state.json. Safe to delete; the next sync rewrites everything from the server.

Can I sync into a directory that already has files? Yes, but the CLI manages the slug subdirectories under target. Files outside those subdirectories are left alone; files inside a slug directory may be overwritten or removed to match the server.

CI integration

pskills status --json is the read-only equivalent of "would pskills sync change anything?". It exits 0 on success regardless of whether drift was found — the JSON body tells you what's out of sync. CI scripts decide what counts as failure.

pskills status --json > drift.json
node -e 'process.exit(JSON.parse(require("fs").readFileSync("drift.json")).inSync ? 0 : 1)'

The JSON shape:

{
  "inSync": false,
  "target": "/repo/.claude/skills",
  "summary": { "added": 1, "updated": 1, "removed": 0, "unchanged": 5 },
  "skills": [
    { "slug": "new-skill",      "status": "added",     "remoteVersion": "1" },
    { "slug": "rollout-checks", "status": "updated",   "localVersion":  "2", "remoteVersion": "3" },
    { "slug": "stable",         "status": "unchanged", "localVersion":  "1", "remoteVersion": "1" }
  ]
}

Entries are sorted by slug. localVersion is omitted on added; remoteVersion is omitted on removed. localVersion is also omitted for state files written before this version of the CLI (the field is optional).

License

MIT