skilllib 1.0.0 → 1.0.2

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.
package/README.md CHANGED
@@ -1,266 +1,340 @@
1
- # skilllib
1
+ <div align="center">
2
2
 
3
- One library of agent skills, and each project gets only the skills it needs. It works with **Claude Code, Cursor, and Codex**. `skilllib` is a system-wide command: run it from any folder to open a full-screen, keyboard-driven app. Everything is local: there's no server, account, or database.
3
+ # ◆ skilllib
4
4
 
5
- **Library vs. Global**
5
+ **Manage your agent skills like dependencies.**<br>
6
+ One library for all your skills. Each repo gets only the ones it needs,<br>
7
+ and every agent you use can see them.
6
8
 
7
- - **Library** (`~/.skilllib/library`) is your shelf of skills. Nothing in it loads anywhere until you add it to a project. Every change becomes a new version.
8
- - **Global** is what your agents load in *every* project: `~/.claude/skills`, `~/.agents/skills`, plugins, claude.ai-synced skills, and Cursor's built-ins. Move yours into the library, then add them only where they're needed.
9
-
10
- ## Install
9
+ [![npm](https://img.shields.io/npm/v/skilllib?color=8b9dff&label=npm)](https://www.npmjs.com/package/skilllib)
10
+ [![license](https://img.shields.io/badge/license-MIT-6bcb77)](LICENSE)
11
+ ![node](https://img.shields.io/badge/node-%E2%89%A522-5eb8f7)
12
+ ![agents](https://img.shields.io/badge/works%20with-Claude%20Code%20%C2%B7%20Cursor%20%C2%B7%20Codex%20%C2%B7%20Zed-c792ea)
11
13
 
12
14
  ```bash
13
- npm install -g skilllib
14
- skilllib
15
+ npx skilllib
15
16
  ```
16
17
 
17
- Or try it without installing: `npx skilllib`.
18
+ <img src="docs/screenshot-project.svg" alt="skilllib showing a repo's skills: where each comes from, which agents load it, whether it's committed, and how often it's used" width="100%">
18
19
 
19
- It needs **Node.js 22 or newer** and runs on macOS and Linux. Windows support is newer: links are made as directory junctions, so no admin rights are needed, and CI runs the tests there. Everything stays on your machine; skilllib makes no network calls.
20
+ </div>
20
21
 
21
- ## First run
22
+ ---
22
23
 
23
- Run `skilllib`. It asks two things:
24
+ ## The problem
24
25
 
25
- 1. **Which agents you use.** Claude Code, Cursor, and Codex; installed ones are pre-selected.
26
- 2. **Where your projects live**, for example `~/Projects`. It finds every git repo there and rescans on each launch.
26
+ [Agent skills](https://code.claude.com/docs/en/skills) (folders with a `SKILL.md`) are one of the best ways to teach Claude Code, Cursor, Codex and Zed how *you* work. But they pile up quickly:
27
27
 
28
- You can change both later in **Settings**, or with `skilllib harnesses` and `skilllib folders`.
28
+ - **`npx skills add`** drops skills into `~/.agents/skills`.
29
+ - **Plugins** bring their own.
30
+ - **claude.ai** syncs a few more.
31
+ - **Your teammates** commit some to the repo.
32
+ - **You** copy folders into `~/.claude/skills` "just for now".
29
33
 
30
- ## Where skills come from
34
+ A few weeks later:
31
35
 
32
- A skill is a folder with a `SKILL.md`. Agents load skills from:
36
+ - **🌍 Global skills load everywhere.** Everything in `~/.claude/skills` or `~/.agents/skills` loads in **every repo, in every session**. Your agent reads the name and description of your Stripe skill while fixing Terraform in your infra repo. That costs context, and skills fire when they shouldn't.
37
+ - **👯 Duplicates.** The same skill arrives through `npx skills` *and* a plugin *and* a copy in the repo, and your agent sees it twice.
38
+ - **🙈 Each agent looks somewhere else.** Claude Code reads `.claude/skills`; Codex and Zed read `.agents/skills`; Cursor reads both. The skills your team committed to `.agents/skills` are invisible to Claude Code.
39
+ - **🧟 Copies drift.** You improved a skill in one repo; the other five still have the old version.
40
+ - **🤷 No overview.** Which skills does this repo actually have? Where did each one come from? Is it committed, or only on my laptop? Does anyone use it?
33
41
 
34
- - **The repo:** `.claude/skills` (Claude Code and Cursor), `.agents/skills` (the shared folder for Codex, Cursor, Zed and others), `.cursor/skills`, and `.codex/skills`. Only agents working in that repo see these.
35
- - **Global folders:** `~/.claude/skills`, `~/.agents/skills` (`npx skills add` installs here), and `~/.cursor/skills`. These load in every repo.
36
- - **Vendors:** Claude Code plugins (`/plugin`), claude.ai skills synced from your account, Claude Code's bundled commands, Cursor's built-in and marketplace skills, and Codex system skills.
37
- - **Your skills** (`~/.skilllib/library`): skilllib's master copies. Nothing there loads until you add it to a project.
42
+ Most agents can't turn off a global skill for just one repo. Claude Code can, but Cursor and Codex can't. **The only real fix is to stop using global skills and give each repo what it needs.**
38
43
 
39
- The same content is in the app: press `?`, or open **Help** in the left pane.
44
+ ## How skilllib fixes it
40
45
 
41
- ### ✻ Claude Code ([docs](https://code.claude.com/docs/en/skills))
46
+ - **📚 Your skills: one versioned library.** Every skill has a single master copy in `~/.skilllib/library`, and each change becomes a new version.
47
+ - **📦 Per-repo installs, pinned like dependencies.** Each repo lists its skills and versions in `skilllib.json`. `sync` reproduces them exactly, and `update` moves to the newest.
48
+ - **🤝 One copy, every agent.** skilllib puts one real copy in the repo and links it into whichever folders your other agents read.
49
+ - **🧹 A cleanup wizard for global skills.** For each global skill, pick the repos that should keep it, keep it global, or delete it. Usage numbers and descriptions help you decide.
50
+ - **🔎 See everything in a repo:**
51
+ - where each skill comes from (the repo, your library, global, a plugin, claude.ai…)
52
+ - which agents load it
53
+ - whether it's committed to git or gitignored
54
+ - how often it was used
55
+ - **✦ Ask an agent.** Copy a ready-made prompt with all of that data, and let Claude Code, Cursor or Codex tell you what to keep, move or delete.
56
+ - **🛟 Nothing is lost.** Every removal goes to a backup you can restore with one key.
42
57
 
43
- - **Where it looks.** When names collide, the first one listed wins: enterprise (managed settings) → `~/.claude/skills` → `.claude/skills` → nested `<subfolder>/.claude/skills` → plugins (namespaced as `/plugin:skill`) → bundled. It also loads claude.ai skills from `~/.claude/skills/synced` and folders added with `--add-dir`. It **does not** read `.agents/skills` (I tested this).
44
- - **How it uses them.** Descriptions are always in context; the full `SKILL.md` loads on `/name` or when Claude decides it's relevant.
45
- - `disable-model-invocation: true`: only you can run it.
46
- - `user-invocable: false`: only Claude can run it.
47
- - **Per-repo control.** `skillOverrides` in `.claude/settings.json`, with values `"off"`, `"name-only"` or `"user-invocable-only"`. This only affects Claude.
58
+ Everything runs locally: no server, no account, no network calls.
48
59
 
49
- ### ⬡ Cursor ([docs](https://cursor.com/docs/context/skills))
60
+ ---
50
61
 
51
- - **Where it looks.**
52
- - In the project: `.agents/skills` and `.cursor/skills`, including nested ones, which only apply to files inside them.
53
- - In your home folder: `~/.agents/skills` and `~/.cursor/skills`.
54
- - For compatibility: `.claude/skills`, `.codex/skills`, `~/.claude/skills` and `~/.codex/skills`.
55
- - It also loads marketplace plugins and its own built-ins. Cloud Agents only see `~/.cursor/skills`.
56
- - **How it uses them.** Descriptions decide relevance, and the full content loads on use; `/` runs one. A `paths:` glob in the frontmatter limits a skill to matching files. `disable-model-invocation: true` makes it manual.
57
- - **Limits.** There's no per-project switch for global skills. The docs don't say what happens when two folders hold the same skill.
62
+ ## Quick start
58
63
 
59
- ### ◎ Codex ([docs](https://learn.chatgpt.com/docs/build-skills))
64
+ ```bash
65
+ npm install -g skilllib # or: npx skilllib
66
+ skilllib
67
+ ```
60
68
 
61
- - **Where it looks.** `.agents/skills` in the working folder, its parents, and the repo root; then `~/.agents/skills`; `/etc/codex/skills` (admin); and OpenAI's bundled skills. It **does not** read `.claude/skills`.
62
- - **How it uses them.** Names and descriptions come first (capped at about 2% of context); `SKILL.md` loads when used. Type `$` to pick one.
63
- - Skills with the same name aren't merged; both can appear.
64
- - To keep a skill manual, set `policy.allow_implicit_invocation: false` in `agents/openai.yaml`.
65
- - To disable a skill everywhere, add `[[skills.config]] … enabled = false` to `~/.codex/config.toml`.
69
+ It needs **Node.js 22+** and works on macOS and Linux. Windows support is newer: it uses directory junctions, so no admin rights are needed.
66
70
 
67
- ### ℤ Zed ([docs](https://zed.dev/docs/ai/skills))
71
+ On first run, skilllib asks two things:
68
72
 
69
- - **Where it looks.** `<worktree>/.agents/skills` (only in trusted worktrees) and `~/.agents/skills`. Only direct child folders count; nested skills aren't picked up. If both define the same name, the project's skill wins.
70
- - **How it uses them.** The agent sees a catalog of names and descriptions; `/` or `@skill` runs one. Changes apply without a restart.
73
+ 1. **Which agents you use:** Claude Code, Cursor, Codex, Zed. The ones installed on your machine are pre-selected.
74
+ 2. **Where your projects live**, e.g. `~/Projects`. It finds every git repo in there, and rescans each time it opens.
71
75
 
72
- skilllib keeps one real copy of each skill and adds links so every agent you use can see it:
76
+ Then a good first session looks like this:
73
77
 
74
- - **Claude Code and/or Cursor:** the copy goes in `.claude/skills`, which both of them read.
75
- - **Codex too:** skilllib also adds a link in `.agents/skills`. If git tracks that folder (many repos commit their team skills there), skilllib asks first and remembers your answer for that project.
78
+ 1. **Open a repo** (type its name, then Enter) to see everything its agents can use.
79
+ 2. **Clean up global skills:** open **Global → ⚠ Clean up…** and decide, skill by skill, which repos keep it.
80
+ 3. **Add skills** to a repo from the *Add skills* tab.
76
81
 
77
- Every skill row shows which agents load it (`CC Cu Cx`: green means loaded, dim means not). **Make visible to…** adds any missing links. Switching agents never moves existing installs; the change only affects new ones.
82
+ ---
78
83
 
79
- Cursor doesn't document how it handles the same skill reached through two folders. When that happens, the row shows it in yellow.
84
+ ## Manual
80
85
 
81
- ## How it works
86
+ ### The screen
82
87
 
83
- The left pane lists **places**: Library, Global, Health, your projects, and Settings. The right pane shows the skills in whichever place you pick. Usage over the last 30 days, read from Claude Code transcripts, appears as a column everywhere. For now it only counts Claude Code: Cursor keeps no transcripts on disk here, and Codex isn't installed on this machine to test against.
88
+ The left pane lists **places**, and the right pane shows the skills of the place you pick:
84
89
 
85
- - **Type to search** in the pane you're in. Fuzzy matching works too: `cfw` finds `cloudflare-workers`.
86
- - **Enter** opens a place (left pane) or shows every action for a skill (right pane).
87
- - **Space** does the obvious thing: add, remove, import, fix, or restore.
88
- - **Esc** clears the search, then returns to the left pane.
89
- - **Tab** (inside a project) switches between Usable here and Add skills.
90
- - **Ctrl+C** quits; **?** shows help.
90
+ | Place | What it shows |
91
+ |---|---|
92
+ | **Your skills** | Your library: master copies, versioned. Nothing here loads anywhere until you add it to a repo. |
93
+ | **Global** | Everything your agents load in *every* repo: yours, plus vendor skills (plugins, claude.ai, Cursor built-ins). |
94
+ | **Health** | Problems with one-key fixes, and everything you can restore. |
95
+ | **Projects** | Every repo found in your project folders. `◆` marks the one you're in. |
96
+ | **Settings** | Your agents and your project folders. |
97
+ | **Help** | Where skills come from, and how each agent finds and uses them. |
91
98
 
92
- ### A project
99
+ ### Keys
93
100
 
94
- A project has two lists. Press `tab` to switch between them:
101
+ | Key | Does |
102
+ |---|---|
103
+ | *type* | Search the pane you're in. Word initials work too: `cfw` finds `cloudflare-workers`. |
104
+ | `↑` `↓` | Move |
105
+ | `space` | The main action: add, remove, copy, clean up, fix, restore |
106
+ | `enter` | Every action for the selected row (or open a place) |
107
+ | `tab` | In a repo: switch between **Usable here** and **Add skills** |
108
+ | `→` `←` | Open or close a group |
109
+ | `esc` | Clear the search, then go back to the left pane |
110
+ | `?` | Help · `ctrl+r` reload · `ctrl+c` quit |
95
111
 
96
- - **Usable here:** everything agents see in this repo, grouped by where it comes from:
97
- - *From your skills*: versioned skills you added. Space removes one.
98
- - *The repo's own*: skills committed to the repo. Space copies one to **Your skills** so other repos can use it; the repo keeps its copy.
99
- - *⚠ Global · yours* ("loaded globally"): skills in `~/.claude/skills` or `~/.agents/skills` that load in every repo, so every agent reads them all the time. Space opens the cleanup wizard.
100
- - *Global · from vendors*, which only their vendor can remove:
101
- - **Claude Code plugins** you enabled (`/plugin`); only Claude loads these
102
- - **claude.ai skills** synced from your account; Claude only
103
- - **Cursor built-ins** that ship with Cursor; Cursor only
112
+ ### A repo
104
113
 
105
- Each skill in the repo also shows its **git state**:
106
- - **✓ committed**: in git, so teammates get it
107
- - **± changed**: committed, with uncommitted edits
108
- - **+ not added**: not committed yet
109
- - **∅ ignored**: matched by `.gitignore`, so it only exists on your machine. Many repos ignore `.claude/skills`.
114
+ A repo has two lists:
110
115
 
111
- **⧉ N copies** means the same skill reaches agents from more than one place. For example, `ponytail` installed with `npx skills` *and* enabled as the `ponytail` plugin *and* added to the repo. The details panel lists every copy, so you can keep just one.
112
- - **Add skills:** your skills that this repo doesn't have yet. Space adds one.
116
+ **Usable here** shows everything agents can use in this repo, grouped by where it comes from:
113
117
 
114
- **Your skills** (`~/.skilllib/library`) keeps one master copy of each skill. That's what "Add skills" shows, what projects update from, and what gets restored when something is missing.
118
+ | Group | What it is | `space` |
119
+ |---|---|---|
120
+ | *From your skills* | Versioned skills you added from your library | Remove it from this repo |
121
+ | *The repo's own* | Skills committed to the repo (e.g. your team's `.agents/skills`) | Copy it into your skills, so other repos can use it |
122
+ | *⚠ Global · yours* | Your global skills: they load in every repo | Open the cleanup wizard |
123
+ | *Global · from vendors* | Plugins, claude.ai skills, Cursor built-ins | – (manage them at the source) |
115
124
 
116
- ### Cleaning up global skills
125
+ **Add skills** shows your skills that this repo doesn't have yet. `space` adds one.
117
126
 
118
- Global skills can't be switched off for a single repo in Cursor or Codex. Claude Code has a per-project setting for it, but it only covers Claude. So instead of blocking them per repo, the **cleanup wizard** turns global skills into per-project ones:
127
+ Each row tells you:
119
128
 
120
- 1. For each global skill, choose what happens to it; Space cycles through the options:
121
- - **◉ move:** it goes into the projects you tick on the right. Projects that already have it, or where Claude Code used it, are pre-ticked.
122
- - **○ keep global**
123
- - **✕ delete** (`d` works too)
129
+ | | Meaning |
130
+ |---|---|
131
+ | **✻ ⬡ ◎ ℤ** | Claude Code, Cursor, Codex, Zed. An icon in color means that agent loads the skill here; a faint one means it doesn't. |
132
+ | `²` | Cursor reaches this skill through two folders, so it may list it twice |
133
+ | `.claude` / `.agents` | The folder holding the real copy |
134
+ | **✓ committed** · **± changed** · **+ not added** · **∅ ignored** | The skill's git state. `∅ ignored` means it only exists on your machine. |
135
+ | `v2` · `v1 → v2` | The installed version, and whether a newer one exists |
136
+ | **⧉ 3 copies** | The same skill reaches your agents from 3 places. The details panel lists them; keep one. |
137
+ | last column | Claude Code uses in the last 30 days |
124
138
 
125
- Each skill shows how often Claude Code used it in the last 30 days, and the panel below shows its description and which projects used it.
126
- 2. Review, then apply. Moved skills are copied into Your skills and installed where you ticked. Deleted ones are **not** kept in Your skills. Either way the original stops loading globally and goes to a backup you can restore from Health.
139
+ Related skills fold into one row: skills from the same plugin, the same source repo, or with the same name prefix (`design-*`). Press Enter on the group row for actions on all of them.
127
140
 
128
- ### Ask an agent to review your skills
141
+ If some skills aren't visible to every agent you use, the top row offers **⇄ Make all N skills usable by …**. It adds links only; nothing is copied or moved.
129
142
 
130
- **Copy review prompt** puts a ready-to-paste prompt on your clipboard (it's also saved to `~/.skilllib/review-prompt.md`). Paste it into Claude Code, Cursor or Codex and the agent recommends **keep global / move to projects / delete / turn off at the vendor** for each skill, as a table plus JSON. For each skill the prompt includes:
143
+ ### Adding and removing skills
131
144
 
132
- - its description and an excerpt of the SKILL.md body
133
- - how it was installed: vendor, plugin, skills.sh repo, claude.ai sync, or copied in
134
- - its path and links
135
- - which agents load it
136
- - Claude Code usage per project
137
- - which projects have it
138
- - other copies
139
- - whether it's in Your skills
145
+ - **Adding** (`space` in *Add skills*) copies the newest version into `.claude/skills/<name>`, which Claude Code and Cursor read. If you use Codex or Zed, it also links it into `.agents/skills`. The skill is recorded in `skilllib.json`. Agents pick it up in their next session.
146
+ - **Removing** (`space` again) deletes that copy and its links. Your library and other repos aren't touched. If you edited it here, skilllib asks first; Enter → *Save local edits to Your skills* keeps them.
147
+ - **The repo's own skills are never deleted by skilllib.** You can copy them into your library, or link them so every agent sees them.
148
+ - **Git-tracked folders:** if the repo commits the folder a link would go into (common for `.agents/skills`), skilllib asks once and remembers your answer.
140
149
 
141
- It also lists your project paths, so the agent can check each project's stack.
150
+ ### Versions
142
151
 
143
- Where to find it:
144
- - **Global** → **✦ Ask an agent to review all global skills** (Enter lets you pick only your own)
145
- - Enter on any skill or group → **Copy review prompt**
146
- - `p` inside the cleanup wizard; then set move / keep / delete per skill based on the answer
152
+ Every change to a library skill becomes a new version, kept in `~/.skilllib/store`. Repos pin the version they use:
147
153
 
148
- To delete a single global skill without the wizard, use Enter → **Delete** in Global, or in a project's global section. **Delete all N** works on a whole group.
154
+ ```json
155
+ { "skills": { "stripe-payments": { "version": 2, "hash": "318bf4b94df4911c" } } }
156
+ ```
149
157
 
150
- If a project can't take its copy (for example, the repo has a different skill with the same name), that skill stays global, so nothing loses it.
158
+ | | Like | What it does |
159
+ |---|---|---|
160
+ | `skilllib sync` | `npm ci` | Installs exactly the pinned versions and restores missing ones. It never touches your edits. |
161
+ | `skilllib outdated` | `npm outdated` | Lists skills with a newer version |
162
+ | `skilllib update [name]` | `npm update` | Moves to the newest version |
163
+ | Enter → *Install a specific version…* | `npm i x@1` | Pins any version, including older ones |
151
164
 
152
- Related skills collapse into one row: skills from the same plugin (*ponytail plugin · 6 skills*), the same account or source (*claude.ai skills*, *Cursor built-in*, a skills.sh repo), or the same name prefix (`design-*`, `code-qa-*`). Space or `→` opens a group, `←` closes it, and Enter shows actions for the whole group, such as *Copy all into your library* or *Add all to this repo*. While you search, groups open up so every match is visible.
165
+ Edit a skill once in **Your skills** (Enter → *Edit SKILL.md*). Every repo that uses it then shows `v1 → v2` and can update.
153
166
 
154
- A line under the tabs says what the current list means. Search looks in the current tab, and tells you if the other tabs have matches.
167
+ ### Cleaning up global skills
155
168
 
156
- If some skills in the repo aren't visible to every agent you use, the top of *Usable here* shows **⇄ Make all N skills usable by…**, which adds the missing links.
169
+ <img src="docs/screenshot-cleanup.svg" alt="The cleanup wizard: each global skill with its Claude Code usage, where it moves, and the projects that keep it" width="100%">
157
170
 
158
- Each row shows which agents load it: **✻** Claude Code, **⬡** Cursor, **◎** Codex, **ℤ** Zed. An icon in brand color means that agent loads the skill; faint means it doesn't. `²` means Cursor reaches it through two folders.
171
+ Open **Global → ⚠ Clean up…**, or press `space` on any of your global skills. For each skill, `space` cycles through:
159
172
 
160
- ### Adding and removing a skill
173
+ - **◉ move:** installed into the repos you tick on the right. Repos that already have it, or where Claude Code used it, are pre-ticked.
174
+ - **○ keep global**
175
+ - **✕ delete** (`d`): removed without keeping a copy in your library
161
176
 
162
- - **Space on an installable skill** copies its newest library version from `~/.skilllib/store` into `.claude/skills/<name>`. With Codex on, it also links it into `.agents/skills`. It records `{version, hash, links}` in `skilllib.json`. Agents pick it up in their next session.
163
- - **Space on it again** deletes that project copy and its links, and drops the entry from `skilllib.json`. Your library copy and other projects aren't touched. If you edited the project copy, you're asked first; Enter → *Save local edits to the library* keeps them.
164
- - **Adding it back** installs the newest version again.
165
- - Skills skilllib didn't install (a repo's own skills) are never deleted by Space; it offers to copy them into your library instead.
177
+ Each skill shows how often Claude Code used it, and the panel below shows its description and where it was used. Review, apply, and your globals are gone: moved ones are in your library and in the right repos. Originals go to a backup you can restore from **Health**.
166
178
 
167
- ### Repo skills in `.agents/skills`
179
+ You can also delete one skill (Enter → **Delete**) or a whole group (Enter → **Delete all N**) straight from Global.
168
180
 
169
- Many repos commit their own skills to `.agents/skills`, the cross-agent folder that Codex, Cursor, Amp, and `npx skills` read. skilllib reads that folder as well as `.claude/skills`. Each skill shows which folder it lives in:
181
+ ### Ask an agent to review your skills
170
182
 
171
- - `◉` means Claude Code can see the skill: it's in `.claude/skills`, or linked there.
172
- - `◌` means only other agents can see it.
183
+ Not sure what to keep? **Copy review prompt** puts a ready-to-paste prompt on your clipboard (also saved to `~/.skilllib/review-prompt.md`). For each skill, it includes:
173
184
 
174
- The repo owns these skills, so skilllib never moves them or adds them to `skilllib.json`:
185
+ - its description and SKILL.md
186
+ - how it was installed (plugin, `npx skills`, claude.ai, copied in…)
187
+ - which agents load it
188
+ - usage per repo
189
+ - duplicates
190
+ - your project list, so the agent can check each repo's stack
175
191
 
176
- - **Space** copies one into your library, so you can reuse it in other projects.
177
- - **Enter → Link for Claude Code** adds a relative symlink in `.claude/skills` pointing at the repo copy. This is the same thing `npx skills` does, and `.claude/skills` is often gitignored. **Unlink** removes only the link.
192
+ Paste it into Claude Code, Cursor or Codex. You get back **keep global / move to projects / delete / turn off at the vendor** for each skill, as a table plus JSON.
178
193
 
179
- Skills that skilllib installs from the library always go in `.claude/skills`.
194
+ It's available from:
195
+ - **Global → ✦ Ask an agent to review all global skills**
196
+ - Enter on any skill or group → **Copy review prompt**
197
+ - `p` inside the cleanup wizard
180
198
 
181
- ### Versions: skills as dependencies
199
+ ### Health and backups
182
200
 
183
- Every change to a library skill becomes a new version (v1, v2, …), stored immutably in `~/.skilllib/store`. A project's `skilllib.json` pins the version it uses:
201
+ **Health** lists broken links, skills loaded twice, out-of-date repos and repo-only skills, each with a one-key fix. Below them is everything skilllib ever moved out, and `space` puts it back where it came from.
184
202
 
185
- ```json
186
- { "skills": { "alpha": { "version": 2, "hash": "318bf4b94df4911c" } } }
187
- ```
203
+ skilllib never really deletes anything:
204
+ - removed library skills go to `~/.skilllib/trash`
205
+ - removed global skills go to `~/.skilllib/global-backup`
206
+
207
+ ---
208
+
209
+ ## Where skills come from
210
+
211
+ A skill is a folder with a `SKILL.md`. These are all the places your agents load them from:
188
212
 
189
- | Command | Like | What it does |
213
+ | Where | Examples | Who sees it |
190
214
  |---|---|---|
191
- | `skilllib sync` | `npm ci` | Installs exactly the pinned versions. It restores missing skills and never touches your edits. |
192
- | `skilllib outdated` | `npm outdated` | Lists skills with a newer library version |
193
- | `skilllib update [name]` | `npm update` | Moves to the newest version |
194
- | Enter → *Install a specific version…* | `npm i x@1` | Pins any version, including older ones |
215
+ | **The repo** | `.claude/skills`, `.agents/skills`, `.cursor/skills`, `.codex/skills` | Agents working in that repo |
216
+ | **Global folders** | `~/.claude/skills`, `~/.agents/skills` (`npx skills add` installs here), `~/.cursor/skills` | **Every repo** |
217
+ | **Vendors** | Claude Code plugins (`/plugin`), claude.ai skills, Claude Code's bundled commands, Cursor built-ins and marketplace, Codex system skills | Every repo; only the vendor can remove them |
218
+ | **Your skills** | `~/.skilllib/library` | Nobody, until you add a skill to a repo |
219
+
220
+ ### ✻ Claude Code · [docs](https://code.claude.com/docs/en/skills)
221
+
222
+ - **Where it looks.** When names collide, the first one listed wins:
223
+ 1. enterprise (managed settings)
224
+ 2. `~/.claude/skills`
225
+ 3. `.claude/skills`
226
+ 4. nested `<subfolder>/.claude/skills`
227
+ 5. plugins (as `/plugin:skill`)
228
+ 6. bundled
229
+
230
+ It also reads claude.ai skills from `~/.claude/skills/synced` and folders passed with `--add-dir`. It **doesn't read `.agents/skills`** (verified).
231
+ - **How it uses them.** Descriptions are always in context; the full `SKILL.md` loads on `/name` or when Claude decides it's relevant.
232
+ - `disable-model-invocation: true`: only you can run it.
233
+ - `user-invocable: false`: only Claude can.
234
+ - **Per-repo control.** `skillOverrides` in `.claude/settings.json` (`"off"`, `"name-only"`, `"user-invocable-only"`). It's Claude-only, so skilllib moves skills out of global instead of blocking them.
235
+
236
+ ### ⬡ Cursor · [docs](https://cursor.com/docs/context/skills)
237
+
238
+ - **Where it looks.**
239
+ - Project: `.agents/skills` and `.cursor/skills`, including nested ones, which apply only to files inside them.
240
+ - Your home folder: `~/.agents/skills` and `~/.cursor/skills`.
241
+ - For compatibility: `.claude/skills`, `.codex/skills`, `~/.claude/skills` and `~/.codex/skills`.
242
+ - Also marketplace plugins and Cursor's built-ins. Cloud Agents only see `~/.cursor/skills`.
243
+ - **How it uses them.** Descriptions decide relevance, and the full content loads on use; `/` runs one. `paths:` globs limit a skill to matching files, and `disable-model-invocation: true` makes it manual.
244
+ - **Limits.** There's no per-project switch for global skills. Its docs don't say how it handles one skill reached through two folders.
195
245
 
196
- ### Global and Health
246
+ ### ◎ Codex · [docs](https://learn.chatgpt.com/docs/build-skills)
197
247
 
198
- - **Global:** everything Claude Code loads in *every* project. Your skills (`~/.claude/skills`, and skills.sh links) are listed separately from vendor skills (claude.ai, plugins). Space imports one of yours into the library, or stops it loading globally once it's there. Enter shows *import all* and *stop loading all*.
199
- - **Health:** broken links, skills loaded twice, out-of-date projects, and repo-only skills, each with a one-key fix. Below them is everything skilllib moved out, which Space restores.
248
+ - **Where it looks.** `.agents/skills` in the working folder, its parents and the repo root; then `~/.agents/skills`; `/etc/codex/skills` (admin); and OpenAI's bundled skills. It **doesn't read `.claude/skills`**.
249
+ - **How it uses them.** Names and descriptions come first (about 2% of context); `SKILL.md` loads when used, and `$` picks one.
250
+ - Same-name skills aren't merged.
251
+ - `policy.allow_implicit_invocation: false` in `agents/openai.yaml` keeps a skill manual.
252
+ - `[[skills.config]] … enabled = false` in `~/.codex/config.toml` disables one everywhere.
200
253
 
201
- Nothing is ever deleted. Deleted skills go to `~/.skilllib/trash`, and unloaded global skills go to `~/.skilllib/global-backup`. Both can be restored from Health.
254
+ ### ℤ Zed · [docs](https://zed.dev/docs/ai/skills)
202
255
 
203
- ## Known limits
256
+ - **Where it looks.** `<worktree>/.agents/skills` (trusted worktrees only) and `~/.agents/skills`. Only direct child folders count, and on a name collision the project's skill wins.
257
+ - **How it uses them.** The agent sees a catalog of names and descriptions; `/` or `@skill` runs one. Changes apply without a restart.
204
258
 
205
- - **Cursor plugin skills aren't listed.** Cursor caches marketplace plugins in `~/.cursor/plugins/cache`, but it doesn't record which ones are enabled in any file skilllib can read. Listing them would guess.
206
- - **Usage only counts Claude Code.**
207
- - **Unloading a skills.sh skill doesn't update its lock file.** If you stop loading a skill from `~/.agents/skills`, the `npx skills` lock file still lists it as installed.
259
+ ---
208
260
 
209
- ## Commands
261
+ ## Command line
210
262
 
211
- Everything the app does is also available as a command, for scripts:
263
+ Everything the app does also works as a command, for scripts and CI:
212
264
 
213
265
  ```
266
+ skilllib open the app (prints `status` when piped)
214
267
  skilllib scan [folder...] add project folders and scan them
215
268
  skilllib folders [add|remove] show or change project folders
216
- skilllib import <dir>... add skill folders to the library (--global: ~/.claude/skills)
217
- skilllib status this project's skills
218
- skilllib add|remove <name>... change this project's skills
269
+ skilllib harnesses [id...] show or set your agents (claude-code cursor codex zed)
270
+
271
+ skilllib status this repo's skills
272
+ skilllib add | remove <name> change this repo's skills
219
273
  skilllib sync [--all] install exactly the pinned versions
220
- skilllib outdated [--all] skills with newer versions
221
- skilllib update [name...] move to the newest versions (--all: every project)
222
- skilllib list | show <name> the library
274
+ skilllib outdated [--all] skills with a newer version
275
+ skilllib update [name...] move to the newest versions
276
+ skilllib link [--all] make every skill here usable by all your agents
277
+
278
+ skilllib list | show <name> your library
279
+ skilllib import <dir>... add skill folders to your library (--global: all your global skills)
223
280
  skilllib new <name> [desc] create a skill
224
- skilllib projects every project and its skills
225
- skilllib usage [--days N] what agents used
226
- skilllib doctor [--fix] problems, and fix them all
227
- skilllib restore [name] put back something that was moved out
228
- skilllib unhide <path> show a hidden project again
281
+
282
+ skilllib usage [--days N] which skills Claude Code used
283
+ skilllib doctor [--fix] find (and fix) problems
284
+ skilllib restore [name] put back something skilllib moved out
285
+ skilllib --version
229
286
  ```
230
287
 
231
- When output is piped, `skilllib` prints `skilllib status` instead of opening the app.
288
+ Flags: `--force` (overwrite local edits), `--allow-tracked` (link into git-tracked folders), `--days N`.
232
289
 
233
290
  ## Files
234
291
 
235
292
  | Path | What |
236
293
  |---|---|
237
- | `~/.skilllib/library/<skill>/` | Your library. Consider putting it under git. |
238
- | `~/.skilllib/config.json` | Project folders and hidden projects |
239
- | `~/.skilllib/projects.json` | Projects found so far |
240
- | `~/.skilllib/origins.json` | Where each library skill was imported from |
241
- | `~/.skilllib/store/<skill>/<n>/` | Immutable copy of every version |
242
- | `<project>/skilllib.json` | The project's skill dependencies and their pinned versions. Commit it with `.claude/skills/`. |
294
+ | `<repo>/skilllib.json` | The repo's skills and pinned versions. **Commit it.** |
295
+ | `~/.skilllib/library/` | Your skills (master copies). Worth putting under git. |
296
+ | `~/.skilllib/store/` | Every version of every skill, immutable |
297
+ | `~/.skilllib/config.json` | Your agents, project folders, hidden projects |
298
+ | `~/.skilllib/trash/`, `global-backup/` | Everything skilllib removed, restorable from Health |
299
+ | `~/.skilllib/review-prompt.md` | The last review prompt you copied |
300
+
301
+ Environment variables: `SKILLLIB_HOME` moves `~/.skilllib`, `$VISUAL` / `$EDITOR` set the editor, and `CLAUDE_CONFIG_DIR` is honored.
243
302
 
244
- Set `SKILLLIB_HOME` to move `~/.skilllib`. `$VISUAL`/`$EDITOR` is used for editing. `CLAUDE_CONFIG_DIR` is honored.
303
+ ## FAQ
304
+
305
+ **Does it change my repos?** Only when you tell it to: adding, removing or linking a skill, which updates `skilllib.json`. It asks before writing into a folder git tracks, and it never deletes a repo's own skills.
306
+
307
+ **Can I share skills with my team?** Commit `skilllib.json` along with the copies in `.claude/skills`. Or keep your library in a git repo and point `SKILLLIB_HOME` at it.
308
+
309
+ **Why does usage only count Claude Code?** It's the only agent here with local transcripts to read. Cursor doesn't keep them locally, and Codex's format hasn't been tested yet. That's why "unused" is a strong hint, not proof.
310
+
311
+ **What's not supported yet?**
312
+ - Cursor marketplace plugin skills: Cursor doesn't record which ones are enabled in a file skilllib can read.
313
+ - Unloading a `npx skills` skill doesn't update that tool's lock file.
314
+ - Installing new skills straight from GitHub is coming. For now, `skilllib import <folder>` or copy one from a repo.
315
+
316
+ ---
245
317
 
246
318
  ## Development
247
319
 
248
320
  ```bash
249
321
  pnpm install
250
- pnpm test && pnpm type-check && pnpm build # tests use bun
322
+ pnpm test && pnpm type-check && pnpm build # tests run on bun
251
323
  pnpm dev # run from source
252
- npm link # use your checkout as the global `skilllib`
324
+ npm link # use your checkout as `skilllib`
253
325
  ```
254
326
 
255
- ### Releasing
256
-
327
+ **Releasing:**
257
328
  1. Bump `version` in `package.json` and merge to `main`.
258
- 2. Tag it: `git tag v1.0.1 && git push --tags`.
329
+ 2. Tag and push:
330
+ ```bash
331
+ git tag v1.0.2 && git push --tags
332
+ ```
259
333
 
260
- The **Release** workflow checks that the tag matches `package.json`, runs the tests, publishes to npm with provenance, and creates a GitHub release. It needs an `NPM_TOKEN` secret in the repo, an npm automation token with publish rights.
334
+ CI then tests on Linux, macOS and Windows, publishes to npm through [trusted publishing](https://docs.npmjs.com/trusted-publishers) (no token; provenance is automatic), and creates a GitHub release.
261
335
 
262
- The earlier registry-server version (Next.js, Postgres, S3) is on the `archive/registry-server` branch.
336
+ The earlier registry-server version (Next.js, Postgres, S3) lives on the `archive/registry-server` branch.
263
337
 
264
338
  ## License
265
339
 
266
- MIT
340
+ [MIT](LICENSE) © Toni Tralice
@@ -422,7 +422,7 @@ function globalFolderSkills(enabled) {
422
422
  linksTo.set(target.path, [...linksTo.get(target.path) ?? [], e]);
423
423
  continue;
424
424
  }
425
- const target_ = e.isLink ? readlinkSync(e.path) : "";
425
+ const target_ = e.isLink ? readlinkSync(e.path).replace(/\\/g, "/") : "";
426
426
  const inAgents = e.dir === agentsDir || target_.includes(".agents/skills");
427
427
  const locked = lock[e.name]?.source;
428
428
  skills.push({
@@ -446,7 +446,8 @@ function globalFolderSkills(enabled) {
446
446
  return skills;
447
447
  }
448
448
  function tildify2(p) {
449
- return p.startsWith(userHome()) ? "~" + p.slice(userHome().length) : p;
449
+ const shown = p.startsWith(userHome()) ? "~" + p.slice(userHome().length) : p;
450
+ return shown.replace(/\\/g, "/");
450
451
  }
451
452
  function cursorBuiltInSkills(enabled) {
452
453
  if (!enabled.includes("cursor")) return [];
@@ -549,8 +550,7 @@ function librarySkills() {
549
550
  return skillDirsIn(libraryDir()).map((dir) => ({
550
551
  name: basename3(dir),
551
552
  description: readSkillInfo(dir).description,
552
- dir,
553
- hash: treeHash(dir) ?? ""
553
+ dir
554
554
  }));
555
555
  }
556
556
  function librarySkillDir(name) {
@@ -1537,7 +1537,6 @@ export {
1537
1537
  syncProject,
1538
1538
  updateProject,
1539
1539
  importSkill,
1540
- projectsUsing,
1541
1540
  deleteLibrarySkill,
1542
1541
  deleteGlobal,
1543
1542
  unloadGlobal,
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  unhide,
22
22
  update,
23
23
  usage
24
- } from "./chunk-J5ZDUXWL.js";
24
+ } from "./chunk-67BDL5SN.js";
25
25
 
26
26
  // src/index.ts
27
27
  import { readFileSync } from "fs";
@@ -73,9 +73,9 @@ async function main() {
73
73
  const args = parseArgs(rest);
74
74
  switch (command) {
75
75
  case void 0:
76
- return process.stdin.isTTY && process.stdout.isTTY ? (await import("./tui-WFN7JSVC.js")).tui() : status(args);
76
+ return process.stdin.isTTY && process.stdout.isTTY ? (await import("./tui-CQCVL6IK.js")).tui() : status(args);
77
77
  case "ui":
78
- return (await import("./tui-WFN7JSVC.js")).tui();
78
+ return (await import("./tui-CQCVL6IK.js")).tui();
79
79
  case "status":
80
80
  return status(args);
81
81
  case "add":
@@ -27,7 +27,6 @@ import {
27
27
  machineSkills,
28
28
  projectOfFactory,
29
29
  projectStatus,
30
- projectsUsing,
31
30
  readConfig,
32
31
  readSkillInfo,
33
32
  relinkDependency,
@@ -47,7 +46,7 @@ import {
47
46
  versionHistory,
48
47
  visibilityOf,
49
48
  visibleProjects
50
- } from "./chunk-J5ZDUXWL.js";
49
+ } from "./chunk-67BDL5SN.js";
51
50
 
52
51
  // src/tui/index.tsx
53
52
  import { render } from "ink";
@@ -250,7 +249,8 @@ function loadSnapshot() {
250
249
  name: s.name,
251
250
  description: s.description,
252
251
  origin: origins[s.name] ?? inferred(s.name),
253
- projects: projectsUsing(s.name).filter((p) => projects.includes(p)),
252
+ // Managed status entries are the manifest, already read above; no need to re-read every manifest per skill.
253
+ projects: projects.filter((p) => statusOf(p).some((x) => x.managed && x.name === s.name)).sort(),
254
254
  version: latestVersion(s.name)?.version ?? null
255
255
  }));
256
256
  return {
@@ -474,12 +474,16 @@ function CleanupWizard({
474
474
  /* @__PURE__ */ jsx2(Box2, { flexGrow: 1 }),
475
475
  orphans.length ? /* @__PURE__ */ jsx2(Text2, { color: color.yellow, children: `${plural(orphans.length, "skill")} won't be in any project \u2014 add them later from "Add skills".` }) : null
476
476
  ] }),
477
- /* @__PURE__ */ jsxs2(Box2, { height: 1, paddingX: 1, children: [
478
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: color.accentDim, color: color.text, children: " enter " }),
479
- /* @__PURE__ */ jsx2(Text2, { color: color.muted, children: " apply " }),
480
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: color.accentDim, color: color.text, children: " esc " }),
481
- /* @__PURE__ */ jsx2(Text2, { color: color.muted, children: " back" })
482
- ] })
477
+ /* @__PURE__ */ jsx2(Box2, { height: 1, paddingX: 1, children: /* @__PURE__ */ jsx2(
478
+ KeyBar,
479
+ {
480
+ width: width - 2,
481
+ hints: [
482
+ ["enter", "apply"],
483
+ ["esc", "back"]
484
+ ]
485
+ }
486
+ ) })
483
487
  ] });
484
488
  }
485
489
  const leftWidth = Math.max(40, Math.floor(width * 0.55));
@@ -559,17 +563,20 @@ function CleanupWizard({
559
563
  })() }),
