skillrepo 2.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +276 -145
  2. package/bin/skillrepo.mjs +224 -36
  3. package/package.json +6 -3
  4. package/src/commands/add.mjs +176 -0
  5. package/src/commands/get.mjs +116 -0
  6. package/src/commands/init.mjs +589 -143
  7. package/src/commands/list.mjs +176 -0
  8. package/src/commands/remove.mjs +162 -0
  9. package/src/commands/search.mjs +188 -0
  10. package/src/commands/session-sync.mjs +152 -0
  11. package/src/commands/uninstall.mjs +484 -0
  12. package/src/commands/update.mjs +184 -0
  13. package/src/lib/artifact-registry.mjs +265 -0
  14. package/src/lib/cli-config.mjs +230 -0
  15. package/src/lib/config.mjs +238 -0
  16. package/src/lib/detect-ides.mjs +0 -19
  17. package/src/lib/errors.mjs +264 -0
  18. package/src/lib/file-write.mjs +705 -0
  19. package/src/lib/fs-utils.mjs +83 -1
  20. package/src/lib/http.mjs +817 -37
  21. package/src/lib/identifier.mjs +153 -0
  22. package/src/lib/mcp-merge.mjs +275 -0
  23. package/src/lib/mergers/gitignore.mjs +73 -18
  24. package/src/lib/mergers/session-hook.mjs +298 -0
  25. package/src/lib/paths.mjs +67 -17
  26. package/src/lib/prompt.mjs +11 -44
  27. package/src/lib/removers/claude-mcp.mjs +67 -0
  28. package/src/lib/removers/cursor-mcp.mjs +60 -0
  29. package/src/lib/removers/env-local.mjs +55 -0
  30. package/src/lib/removers/gitignore.mjs +108 -0
  31. package/src/lib/removers/settings.mjs +183 -0
  32. package/src/lib/removers/vscode-mcp.mjs +87 -0
  33. package/src/lib/removers/windsurf-mcp.mjs +65 -0
  34. package/src/lib/sync.mjs +305 -0
  35. package/src/test/commands/add.test.mjs +285 -0
  36. package/src/test/commands/get.test.mjs +176 -0
  37. package/src/test/commands/init.test.mjs +697 -0
  38. package/src/test/commands/list.test.mjs +172 -0
  39. package/src/test/commands/remove.test.mjs +234 -0
  40. package/src/test/commands/search.test.mjs +204 -0
  41. package/src/test/commands/session-sync.test.mjs +350 -0
  42. package/src/test/commands/uninstall.test.mjs +768 -0
  43. package/src/test/commands/update.test.mjs +322 -0
  44. package/src/test/detect-ides.test.mjs +9 -14
  45. package/src/test/dispatcher.test.mjs +224 -0
  46. package/src/test/e2e/cli-commands.test.mjs +576 -0
  47. package/src/test/e2e/mock-server.mjs +364 -22
  48. package/src/test/helpers/capture-stream.mjs +48 -0
  49. package/src/test/integration/file-write.integration.test.mjs +279 -0
  50. package/src/test/lib/artifact-registry.test.mjs +268 -0
  51. package/src/test/lib/cli-config.test.mjs +407 -0
  52. package/src/test/lib/config.test.mjs +257 -0
  53. package/src/test/lib/errors.test.mjs +359 -0
  54. package/src/test/lib/file-write.test.mjs +784 -0
  55. package/src/test/lib/http.test.mjs +1198 -0
  56. package/src/test/lib/identifier.test.mjs +157 -0
  57. package/src/test/lib/mcp-merge.test.mjs +345 -0
  58. package/src/test/lib/paths.test.mjs +83 -0
  59. package/src/test/lib/sync.test.mjs +514 -0
  60. package/src/test/mergers/gitignore.test.mjs +145 -20
  61. package/src/test/mergers/session-hook.test.mjs +745 -0
  62. package/src/test/mergers/uninstall-claude-mcp.test.mjs +145 -0
  63. package/src/test/mergers/uninstall-cursor-mcp.test.mjs +108 -0
  64. package/src/test/mergers/uninstall-env-local.test.mjs +144 -0
  65. package/src/test/mergers/uninstall-gitignore.test.mjs +209 -0
  66. package/src/test/mergers/uninstall-settings.test.mjs +285 -0
  67. package/src/test/mergers/uninstall-vscode-mcp.test.mjs +215 -0
  68. package/src/test/mergers/uninstall-windsurf-mcp.test.mjs +122 -0
  69. package/src/lib/write-configs.mjs +0 -202
  70. package/src/test/e2e/HANDOFF.md +0 -223
  71. package/src/test/e2e/cli-init.test.mjs +0 -213
  72. package/src/test/e2e/payload-factory.mjs +0 -22
