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

skillrepo

v4.8.3

Published

Pull-based CLI for agent skills — init, sync, search, add, remove your library from any IDE

Readme

skillrepo

A pull-based CLI for managing your agent-skills library from the terminal.

npx skillrepo init

Validates your access key, picks which agents to configure, wires up the MCP config, and pulls your library. Safe to re-run at any time.

Install

# One-off via npx (recommended)
npx skillrepo <command>

# Or install globally
npm install -g skillrepo
skillrepo <command>

Requires Node.js 18 or later.

Quick start

  1. Run init inside your project directory:
    npx skillrepo init
    When no key is configured, init opens skillrepo.dev/cli/auth in your default browser. Sign in, click Issue CLI key, and paste the key back into the terminal. The page works headless too — copy the key from any browser if your terminal can't auto-launch one.
  2. Your library is now on disk. The CLI wrote skills into .claude/skills/ (for Claude Code) and .agents/skills/ (the shared path for Cursor, Windsurf, Gemini CLI, Codex CLI, Cline, VS Code + Copilot, and others). Both paths are added to .gitignore — skills are a per-developer cache, not committed.
  3. From now on, use skillrepo update to pull new versions, skillrepo add to add skills to your library, and skillrepo list to see what you have.

If you'd rather provision the key yourself, create one at skillrepo.dev/app/settings (Settings → Access Keys) and pass --key <sk_live_...> to init.

Commands

init — first-run setup

skillrepo init [--key <key>] [--url <url>] [--yes] [--force] [--agent <list>] [--global] [--json] [--no-session-sync]

Validates your access key, picks which targets to configure (interactive two-row picker by default — Claude Code at .claude/skills/ and the shared .agents/skills/ cohort path for everything else), writes the MCP config, installs the Claude Code SessionStart hook (opt-in — see session-sync below), and runs the first library sync.

Detection drives the picker's pre-checked rows. Three signal types per agent are probed:

  • Active session env vars (e.g., CLAUDECODE, CURSOR_AGENT, GEMINI_CLI, CLINE_ACTIVE) — strongest signal, indicates the agent is currently running.
  • HOME traces (e.g., ~/.claude/, ~/.cursor/, ~/.codeium/windsurf/) — installed-on-this-machine signal.
  • Project dotfiles (e.g., .claude/, .cursor/, .github/skills/) — configured-for-this-repo signal.

When any signal fires for either target, that row pre-checks. Fresh clone with no detection: both rows still pre-checked — the product's job is to set up skills, defaulting to "do nothing" because env vars didn't fire is wrong. Pick the third row ("None") to skip placement and just write the config + gitignore.

| Flag | Description | |------|-------------| | --key, -k <key> | Access key. Falls back to SKILLREPO_ACCESS_KEY env var, then interactive prompt. | | --url, -u <url> | Server URL. Defaults to https://skillrepo.dev. Use for self-hosted. | | --yes, -y | Non-interactive. Skip all confirmation prompts. Required for CI. Installs the session-sync hook by default — pass --no-session-sync to opt out. Under npx, this also auto-runs npm install -g skillrepo@<this-version> if no global install is present (so the session-sync hook can use the resulting absolute path). | | --force | Re-prompt for a new key even if ~/.claude/skillrepo/config.json is valid. | | --agent <list> | Comma-separated agent target override. Canonical tokens: claude (Claude Code), agents (every other supported vendor — Cursor, Windsurf, Gemini CLI, Codex CLI, Cline, VS Code + Copilot — sharing the .agents/skills/ cohort path), none (skip placement entirely; init still writes config + gitignore). Vendor names like cursor or claude-code are accepted as silent aliases. | | --global | Write skills to ~/.claude/skills/ (personal) instead of .claude/skills/ (project). | | --no-session-sync | Skip step 6 (SessionStart hook install). Works in both interactive and --yes modes. Use for CI scripts that bootstrap a project without ever starting a Claude Code session. | | --json | Emit a structured JSON summary on success. Requires --yes. See JSON output shape below. |

JSON output shape (init --json --yes)