560
564
  wrap(skill.description || "(no description)", width - 6, detailHeight - 3).map((l, i) => /* @__PURE__ */ jsx2(Text2, { color: color.text, wrap: "truncate-end", children: l }, i))
561
565
  ] }) : null,
562
- /* @__PURE__ */ jsx2(Box2, { height: 1, paddingX: 1, children: [
563
- ["space", focus === "skills" ? "move / keep / delete" : "tick project"],
564
- ...focus === "skills" ? [["d", "delete"]] : [],
565
- ["tab", "switch side"],
566
- ["p", "ask an agent (copy prompt)"],
567
- ["enter", `review (${plural(totalInstalls, "install")})`],
568
- ["esc", "cancel"]
569
- ].map(([k, l]) => /* @__PURE__ */ jsxs2(Box2, { marginRight: 2, children: [
570
- /* @__PURE__ */ jsx2(Text2, { backgroundColor: color.accentDim, color: color.text, children: ` ${k} ` }),
571
- /* @__PURE__ */ jsx2(Text2, { color: color.muted, children: ` ${l}` })
572
- ] }, k)) })
566
+ /* @__PURE__ */ jsx2(Box2, { height: 1, paddingX: 1, children: /* @__PURE__ */ jsx2(
567
+ KeyBar,
568
+ {
569
+ width: width - 2,
570
+ hints: [
571
+ ["space", focus === "skills" ? "move / keep / delete" : "tick project"],
572
+ ...focus === "skills" ? [["d", "delete"]] : [],
573
+ ["tab", "switch side"],
574
+ ["enter", `review (${plural(totalInstalls, "install")})`],
575
+ ["p", "ask an agent"],
576
+ ["esc", "cancel"]
577
+ ]
578
+ }
579
+ ) })
573
580
  ] });
