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 initValidates 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
- Run
initinside your project directory:
When no key is configured,npx skillrepo initinitopens 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. - 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. - From now on, use
skillrepo updateto pull new versions,skillrepo addto add skills to your library, andskillrepo listto 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_...>toinit.
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:
vendorsis the resolved canonical-key list, NOT the raw--agentinput.--agent agentsproduces every cohort vendor (cursor, windsurf, gemini, codex, cline, copilot);--agent noneproduces 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-nullagentHookregistry spec — Cursor, Gemini CLI, Codex CLI, VS Code + Copilot).reasonis present only whenaction: "failed". Empty array when--no-session-syncwas passed or no cohort vendor was selected.sync.fullSyncistruefor first-time syncs (no prior.last-sync),falsefor delta syncs, andnullonly on synthesized-failure summaries when the network call never completed (also signals viasync.failureReason).sync.failureReason: stringis present only when the first sync failed but the rest of init succeeded — config is still saved; user should re-runskillrepo 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 — runskillrepo updateto 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; runskillrepo update.No sync history on this machine— fresh install or baseline-less state; runskillrepo 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, orcompatibilitychanged) or minor otherwise, and returnsaction: "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 isF.
Flags:
--json— emit{ action, owner, name }. The CLI exits non-zero on error, so the presence of stdout JSON already implies success — there is nookfield.--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 }.notifiedSubscriberCountis0whenaction === "unchanged". Nookfield — 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.jsonso the hook fires in every Claude Code session across all projects on your machine.--json— emit structured JSON withaction,path, andcommandfields 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.skillrepofrom.mcp.json,.cursor/mcp.json, and.vscode/mcp.json(plus the matchinginputsprompt in the VS Code config)SKILLREPO_ACCESS_KEY=...lines from.env.local- The SkillRepo section of
.gitignore - The SkillRepo
SessionStarthook 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.skillrepofrom~/.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 commandnpx --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 includesremoved[]anderrors[]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:
--key/--urlCLI flags~/.claude/skillrepo/config.jsonSKILLREPO_ACCESS_KEY/SKILLREPO_URLenvironment variables- 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):
--key/--urlCLI flagsSKILLREPO_ACCESS_KEY/SKILLREPO_URLenvironment variables (process env, not files)- Existing
~/.claude/skillrepo/config.json— skipped when--forceis set .env.localand.envfiles in the project directory — skipped when--forceis set- Interactive prompt for the key; server URL falls back to
https://skillrepo.dev
Two scenarios worth calling out:
init --forcewithSKILLREPO_ACCESS_KEYset: uses the env var (step 2).--forceonly clears the cached credentials, not the runtime env.initwith valid existing config and no flags/env: reuses the cached credentials for a silent no-op refresh.initwith 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@latestThe 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.comOr 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.