{
  "action": "initialized",
  "account": { "slug": "...", "id": "...", "tier": "publisher|developer|team" },
  "config": { "action": "created|updated|unchanged" },
  "vendors": ["claudeCode", "cursor", "..."],
  "mcp": {
    "merged": [".mcp.json", ".cursor/mcp.json"],
    "skipped": ["..."],
    "failed": [{ "path": "...", "reason": "..." }]
  },
  "sessionSync": {
    "action": "installed|unchanged|skipped|failed|not-applicable",
    "path": "...",
    "cohortHooks": [
      {
        "vendorKey": "cursor|gemini|codex|copilot",
        "displayName": "...",
        "path": "~/.cursor/hooks.json",
        "action": "installed|updated|unchanged|failed",
        "reason": "..."
      }
    ]
  },
  "sync": {
    "added": 0,
    "updated": 0,
    "removed": 0,
    "notModified": false,
    "fullSync": true,
    "syncedAt": "2026-05-01T00:00:00.000Z"
  }
}

Field notes:

  • vendors is the resolved canonical-key list, NOT the raw --agent input. --agent agents produces every cohort vendor (cursor, windsurf, gemini, codex, cline, copilot); --agent none produces an empty array.
  • sessionSync.cohortHooks[] reports per-vendor outcomes for the auto-refresh hooks installed alongside the Claude Code SessionStart hook (one entry per cohort vendor with a non-null agentHook registry spec — Cursor, Gemini CLI, Codex CLI, VS Code + Copilot). reason is present only when action: "failed". Empty array when --no-session-sync was passed or no cohort vendor was selected.
  • sync.fullSync is true for first-time syncs (no prior .last-sync), false for delta syncs, and null only on synthesized-failure summaries when the network call never completed (also signals via sync.failureReason).
  • sync.failureReason: string is present only when the first sync failed but the rest of init succeeded — config is still saved; user should re-run skillrepo update.

init is idempotent: re-running with a valid existing config re-runs detection + MCP merge + first sync without re-prompting for a key. If the stored key has been revoked (401 from /auth/validate), the CLI falls back to the interactive prompt automatically — including opening skillrepo.dev/cli/auth so you can mint a fresh key without leaving the terminal.

When stdin is not a TTY (CI, piped input), init skips the browser launch and just prints the URL — paste the key via the upstream pipe.

Headless / non-interactive: under --yes the picker is skipped and the pre-checked rows become the selection. With no detection signals, both default rows are pre-checked — running init --yes on a fresh clone configures both targets so CI bootstrap scripts always produce a working library. Pass --agent <target> (claude, agents, none, or a vendor name like cursor) to bypass the picker entirely.

update — sync your library

skillrepo update [--global] [--agent <list>] [--json] [--silent]

Pulls the latest state of your library from the server using a delta sync. Writes new and updated skills, removes skills that were removed from the library, and skips skills that are unchanged. Uses ETag caching so repeat runs return 304 Not Modified when nothing has changed.

--silent suppresses normal output and writes a single {} line to stdout on success. Designed for SessionStart hooks that pipe stdout to their agent's session log — Gemini CLI specifically requires hook stdout to be valid JSON, and the empty object satisfies that without injecting model context. Sync progress and warnings still go to stderr. On failure, the command exits with the appropriate non-zero code and the error message goes to stderr (distinct from --session-hook, which is Claude-Code-specific and exits 0 on every error so a sync failure can't block a session start).

get — fetch a single skill

skillrepo get <@owner/name> [--global] [--agent <list>] [--json]

One-shot fetch. Does NOT mutate your library or the server — just reads GET /api/v1/skills/{owner}/{name} and writes the skill to disk. Use this to preview or pin a specific skill without adding it to your library.

list — show what's in your library and what needs syncing

skillrepo list [--json]

Renders your library as a table with a per-row Local column showing on-disk drift state for each detected vendor:

  • OK — local copy matches the last sync.
  • STALE — library has a newer version than what's on disk.
  • MISS — library has the skill but no on-disk placement (or no sync history yet — run skillrepo update to establish a baseline).
  • EDIT — local files have been modified since the last sync (different SHA than what was persisted).

When multiple vendors are detected, the column shows a worst-state-wins rollup (missing > edited > stale > current). The --json output includes a placements[] array per item with per-vendor states for scripts that want the full breakdown.

A footer reports library-level sync state:

  • library in sync — local skills up to date — everything is current.
  • library in sync — but N skills show local drift — library hasn't changed but some local placements need attention.
  • library has changed since last sync — registry has new content; run skillrepo update.
  • No sync history on this machine — fresh install or baseline-less state; run skillrepo update.

Glyphs ( / ) are used in TTY contexts; ASCII fallbacks (OK / [!] / STALE / MISS / EDIT) appear when stdout is not a TTY or NO_COLOR is set, so piped output stays clean.