574
581
  }
575
582
 
@@ -1156,7 +1163,8 @@ function App() {
1156
1163
  const edit = async (file) => {
1157
1164
  const editor = process.env.VISUAL || process.env.EDITOR || (process.platform === "win32" ? "notepad" : "vi");
1158
1165
  await suspendTerminal(() => {
1159
- spawnSync2(`${editor} "${file}"`, { shell: true, stdio: "inherit" });
1166
+ if (process.platform === "win32") spawnSync2(`${editor} "${file}"`, { shell: true, stdio: "inherit" });
1167
+ else spawnSync2("/bin/sh", ["-c", `${editor} "$1"`, "sh", file], { stdio: "inherit" });
1160
1168
  });
1161
1169
  reload();
1162
1170
  say(`Saved ${tildify2(file)}`);
package/package.json CHANGED
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "skilllib",
3
- "version": "1.0.0",
4
- "description": "Manage agent skills like dependencies: one versioned library, and each repo picks what it needs. Works with Claude Code, Cursor, Codex and Zed.",
3
+ "version": "1.0.2",
4
+ "description": "Manage your agent skills like dependencies. One library for all your skills; each repo gets only the ones it needs, and every agent can see them. Works with Claude Code, Cursor, Codex and Zed.",
5
5
  "keywords": [
6
6
  "agent-skills",
7
7
  "skills",
8
+ "skill-md",
8
9
  "claude-code",
10
+ "claude",
9
11
  "cursor",
10
12
  "codex",
11
13
  "zed",
12
- "skill-md",
14
+ "ai-agents",
15
+ "skills-manager",
13
16
  "cli",
14
17
  "tui"
15
18
  ],
@@ -25,7 +28,7 @@
25
28
  "author": "Toni Tralice",
26
29
  "type": "module",
27
30
  "bin": {
28
- "skilllib": "./dist/index.js"
31
+ "skilllib": "dist/index.js"
29
32
  },
30
33
  "files": [
31
34
  "dist",