package/README.md CHANGED
@@ -1,214 +1,345 @@
1
1
  # skillrepo
2
2
 
3
- Set up SkillRepo in any IDE -- one command.
3
+ A pull-based CLI for managing your agent-skills library from the terminal.
4
4
 
5
5
  ```
6
6
  npx skillrepo init
7
7
  ```
8
8
 
9
- Auto-detects your IDEs, validates your access key, and writes the correct MCP
10
- configuration for each one. Safe to run multiple times.
9
+ Validates your access key, auto-detects your IDEs, wires up the MCP config,
10
+ and pulls your library. Safe to re-run at any time.
11
11
 
12
- ## Quick Start
13
-
14
- 1. **Create an access key** at [skillrepo.dev/app/settings](https://skillrepo.dev/app/settings) (Settings > Access Keys).
15
- 2. **Run the CLI** in your project directory:
16
- ```
17
- npx skillrepo init
18
- ```
19
- 3. **Done.** Your IDE can now discover and activate skills from your SkillRepo library.
20
-
21
- ## Usage
22
-
23
- ```
24
- npx skillrepo init [options]
25
- ```
26
-
27
- ### Options
28
-
29
- | Flag | Short | Description |
30
- |------|-------|-------------|
31
- | `--key <key>` | `-k` | Access key. If omitted, the CLI reads `SKILLREPO_ACCESS_KEY` from the environment, then prompts interactively. |
32
- | `--url <url>` | `-u` | SkillRepo server URL. Defaults to `https://skillrepo.dev`. Use this for self-hosted instances. |
33
- | `--yes` | `-y` | Non-interactive mode. Skips confirmation prompts. Useful for CI or scripted setups. |
34
-
35
- ### Examples
12
+ ## Install
36
13
 
37
14
  ```sh
38
- # Interactive setup (prompts for key and confirms detected IDEs)
39
- npx skillrepo init
40
-
41
- # Pass the key directly
42
- npx skillrepo init --key sk_live_abc123
15
+ # One-off via npx (recommended)
16
+ npx skillrepo <command>
43
17
 
44
- # Self-hosted instance, non-interactive
45
- npx skillrepo init --url https://skillrepo.internal.company.com --yes
46
-
47
- # Key from environment variable
48
- export SKILLREPO_ACCESS_KEY=sk_live_abc123
49
- npx skillrepo init --yes
18
+ # Or install globally
19
+ npm install -g skillrepo
20
+ skillrepo <command>
50
21
  ```
51
22
 
52
- ## What It Does
53
-
54
- The CLI performs four steps:
23
+ Requires Node.js 18 or later.
55
24
 
56
- 1. **Detects installed IDEs** by checking for IDE-specific directories in the
57
- current project (`.claude/`, `.cursor/`, `.vscode/`) and global paths
58
- (`~/.codeium/windsurf/`). If no IDE is detected, it defaults to Claude Code
59
- and Cursor.
25
+ ## Quick start
60
26
 
61
- 2. **Validates the access key** against the SkillRepo API and fetches the
62
- current skill mapping data for your library.
27
+ 1. **Create an access key** at [skillrepo.dev/app/settings](https://skillrepo.dev/app/settings)
28
+ (Settings Access Keys).
29
+ 2. **Run `init`** inside your project directory:
30
+ ```sh
31
+ npx skillrepo init
32
+ ```
33
+ 3. **Your library is now on disk.** The CLI wrote skills into
34
+ `.claude/skills/` (project) and registered the MCP server with every IDE
35
+ it detected (`.claude/`, `.cursor/`, `.vscode/`, `~/.codeium/windsurf/`).
36
+ 4. **From now on**, use `skillrepo update` to pull new versions,
37
+ `skillrepo add` to add skills to your library, and `skillrepo list` to
38
+ see what you have.
63
39
 
64
- 3. **Writes MCP configuration files** for each detected IDE, using the correct
65
- format and environment variable syntax for that IDE.
40
+ ## Commands
66
41
 
67
- 4. **Writes skill mapping files** that let agents match user requests to the
68
- right skill without a network round-trip. For Claude Code, it also installs a
69
- SessionStart hook that auto-refreshes the mapping on each session start.
42
+ ### `init` first-run setup
70
43
 
71
- ### Files Created or Modified
44
+ ```sh
45
+ skillrepo init [--key <key>] [--url <url>] [--yes] [--force] [--ide <list>] [--global] [--json] [--no-session-sync]
46
+ ```
72
47
 
73
- | File | IDE | Purpose |
74
- |------|-----|---------|
75
- | `.mcp.json` | Claude Code | MCP server connection config |
76
- | `.claude/skillrepo.md` | Claude Code | Skill-to-tool mapping |
77
- | `.cursor/mcp.json` | Cursor | MCP server connection config |
78
- | `.cursor/rules/skillrepo.mdc` | Cursor | Skill-to-tool mapping |
79
- | `~/.codeium/windsurf/mcp_config.json` | Windsurf | MCP server connection config (global) |
80
- | `.vscode/mcp.json` | VS Code + Copilot | MCP server connection config |
81
- | `.env.local` | All | Stores `SKILLREPO_ACCESS_KEY` (gitignored) |
48
+ Validates your access key, detects installed IDEs, writes the MCP config,
49
+ installs the Claude Code SessionStart hook (opt-in — see `session-sync`
50
+ below), and runs the first library sync.
82
51
 
83
- All writes are merge-safe. The CLI reads existing files, adds or updates only
84
- the `skillrepo` entry, and leaves all other entries untouched. Running `init`
85
- again with a new key updates the key in `.env.local` without affecting anything
86
- else.
52
+ | Flag | Description |
53
+ |------|-------------|
54
+ | `--key, -k <key>` | Access key. Falls back to `SKILLREPO_ACCESS_KEY` env var, then interactive prompt. |
55
+ | `--url, -u <url>` | Server URL. Defaults to `https://skillrepo.dev`. Use for self-hosted. |
56
+ | `--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. |
57
+ | `--force` | Re-prompt for a new key even if `~/.claude/skillrepo/config.json` is valid. |
58
+ | `--ide <list>` | Comma-separated vendor override. One or more of `claude`, `cursor`, `windsurf`, `vscode`, or `all`. |
59
+ | `--global` | Write skills to `~/.claude/skills/` (personal) instead of `.claude/skills/` (project). |
60
+ | `--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. |
61
+ | `--json` | Emit a structured JSON summary on success. Includes a `sessionSync: { action, path }` block describing whether the hook was installed. |
87
62
 
88
- ## IDE-Specific Details
63
+ `init` is idempotent: re-running with a valid existing config re-runs
64
+ detection + MCP merge + first sync without re-prompting for a key. If the
65
+ stored key has been revoked (401 from `/auth/validate`), the CLI falls back
66
+ to the interactive prompt automatically.
89
67
 
90
- ### Claude Code
68
+ **Headless / CI:** if you run from a directory with no IDE markers, init
69
+ will refuse and print a copy-pasteable MCP config for manual wiring. To
70
+ proceed anyway, pass `--ide claude` (or the target vendor).
91
71
 
92
- - Config file: `.mcp.json` with `mcpServers.skillrepo` entry
93
- - Uses `${SKILLREPO_ACCESS_KEY}` syntax for environment variable expansion
94
- - Includes `"type": "http"` in the server entry
95
- - Installs a SessionStart hook that refreshes the skill mapping file
96
- (`.claude/skillrepo.md`) automatically on every session start
97
- - Skill mappings are always current without manual intervention
72
+ ### `update` sync your library
98
73
 
99
- ### Cursor
74
+ ```sh
75
+ skillrepo update [--global] [--ide <list>] [--json]
76
+ ```
100
77
 
101
- - Config file: `.cursor/mcp.json` with `mcpServers.skillrepo` entry
102
- - Uses `${env:SKILLREPO_ACCESS_KEY}` syntax for environment variable expansion
103
- - Skill mapping file (`.cursor/rules/skillrepo.mdc`) is static; re-run
104
- `npx skillrepo init` or ask your agent to run `update skills from skillrepo`
105
- to refresh it after adding or removing skills
78
+ Pulls the latest state of your library from the server using a delta
79
+ sync. Writes new and updated skills, removes skills that were removed
80
+ from the library, and skips skills that are unchanged. Uses ETag
81
+ caching so repeat runs return `304 Not Modified` when nothing has
82
+ changed.
106
83
 
107
- ### Windsurf
84
+ ### `get` — fetch a single skill
108
85
 
109
- - Config file: `~/.codeium/windsurf/mcp_config.json` (global, not per-project)
110
- - Uses `serverUrl` instead of `url` in the server entry
111
- - Uses `${env:SKILLREPO_ACCESS_KEY}` syntax for environment variable expansion
86
+ ```sh
87
+ skillrepo get <@owner/name> [--global] [--ide <list>] [--json]
88
+ ```
112
89
 
113
- ### VS Code + Copilot
90
+ One-shot fetch. Does NOT mutate your library or the server — just reads
91
+ `GET /api/v1/skills/{owner}/{name}` and writes the skill to disk. Use
92
+ this to preview or pin a specific skill without adding it to your library.
114
93
 
115
- - Config file: `.vscode/mcp.json` with `servers.skillrepo` entry (note:
116
- `servers`, not `mcpServers`)
117
- - VS Code does not support environment variable interpolation in MCP config;
118
- instead, the CLI creates an `inputs` entry that prompts for the access key on
119
- first use
120
- - Uses `${input:skillrepo-api-key}` syntax to reference the input prompt
94
+ ### `list` show what's in your library
121
95
 
122
- ## Team Setup
96
+ ```sh
97
+ skillrepo list [--json]
98
+ ```
123
99
 
124
- For teams sharing a repository, an admin runs the setup once and commits the
125
- generated config files. Each developer then clones and adds their own key.
100
+ Renders your library as a table: owner, name, version, description. Uses
101
+ the same cached ETag as `update`.
126
102
 
127
- ### Admin (one-time)
103
+ ### `search` — explore the registry
128
104
 
129
105
  ```sh
130
- cd your-team-repo
131
- npx skillrepo init
132
- git add .mcp.json .claude/ .cursor/ .vscode/
133
- git commit -m "chore: add SkillRepo integration"
134
- git push
106
+ skillrepo search <query> [--limit <n>] [--json] [--semantic]
135
107
  ```
136
108
 
137
- The `.env.local` file is not committed -- it contains the access key and should
138
- remain gitignored.
109
+ Queries `/api/v1/skills/search` for public skills matching `query`.
110
+ `--limit` caps the result count (default 20). `--semantic` is accepted
111
+ but currently a no-op — semantic search is a planned backend feature.
139
112
 
140
- ### Each Developer
113
+ ### `add` — add a skill to your library
141
114
 
142
115
  ```sh
143
- git pull
144
- npx skillrepo init
116
+ skillrepo add <@owner/name> [--global] [--ide <list>] [--json]
145
117
  ```
146
118
 
147
- The CLI detects the existing config files, merges in any updates, and writes the
148
- developer's own access key to `.env.local`. Developers can also skip the CLI
149
- and set the environment variable manually:
119
+ POSTs to `/api/v1/library`, then fetches the single skill directly and
120
+ writes it to disk. Requires a write-scoped access key. On `409` (already
121
+ in library), re-fetches the current version so your local state is
122
+ consistent.
123
+
124
+ ### `remove` — remove a skill from your library
150
125
 
151
126
  ```sh
152
- echo 'SKILLREPO_ACCESS_KEY=sk_live_their_key' >> .env.local
127
+ skillrepo remove <@owner/name> [--global] [--ide <list>] [--json]
153
128
  ```
154
129
 
155
- ## Self-Hosted Usage
130
+ DELETEs from `/api/v1/library` and deletes the local directory. Requires
131
+ a write-scoped access key. The local delete is immediate and does not
132
+ wait for a follow-up sync.
156
133
 
157
- If you run a self-hosted SkillRepo instance, pass the `--url` flag:
134
+ ### `session-sync` auto-sync on Claude Code session start
158
135
 
159
136
  ```sh
160
- npx skillrepo init --url https://skillrepo.internal.company.com
137
+ skillrepo session-sync enable [--global] [--json]
138
+ skillrepo session-sync disable [--global] [--json]
161
139
  ```
162
140
 
163
- The CLI writes the custom URL into all MCP config files. The access key is
164
- validated against your self-hosted instance instead of skillrepo.dev.
141
+ Installs (or removes) a Claude Code [SessionStart hook](https://docs.claude.com/en/docs/claude-code/hooks) 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.
165
142
 
166
- You can also set the URL via the `SKILLREPO_URL` environment variable to avoid
167
- passing `--url` every time.
143
+ 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.
168
144
 
169
- ## Troubleshooting
145
+ **The hook cannot block your session.** The command it runs is `skillrepo update --session-hook 2>&1 || true`. That 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. The `|| true` shell backstop catches anything that escapes. Session starts are never blocked by sync failures.
170
146
 
171
- ### "Invalid key format. Keys start with sk_live_"
147
+ **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.
172
148
 
173
- Access keys always begin with `sk_live_`. Verify you copied the full key from
174
- Settings > Access Keys. If the key was created with a different prefix, it may
175
- be a test key that is not valid for production use.
149
+ Flags:
176
150
 
177
- ### "Cannot reach https://skillrepo.dev"
151
+ - `--global` operates on `~/.claude/settings.local.json` so the hook fires in every Claude Code session across all projects on your machine.
152
+ - `--json` — emit structured JSON with `action`, `path`, and `command` fields for scripting.
178
153
 
179
- Check your network connection. If you are behind a corporate proxy or firewall,
180
- ensure HTTPS traffic to `skillrepo.dev` (or your self-hosted URL) is allowed.
181
- For self-hosted instances, verify the `--url` flag points to the correct address.
154
+ ### `uninstall` remove SkillRepo from a project
182
155
 
183
- ### "Cannot parse .mcp.json -- invalid JSON"
156
+ ```sh
157
+ skillrepo uninstall [--dry-run] [--yes] [--global] [--json]
158
+ ```
159
+
160
+ Surgically removes every SkillRepo artifact from the current project:
161
+
162
+ - `mcpServers.skillrepo` from `.mcp.json`, `.cursor/mcp.json`,
163
+ and `.vscode/mcp.json` (plus the matching `inputs` prompt in the
164
+ VS Code config)
165
+ - `SKILLREPO_ACCESS_KEY=...` lines from `.env.local`
166
+ - The SkillRepo section of `.gitignore`
167
+ - The SkillRepo `SessionStart` hook from `.claude/settings.local.json`
168
+ (if present)
169
+ - The `.claude/skills/` directory
170
+
171
+ Non-SkillRepo entries in shared files are preserved. Runs offline — no
172
+ server call required, so a revoked or missing access key is not a
173
+ problem. Interactive by default: the command prints a full list of what
174
+ will be removed and prompts for confirmation before touching anything.
175
+
176
+ With `--global`, also removes:
177
+
178
+ - `mcpServers.skillrepo` from `~/.codeium/windsurf/mcp_config.json`
179
+ - The `~/.claude/skills/` global skill cache
180
+ - The `~/.claude/skillrepo/` directory (stored credentials + sync cache)
181
+
182
+ Flags:
183
+
184
+ - `--dry-run` / `-n` — print what would be removed and exit without
185
+ touching any file.
186
+ - `--yes` / `-y` — skip the confirmation prompt.
187
+ - `--global` — also remove user-global state. By default the command
188
+ leaves your credential and other projects' integrations untouched.
189
+ - `--json` — emit structured JSON instead of human output. The summary
190
+ includes `removed[]` and `errors[]` arrays suitable for scripting.
191
+
192
+ The command is idempotent — a second run with nothing left to remove
193
+ exits 0 and reports "Nothing to remove." If any artifact fails to
194
+ remove (e.g. a file is read-only), the command continues processing
195
+ the others, surfaces every error at the end, and exits with code 3
196
+ (disk error).
197
+
198
+ ## Configuration
199
+
200
+ ### Credentials
201
+
202
+ The CLI stores credentials at `~/.claude/skillrepo/config.json` (chmod
203
+ 0600 on POSIX):
204
+
205
+ ```json
206
+ {
207
+ "schemaVersion": 1,
208
+ "apiKey": "sk_live_...",
209
+ "serverUrl": "https://skillrepo.dev",
210
+ "accountSlug": "alice",
211
+ "accountId": "acc_...",
212
+ "userId": "user_...",
213
+ "writtenAt": "2026-04-15T00:00:00Z"
214
+ }
215
+ ```
184
216
 
185
- The CLI cannot merge into a malformed JSON file. Open the file, fix the syntax
186
- error (or delete it to start fresh), then run `npx skillrepo init` again.
217
+ Every command except `init` resolves credentials in this order:
218
+ 1. `--key` / `--url` CLI flags
219
+ 2. `~/.claude/skillrepo/config.json`
220
+ 3. `SKILLREPO_ACCESS_KEY` / `SKILLREPO_URL` environment variables
221
+ 4. Hard-fail with a "run `skillrepo init`" hint
222
+
223
+ `init` is different by design. Because `init` owns the credential
224
+ lifecycle — it writes the config file in the first place, and
225
+ `--force` / stale-key re-prompts need to decide whether to reuse
226
+ cached credentials — `init` uses a more nuanced order. Resolved
227
+ in sequence (each step only runs if the prior ones produced no
228
+ key):
229
+
230
+ 1. `--key` / `--url` CLI flags
231
+ 2. `SKILLREPO_ACCESS_KEY` / `SKILLREPO_URL` environment variables
232
+ (process env, not files)
233
+ 3. Existing `~/.claude/skillrepo/config.json` — skipped when
234
+ `--force` is set
235
+ 4. `.env.local` and `.env` files in the project directory — skipped
236
+ when `--force` is set
237
+ 5. Interactive prompt for the key; server URL falls back to
238
+ `https://skillrepo.dev`
239
+
240
+ Two scenarios worth calling out:
241
+
242
+ - **`init --force` with `SKILLREPO_ACCESS_KEY` set**: uses the env
243
+ var (step 2). `--force` only clears the cached credentials, not
244
+ the runtime env.
245
+ - **`init` with valid existing config and no flags/env**: reuses
246
+ the cached credentials for a silent no-op refresh.
247
+ - **`init` with a config that the server now rejects (stale key)**:
248
+ falls through to the interactive prompt automatically, without
249
+ needing `--force`.
250
+
251
+ ### Environment variables
252
+
253
+ | Variable | Purpose |
254
+ |----------|---------|
255
+ | `SKILLREPO_ACCESS_KEY` | Access key for any command. Takes precedence over the config file but not CLI flags. |
256
+ | `SKILLREPO_URL` | Server URL. Same precedence as above. |
257
+ | `SKILLREPO_TIMEOUT_MS` | Per-request fetch timeout in milliseconds (default 30000). Set to `0` to disable. |
258
+ | `NO_COLOR` | Set any non-empty value to disable ANSI color in CLI output. |
259
+
260
+ ### Skill placement
261
+
262
+ By default, skills land at `.claude/skills/<name>/` (project-scoped). Pass
263
+ `--global` to target `~/.claude/skills/<name>/` instead. When the CLI
264
+ detects an IDE that has no documented skills convention (Cursor, Windsurf,
265
+ VS Code), it falls back to project `/skills/<name>/` and adds `/skills/`
266
+ to your `.gitignore` on first write.
267
+
268
+ ## Exit codes
269
+
270
+ | Code | Meaning |
271
+ |------|---------|
272
+ | 0 | Success |
273
+ | 1 | Network error (unreachable server, DNS, timeout, exhausted retries) |
274
+ | 2 | Auth error (invalid key, revoked, suspended account) |
275
+ | 3 | Disk error (cannot read or write a file/directory) |
276
+ | 4 | Scope error (key lacks the required `registry:write` scope) |
277
+ | 5 | Validation error (bad flag, malformed identifier, unknown vendor) |
278
+
279
+ Pass `--verbose` to any command to print stack traces and retry
280
+ attempts on failure.
281
+
282
+ ## Retries
283
+
284
+ The CLI automatically retries transient server failures on every
285
+ idempotent API call — specifically `POST /auth/validate`,
286
+ `GET /library`, `GET /skills/:owner/:name`, and `GET /skills/search`.
287
+ This means the read-only commands (`update`, `get`, `list`, `search`)
288
+ and the validate + sync calls inside `init` benefit automatically.
289
+
290
+ - **Triggered by:** 429, 502, 503, 504, and raw network errors (DNS,
291
+ TCP reset, timeout).
292
+ - **NOT triggered by:** 4xx auth/validation errors — those never
293
+ succeed on retry — nor 500, which is treated as a real-bug signal
294
+ that should surface loudly rather than be masked.
295
+ - **Backoff:** exponential with full jitter, 3 attempts total, base
296
+ 500ms, capped at 8 seconds per sleep.
297
+ - **Write endpoints** (`add`, `remove`) are single-shot to keep
298
+ behavior predictable — a 503 mid-POST could mean either "body
299
+ never reached the server" or "body processed, response lost",
300
+ and the client cannot distinguish the two.
301
+
302
+ ## Self-hosted SkillRepo
303
+
304
+ The CLI works against any SkillRepo instance that implements the v1 API.
305
+ Point it at your own host:
187
306
 
188
- ### "No IDEs detected"
307
+ ```sh
308
+ skillrepo init --url https://skillrepo.internal.company.com
309
+ ```
189
310
 
190
- The CLI looks for IDE-specific directories in the current working directory. If
191
- you are not in a project root, `cd` into your project first. If no IDE
192
- directories exist yet, the CLI defaults to configuring Claude Code and Cursor.
311
+ Or persist it via env var in your shell profile:
193
312
 
194
- ### VS Code prompts for the access key every time
313
+ ```sh
314
+ export SKILLREPO_URL=https://skillrepo.internal.company.com
315
+ export SKILLREPO_ACCESS_KEY=sk_live_...
316
+ ```
317
+
318
+ ## Troubleshooting
195
319
 
196
- This is expected. VS Code does not support environment variable expansion in
197
- MCP config files, so it uses an input prompt instead. The key is cached for the
198
- duration of your VS Code session. Enter the same key from your `.env.local`
199
- file.
320
+ **"No access key configured"** Run `skillrepo init`, or pass `--key`,
321
+ or set `SKILLREPO_ACCESS_KEY`.
200
322
 
201
- ### Skill mappings are stale
323
+ **"Invalid access key format"** — Keys must start with `sk_live_`.
324
+ The CLI trims leading and trailing whitespace from keys in every
325
+ path — both the interactive prompt in `init` and the Bearer header
326
+ used by every subsequent command — so pasting from email or a
327
+ browser with a trailing newline is safe.
202
328
 
203
- For Claude Code, the SessionStart hook refreshes mappings automatically. For
204
- Cursor and VS Code + Copilot, re-run `npx skillrepo init` or ask your agent to
205
- run `update skills from skillrepo` to regenerate the mapping file.
329
+ **"No IDEs detected in this directory"** The CLI detected no
330
+ `.claude/`, `.cursor/`, `.vscode/`, or `~/.codeium/windsurf/` markers.
331
+ Either run from inside a project with one of those folders, pass
332
+ `--ide <vendor>` to target a specific IDE, or copy the printed MCP
333
+ config manually.
206
334
 
207
- ## Requirements
335
+ **"Rate limit exceeded — retried automatically and still getting
336
+ 429"** — The CLI already retried with backoff. Wait a minute and
337
+ retry. Pass `--verbose` to see the per-attempt timings.
208
338
 
209
- - Node.js 18 or later
210
- - Zero runtime dependencies (uses built-in `fetch` and `fs`)
339
+ **Windows:** skill updates use a best-effort atomic rename pattern.
340
+ A crash mid-update may leave a partial state; the next `update` run
341
+ fully overwrites it.
211
342
 
212
343
  ## License
213
344
 
214
- AGPL-3.0
345
+ MIT — see [LICENSE](./LICENSE).