--json is a bare array of skill objects with the additional fields state (rollup) and placements[]. Existing scripts that consume the pre-#1555 --json shape keep working — the additions are purely per-item, no top-level wrapper.

Uses the same cached ETag as update for the library-level footer state.

search — explore the registry

skillrepo search <query> [--limit <n>] [--json] [--semantic]

Queries /api/v1/skills/search for public skills matching query. --limit caps the result count (default 20). --semantic is accepted but currently a no-op — semantic search is a planned backend feature.

add — add a skill to your library

skillrepo add <@owner/name> [--global] [--agent <list>] [--json]

POSTs to /api/v1/library, then fetches the single skill directly and writes it to disk. Requires a write-scoped access key. On 409 (already in library), re-fetches the current version so your local state is consistent.

remove — remove a skill from your library

skillrepo remove <@owner/name> [--global] [--agent <list>] [--json]

DELETEs from /api/v1/library and deletes the local directory. Requires a write-scoped access key. The local delete is immediate and does not wait for a follow-up sync.

push — upload a local skill directory to your account

skillrepo push <path> [--idempotency-key <key>] [--key <key>] [--url <url>] [--json]

Multipart POST to /api/v1/library. Walks <path>, packages SKILL.md plus every supporting file under scripts/, references/, and assets/, and uploads them as a single request. The server picks the outcome by SKILL.md frontmatter name:

  • First push of this name → creates a private skill and returns action: "created".
  • Subsequent push with changed content → releases a new version. The server classifies the bump as major (if description, allowed-tools, or compatibility changed) or minor otherwise, and returns action: "updated" with the bump kind.
  • Identical content → no-op (SHA-matched). Returns action: "unchanged".

push is the only CLI command that uploads local content; it does not write anything back to disk. Use update to pull canonical skills from the server to your local library.

Limits: total multipart body ≤ 4.5 MB, per-file path depth ≤ 5 segments, executable/archive extensions blocked (full list in src/lib/skills/constants.ts). Anti-abuse rate limit: 6/min and 100/hr on Developer; 30/min and 500/hr on Team. (push needs a write-scoped access key, which starts on the Developer plan.)

Flags:

  • --idempotency-key <key> — explicit key for safe retries. By default the CLI generates a fresh UUID per invocation and uses it for the in-process retry loop (transient 5xx/429 get up to 3 attempts with exponential backoff and jitter). Pass an explicit key to share it across separate shell invocations (CI step retries, manual reruns) and replay the cached response. Cached responses live for 24 hours.
  • --json — emit a structured object (action, bump, owner, name, version, filesUploaded).
  • --key, --url — standard auth / endpoint flags.

Exit codes: 5 (validation — bad SKILL.md, blocked path, payload too large, plan_limit), 4 (scope — read-only key), 2 (auth), 1 (network/5xx after retries).

publish — make one of your skills visible in the public catalog

skillrepo publish <@owner/name> [--key <key>] [--url <url>] [--json]

POSTs to /api/v1/library/{owner}/{name}/publish to flip the skill's visibility from private to global. Idempotent: calling publish on an already-global skill returns 200 with action: "unchanged" (the CLI prints "Already published"). Requires a write-scoped access key.

Permission model: admin+ members can always publish. Non-admin members can publish if their account-membership has canPublish: true (or the account-wide memberCanPublish default is enabled). Without either, the CLI exits 4 / scope with code: publish_not_permitted. The same canPublish capability gates unpublish and delete symmetrically.

Publish-only preconditions that surface as exit 5 / validation:

  • namespace_unset — the account's handle is still the auto-generated placeholder; choose an Author ID in Settings first.
  • analysis_pending — safety analysis hasn't completed (only fires where analysis is enabled).
  • safety_grade_too_low — the skill's safety grade is F.

Flags:

  • --json — emit { action, owner, name }. The CLI exits non-zero on error, so the presence of stdout JSON already implies success — there is no ok field.
  • --key, --url — standard auth / endpoint flags.

unpublish — remove one of your skills from the public catalog

skillrepo unpublish <@owner/name> [--key <key>] [--url <url>] [--json]

POSTs to /api/v1/library/{owner}/{name}/unpublish to flip the skill's visibility from global to private. Pair to publish: same auth, same scope, same flag surface.

Subscribers keep their copy. Accounts that already had your skill in their library retain the version they pulled — they just stop receiving future updates unless you republish. The CLI surfaces a one-line summary (e.g. "Notified 12 subscribers") so you know how many accounts the unpublish reached.

Each affected subscriber account's owner-role member(s) receive a one-time notification email, debounced 24h per (skill, account) pair so a fast unpublish/republish/unpublish cycle doesn't spam the same recipient. The publisher's own account is excluded. Already-private skills (action: "unchanged") trigger no emails.

Flags:

  • --json — emit { action, owner, name, notifiedSubscriberCount }. notifiedSubscriberCount is 0 when action === "unchanged". No ok field — exit code carries success/failure.
  • --key, --url — standard auth / endpoint flags.

session-sync — auto-sync on Claude Code session start

skillrepo session-sync enable [--global] [--json]
skillrepo session-sync disable [--global] [--json]

Installs (or removes) a Claude Code SessionStart hook that calls skillrepo update every time you open a Claude Code session — keeping your library current without you remembering to sync manually. The hook lives in .claude/settings.local.json (per-developer, gitignored by default) and runs your existing globally-installed skillrepo binary.

By default skillrepo init prompts you to install this hook. If you said no (or passed --no-session-sync), run session-sync enable later to turn it on.

Auto-refresh hooks for other agents

For Cursor, Gemini CLI, Codex CLI, and VS Code + Copilot, skillrepo init writes a SessionStart hook to each agent's user-scope hook config so your library refreshes on every session start without a separate command. Each hook invokes npx --yes skillrepo update --silent, so it works without a global skillrepo install.

| Agent | Hook config path | Notes | |-------|------------------|-------| | Cursor | ~/.cursor/hooks.json (sessionStart event) | timeout: 60 (seconds) | | Gemini CLI | ~/.gemini/settings.json (SessionStart event) | matcher: "*" group filter, timeout: 60000 (milliseconds), entry named skillrepo-update | | Codex CLI | ~/.codex/hooks.json (SessionStart event) | timeout: 60 (seconds). Codex also reads [hooks] from ~/.codex/config.toml; both sources coexist — Codex merges them at runtime, so a hand-written TOML entry won't conflict with our JSON. | | VS Code + Copilot | ~/.copilot/hooks/skillrepo-update.json (sessionStart event) | timeout: 60 (seconds). Preview status: GitHub currently labels Copilot's hook system as Preview; the schema may shift before GA. |

skillrepo init writes these alongside the Claude Code hook for every selected vendor that publishes a SessionStart-equivalent event. --no-session-sync skips ALL of them. skillrepo uninstall --global removes them surgically — other tools' entries (1Password, Snyk, your own scripts) in those config files are preserved.

Cloud-agent runners (e.g. GitHub Codespaces, Copilot's cloud agent) read only the committed default-branch content. Because skills sync to a per-developer, gitignored cache, those runners do not see the local skill library — same documented limitation as .agents/skills/ placement. The auto-refresh hooks above are per-developer; they don't run in cloud runners.

Auto-refresh hooks for Windsurf and Cline are not yet supported — those agents lack a documented SessionStart-equivalent event today. Run skillrepo update manually in those environments.

Under npx skillrepo init, the CLI offers to install itself globally. Session sync needs the binary at a stable absolute path (the npx cache path is transient and would break on the next cache eviction). Rather than skipping with a warning the way v3.1.1 did, v3.1.2 prompts during init: "SkillRepo needs a global install to enable session sync. Install skillrepo globally now? (Y/n)" — saying yes runs npm install -g skillrepo@<version> (pinned to the version you just invoked) and then installs the hook with the resulting absolute path. Under --yes the install runs without prompting; under --no-session-sync it's skipped entirely. If the install fails (permissions, network, registry), init prints actionable next-steps and continues; the rest of init still completes successfully.

skillrepo session-sync enable does not auto-install — it's an explicit, deliberate command and assumes you already have a global install. If invoked under npx without a global install present, it returns a clear "install globally first" message rather than mutating your global package set.

The hook cannot block your session. The command it runs is <path-to-skillrepo> update --session-hook 2>&1 [|| true]. The --session-hook flag makes update exit 0 on every failure — network outage, revoked key, disk error, anything — and print a single-line failure message to your session. On POSIX systems the || true shell backstop is appended as belt-and-suspenders; on Windows it's omitted because cmd.exe doesn't know the true builtin (the --session-hook flag's exit-0 contract is the primary defense regardless of platform). Session starts are never blocked by sync failures.

On 304 (nothing changed) the hook is silent. You only see output when your library actually syncs or a failure happens. No "Syncing…" noise on every session.

Flags:

  • --global — operates on ~/.claude/settings.local.json so the hook fires in every Claude Code session across all projects on your machine.
  • --json — emit structured JSON with action, path, and command fields for scripting.

uninstall — remove SkillRepo from a project

skillrepo uninstall [--dry-run] [--yes] [--global] [--json]

Surgically removes every SkillRepo artifact from the current project:

  • mcpServers.skillrepo from .mcp.json, .cursor/mcp.json, and .vscode/mcp.json (plus the matching inputs prompt in the VS Code config)
  • SKILLREPO_ACCESS_KEY=... lines from .env.local
  • The SkillRepo section of .gitignore
  • The SkillRepo SessionStart hook from .claude/settings.local.json (if present)
  • The .claude/skills/ directory

Non-SkillRepo entries in shared files are preserved. Runs offline — no server call required, so a revoked or missing access key is not a problem. Interactive by default: the command prints a full list of what will be removed and prompts for confirmation before touching anything.

With --global, also removes:

  • mcpServers.skillrepo from ~/.codeium/windsurf/mcp_config.json
  • The ~/.claude/skills/ global skill cache
  • The ~/.claude/skillrepo/ directory (stored credentials + sync cache)
  • The SkillRepo SessionStart entry from each cohort vendor's hook config — ~/.cursor/hooks.json, ~/.gemini/settings.json, ~/.codex/hooks.json, and ~/.copilot/hooks/skillrepo-update.json. Other tools' entries (1Password, Snyk, Apiiro, the user's own hooks) and unrelated top-level keys (theme, mcpServers, etc.) are preserved — only our entry, identified by the canonical command npx --yes skillrepo update --silent, is filtered out.

Flags:

  • --dry-run / -n — print what would be removed and exit without touching any file.
  • --yes / -y — skip the confirmation prompt.
  • --global — also remove user-global state. By default the command leaves your credential and other projects' integrations untouched.
  • --json — emit structured JSON instead of human output. The summary includes removed[] and errors[] arrays suitable for scripting.

The command is idempotent — a second run with nothing left to remove exits 0 and reports "Nothing to remove." If any artifact fails to remove (e.g. a file is read-only), the command continues processing the others, surfaces every error at the end, and exits with code 3 (disk error).

Configuration

Credentials

The CLI stores credentials at ~/.claude/skillrepo/config.json (chmod 0600 on POSIX):

{
  "schemaVersion": 1,
  "apiKey": "sk_live_...",
  "serverUrl": "https://skillrepo.dev",
  "accountSlug": "alice",
  "accountId": "acc_...",
  "userId": "user_...",
  "writtenAt": "2026-04-15T00:00:00Z"
}

Every command except init resolves credentials in this order:

  1. --key / --url CLI flags
  2. ~/.claude/skillrepo/config.json
  3. SKILLREPO_ACCESS_KEY / SKILLREPO_URL environment variables
  4. Hard-fail with a "run skillrepo init" hint

init is different by design. Because init owns the credential lifecycle — it writes the config file in the first place, and --force / stale-key re-prompts need to decide whether to reuse cached credentials — init uses a more nuanced order. Resolved in sequence (each step only runs if the prior ones produced no key):

  1. --key / --url CLI flags
  2. SKILLREPO_ACCESS_KEY / SKILLREPO_URL environment variables (process env, not files)
  3. Existing ~/.claude/skillrepo/config.json — skipped when --force is set
  4. .env.local and .env files in the project directory — skipped when --force is set
  5. Interactive prompt for the key; server URL falls back to https://skillrepo.dev

Two scenarios worth calling out:

  • init --force with SKILLREPO_ACCESS_KEY set: uses the env var (step 2). --force only clears the cached credentials, not the runtime env.
  • init with valid existing config and no flags/env: reuses the cached credentials for a silent no-op refresh.
  • init with a config that the server now rejects (stale key): falls through to the interactive prompt automatically, without needing --force.

Environment variables

| Variable | Purpose | |----------|---------| | SKILLREPO_ACCESS_KEY | Access key for any command. Takes precedence over the config file but not CLI flags. | | SKILLREPO_URL | Server URL. Same precedence as above. | | SKILLREPO_TIMEOUT_MS | Per-request fetch timeout in milliseconds (default 30000). Set to 0 to disable. | | SKILLREPO_NO_UPDATE_CHECK | Set to any non-empty truthy value (1, yes, true) to disable the post-command npm-registry self-staleness check. The check otherwise runs at most once per 24 hours, hits registry.npmjs.org/skillrepo/latest, and prints a one-line upgrade hint to stderr if a newer version is available. Auto-disabled when CI=true. | | NO_COLOR | Set any non-empty value to disable ANSI color in CLI output. |

Update nudge

After every command that isn't --json, the CLI does a best-effort check against https://registry.npmjs.org/skillrepo/latest and prints a one-line hint on stderr when a newer version is available:

  A newer skillrepo is available: 4.3.0 → 4.5.0
  Upgrade: npm install -g skillrepo@latest

The check is cached at ~/.claude/skillrepo/.npm-version-check for 24 hours on success and 1 hour on failure, has a 2-second fetch timeout, and is fire-and-forget — every failure mode (network error, non-2xx, parse failure, read-only FS) is swallowed silently. Set SKILLREPO_NO_UPDATE_CHECK=1 to disable. CI=true auto-disables. Output is suppressed entirely when --json is on the parent command, so structured pipelines aren't disturbed.

Skill placement

Skills land at one of two project paths, depending on the agent:

| Agent | Project path | Personal (--global) path | |---|---|---| | Claude Code | .claude/skills/<name>/ | ~/.claude/skills/<name>/ | | Cursor / Windsurf / Gemini CLI / Codex CLI / Cline / GitHub Copilot | .agents/skills/<name>/ | ~/.agents/skills/<name>/ | | Windsurf (personal-scope override) | — | ~/.codeium/windsurf/skills/<name>/ |

The CLI auto-adds .claude/skills/ and .agents/skills/ to your project .gitignore on first write — skills are a per-developer cache, not committed content. The --agent flag overrides detection (e.g. --agent claude,agents writes both paths). See docs/vendor-paths.md for primary-source citations on each agent's read paths.

Exit codes

| Code | Meaning | |------|---------| | 0 | Success | | 1 | Network error (unreachable server, DNS, timeout, exhausted retries) | | 2 | Auth error (invalid key, revoked, suspended account) | | 3 | Disk error (cannot read or write a file/directory) | | 4 | Scope error (key lacks the required registry:write scope) | | 5 | Validation error (bad flag, malformed identifier, unknown vendor) |

Pass --verbose to any command to print stack traces and retry attempts on failure.

Retries

The CLI automatically retries transient server failures on every idempotent API call — specifically POST /auth/validate, GET /library, GET /skills/:owner/:name, and GET /skills/search. This means the read-only commands (update, get, list, search) and the validate + sync calls inside init benefit automatically.

  • Triggered by: 429, 502, 503, 504, and raw network errors (DNS, TCP reset, timeout).
  • NOT triggered by: 4xx auth/validation errors — those never succeed on retry — nor 500, which is treated as a real-bug signal that should surface loudly rather than be masked.
  • Backoff: exponential with full jitter, 3 attempts total, base 500ms, capped at 8 seconds per sleep.
  • Write endpoints (add, remove) are single-shot to keep behavior predictable — a 503 mid-POST could mean either "body never reached the server" or "body processed, response lost", and the client cannot distinguish the two.

Self-hosted SkillRepo

The CLI works against any SkillRepo instance that implements the v1 API. Point it at your own host:

skillrepo init --url https://skillrepo.internal.company.com

Or persist it via env var in your shell profile:

export SKILLREPO_URL=https://skillrepo.internal.company.com
export SKILLREPO_ACCESS_KEY=sk_live_...

Troubleshooting

"No access key configured" — Run skillrepo init, or pass --key, or set SKILLREPO_ACCESS_KEY.

"Invalid access key format" — Keys must start with sk_live_. The CLI trims leading and trailing whitespace from keys in every path — both the interactive prompt in init and the Bearer header used by every subsequent command — so pasting from email or a browser with a trailing newline is safe.

Picker selected nothing under --yes — Phase 3 (#1236) replaced the old "no agents detected → refuse" branch with a friendlier default: when no detection signals fire, both default rows are pre-checked, so --yes configures both targets. If you want to skip placement entirely under --yes, pass --agent none (config and gitignore still happen; only the skill files are skipped).

"Rate limit exceeded — retried automatically and still getting 429" — The CLI already retried with backoff. Wait a minute and retry. Pass --verbose to see the per-attempt timings.

Windows: skill updates use a best-effort atomic rename pattern. A crash mid-update may leave a partial state; the next update run fully overwrites it.

License

Proprietary. Copyright © 2026 SkillRepo LLC. All rights reserved. Use of this CLI is governed by the SkillRepo End User License Agreement at https://skillrepo.dev/eula. See LICENSE for the full notice.