@klhapp/skillmux 0.4.4 → 0.5.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.
- package/CHANGELOG.md +29 -0
- package/README.md +57 -11
- package/docs/configuration.md +50 -9
- package/package.json +1 -1
- package/src/cli.ts +524 -44
- package/src/completions.ts +33 -2
- package/src/config.ts +7 -3
- package/src/init-clients.ts +189 -0
- package/src/init-instructions.ts +173 -0
- package/src/init.ts +280 -17
- package/src/manifest.ts +24 -13
- package/src/setup.ts +145 -0
- package/src/sync.ts +136 -19
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,35 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.5.0](https://github.com/klhq/skillmux/compare/v0.4.5...v0.5.0) (2026-07-24)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
* **init:** add named client registry ([e14dc26](https://github.com/klhq/skillmux/commit/e14dc261c51f7235cd7ee2223f49a0ec87668922))
|
|
14
|
+
* **init:** add safe client-aware setup planner ([4a199b7](https://github.com/klhq/skillmux/commit/4a199b76c52819601a5935a7e6ac478aeddce5ca))
|
|
15
|
+
* **init:** add shared setup bootstrap planner ([83ef8de](https://github.com/klhq/skillmux/commit/83ef8de67a1ff8a13de992e26ad5eedb4487509c))
|
|
16
|
+
* **init:** add transactional setup planning ([6fc6f5e](https://github.com/klhq/skillmux/commit/6fc6f5e8d991a6b411c78016f5d0659486daf4d0))
|
|
17
|
+
* **init:** classify and preflight skill surfaces ([b760e93](https://github.com/klhq/skillmux/commit/b760e939a66b49372642109daff6e753d9b99b8b))
|
|
18
|
+
* **init:** harden target setup and host scoping ([8941f59](https://github.com/klhq/skillmux/commit/8941f598b52f73fe204c0705efb2b857b2f3c658))
|
|
19
|
+
* **init:** manage client instruction blocks ([256c7a7](https://github.com/klhq/skillmux/commit/256c7a7f690e14a0e4ea5340536d762dab853bcc))
|
|
20
|
+
* **init:** preflight and commit setup atomically ([9307780](https://github.com/klhq/skillmux/commit/93077809fca4949b1384213a7d8d444cd0da88eb))
|
|
21
|
+
* **sync:** scope manifest targets by host ([1441dea](https://github.com/klhq/skillmux/commit/1441deac95e70df9d97b798cb514f6e7722e24eb))
|
|
22
|
+
* **sync:** track ownership with versioned markers ([ad415b1](https://github.com/klhq/skillmux/commit/ad415b1a5cd8cf5351e6497c42640b624048d001))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
* **init:** harden no-op plans and symlink checks ([137e050](https://github.com/klhq/skillmux/commit/137e05086e4f6b2d01cfdf6d5e8843f21bc1ae54))
|
|
28
|
+
* **init:** preserve existing setup on reinitialization ([0c1bea9](https://github.com/klhq/skillmux/commit/0c1bea92c1d600679663c853f15bcc5a246109ff))
|
|
29
|
+
|
|
30
|
+
## [0.4.5](https://github.com/klhq/skillmux/compare/v0.4.4...v0.4.5) (2026-07-24)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
* **manifest:** rename project group repos to paths ([51263f1](https://github.com/klhq/skillmux/commit/51263f175a45b6368509bb3c25ce8dcbeb07d127))
|
|
36
|
+
|
|
8
37
|
## [0.4.4](https://github.com/klhq/skillmux/compare/v0.4.3...v0.4.4) (2026-07-23)
|
|
9
38
|
|
|
10
39
|
|
package/README.md
CHANGED
|
@@ -186,29 +186,74 @@ bun run src/cli.ts serve
|
|
|
186
186
|
|
|
187
187
|
Optional — skip this if `resolve_skill` alone is enough (most setups). Use it once you want a small set of skills loaded *statically* in every agent that reads from a given directory, instead of routed on demand — see [Tiers](#tiers-routed-vs-pinned).
|
|
188
188
|
|
|
189
|
-
### 1.
|
|
189
|
+
### 1. Check the plan
|
|
190
190
|
|
|
191
191
|
```sh
|
|
192
|
-
skillmux init
|
|
192
|
+
skillmux init --client claude-code --client codex --core csv-formatter --dry-run
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
-
|
|
195
|
+
`--client` names the tool you use. Skillmux maps it to the correct user-level
|
|
196
|
+
skill directory and merges clients that share one directory. Gemini CLI,
|
|
197
|
+
OpenCode, GitHub Copilot, and Windsurf share `~/.agents/skills`. Claude Code
|
|
198
|
+
uses `~/.claude/skills`; Codex uses `$CODEX_HOME/skills` or
|
|
199
|
+
`~/.codex/skills`.
|
|
200
|
+
|
|
201
|
+
Supported clients are `claude-code`, `codex`, `gemini-cli`, `opencode`,
|
|
202
|
+
`github-copilot`, `windsurf`, `antigravity`, `goose`, `hermes`, and
|
|
203
|
+
`skillmux-mcp`. Goose, Hermes, and Skillmux MCP report the manual registration
|
|
204
|
+
work they need instead of inventing a target directory.
|
|
205
|
+
|
|
206
|
+
The dry run prints target classification, config changes, instruction-file
|
|
207
|
+
changes, readiness, and core pins. It does not prompt or write.
|
|
208
|
+
|
|
209
|
+
### 2. Apply the plan
|
|
210
|
+
|
|
211
|
+
```sh
|
|
212
|
+
skillmux init --client claude-code --client codex --core csv-formatter --yes
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Skillmux writes `skillmux.toml`, adds host-scoped targets, adopts each selected
|
|
216
|
+
directory, and installs one managed discovery block in each client's durable
|
|
217
|
+
instruction file. Existing manifest entries and instruction text stay intact.
|
|
218
|
+
Without `--yes`, an interactive terminal asks about each change; a pipe or CI
|
|
219
|
+
job must pass `--yes`.
|
|
220
|
+
|
|
221
|
+
Use direct targets when you want paths rather than clients:
|
|
222
|
+
|
|
223
|
+
```sh
|
|
224
|
+
skillmux init --target agent-skills --yes
|
|
225
|
+
skillmux init --target claude-code --yes
|
|
226
|
+
skillmux init --target codex --yes
|
|
227
|
+
skillmux init --target custom --path /srv/my-agent/skills --yes
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
The old `agents` and `claude` target names still work and print a deprecation
|
|
231
|
+
warning. Skillmux keeps those names in an existing manifest.
|
|
232
|
+
|
|
233
|
+
If a target points at the whole vault, Skillmux classifies it as `full-vault`
|
|
234
|
+
and refuses managed-pin adoption. Review the visibility change before
|
|
235
|
+
converting it:
|
|
196
236
|
|
|
197
237
|
```sh
|
|
198
|
-
skillmux init --
|
|
238
|
+
skillmux init --client claude-code --migrate-full-vault \
|
|
239
|
+
--core csv-formatter --dry-run
|
|
240
|
+
skillmux init --client claude-code --migrate-full-vault \
|
|
241
|
+
--core csv-formatter --yes
|
|
199
242
|
```
|
|
200
243
|
|
|
201
|
-
|
|
244
|
+
After conversion and `skillmux sync`, the client sees the selected core pins
|
|
245
|
+
instead of every vault skill.
|
|
202
246
|
|
|
203
|
-
###
|
|
247
|
+
### 3. Add or remove pins later
|
|
204
248
|
|
|
205
|
-
|
|
249
|
+
`--core` seeds only the skill IDs you name. Without it, `init` preserves
|
|
250
|
+
existing core pins and makes no guesses. Add another pin with:
|
|
206
251
|
|
|
207
252
|
```sh
|
|
208
253
|
skillmux manifest pin csv-formatter --core
|
|
209
254
|
```
|
|
210
255
|
|
|
211
|
-
Unpin the same way: `skillmux manifest unpin csv-formatter --core`. `--project <group>` pins into a `[project.<group>]` tier instead (add `--
|
|
256
|
+
Unpin the same way: `skillmux manifest unpin csv-formatter --core`. `--project <group>` pins into a `[project.<group>]` tier instead (add `--path <path>` the first time, to create the group). Every pin is validated before writing — the skill must actually resolve from the vault, and `[core]` stays under its 25-skill cap.
|
|
212
257
|
|
|
213
258
|
Hand-editing `skillmux.toml` still works if you prefer it:
|
|
214
259
|
|
|
@@ -218,12 +263,13 @@ skills = ["csv-formatter"]
|
|
|
218
263
|
|
|
219
264
|
[targets.claude]
|
|
220
265
|
dir = "/Users/you/.claude/skills"
|
|
266
|
+
host = "workhorse" # optional; sync skips this target on every other hostname
|
|
221
267
|
project_groups = []
|
|
222
268
|
```
|
|
223
269
|
|
|
224
|
-
Full manifest schema, including `[project.<group>]` pins scoped to one
|
|
270
|
+
Full manifest schema, including `[project.<group>]` pins scoped to one or more local paths and machine-local overlay vaults via `local_vault_paths`, is in [`docs/configuration.md`](docs/configuration.md#tiers-and-the-manifest).
|
|
225
271
|
|
|
226
|
-
###
|
|
272
|
+
### 4. Materialize
|
|
227
273
|
|
|
228
274
|
```sh
|
|
229
275
|
skillmux sync
|
|
@@ -240,7 +286,7 @@ skillmux sync --restore-monolith # undo: replace a target dir with one symlink
|
|
|
240
286
|
|
|
241
287
|
`--restore-monolith` drops the `.skillmux` marker along with the per-skill symlinks — re-adopt with `skillmux init --target <name> --yes` before that target can be `sync`'d again.
|
|
242
288
|
|
|
243
|
-
###
|
|
289
|
+
### 5. See what's actually getting used
|
|
244
290
|
|
|
245
291
|
`skillmux report` reads the same audit log `resolve_skill` writes to (see [Guarantees](#guarantees)) — useful for deciding what belongs in `[core]` versus staying routed:
|
|
246
292
|
|
package/docs/configuration.md
CHANGED
|
@@ -4,6 +4,25 @@ Skillmux defaults to FTS5 plus local GTE-small semantic retrieval. Most users ne
|
|
|
4
4
|
|
|
5
5
|
For detailed CLI command reference, target resolution, policy calibration, and automation envelopes, see [`docs/cli.md`](cli.md).
|
|
6
6
|
|
|
7
|
+
## Machine config bootstrap
|
|
8
|
+
|
|
9
|
+
Create `~/.config/skillmux/config.toml` from a populated vault:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
skillmux config init --vault ~/skills --yes
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The command writes:
|
|
16
|
+
|
|
17
|
+
```toml
|
|
18
|
+
vault_path = "/home/you/skills"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
It validates that the path resolves to a directory with at least one
|
|
22
|
+
`SKILL.md`, preserves an existing config byte-for-byte, and leaves
|
|
23
|
+
`local_vault_paths` unset. `skillmux init --vault ~/skills --yes` uses the
|
|
24
|
+
same bootstrap when the machine config does not exist.
|
|
25
|
+
|
|
7
26
|
## Local mode
|
|
8
27
|
|
|
9
28
|
```toml
|
|
@@ -85,39 +104,61 @@ Lives at the vault root (a legacy `skr.toml` is still read if present, never wri
|
|
|
85
104
|
skills = ["csv-formatter"] # pinned into every [targets.*] dir; capped at 25
|
|
86
105
|
|
|
87
106
|
[project.repo1]
|
|
88
|
-
|
|
107
|
+
paths = ["/Users/you/code/repo1"] # only synced for paths that exist locally
|
|
89
108
|
skills = ["pdf-extractor"] # must not overlap [core]
|
|
90
109
|
|
|
91
|
-
[targets.claude]
|
|
110
|
+
[targets.claude-code]
|
|
92
111
|
dir = "/Users/you/.claude/skills"
|
|
112
|
+
host = "workhorse" # optional; init adds the current hostname
|
|
93
113
|
project_groups = ["repo1"] # which [project.*] groups materialize into this target — [] means none
|
|
94
114
|
```
|
|
95
115
|
|
|
96
116
|
- `[core].skills` — symlinked into every `[targets.*]` dir on `sync`. Capped at 25 skills; `sync` fails if a listed skill id isn't actually in the vault.
|
|
97
|
-
- `[project.<group>].skills` — symlinked only into `<
|
|
98
|
-
- `[
|
|
117
|
+
- `[project.<group>].skills` — symlinked only into `<path>/<relative path from $HOME to the target dir>`, for each `paths` entry, and only for targets whose `project_groups` names that group. `paths` entries must resolve under `$HOME` (that's how the pin path is derived). A skill can't appear in both `[core]` and the same `[project.*]` group.
|
|
118
|
+
- `[project.<group>].paths` can list the same project's checkout on more than one machine (e.g. `["/home/alice/code/repo1", "/Users/alice/code/repo1"]`) — `sync` silently skips any entry that doesn't exist on the machine it's running on (see below), so one shared manifest can span machines with different checkout locations without needing per-machine manifests.
|
|
119
|
+
- `[targets.<name>]` — one entry per adopted surface. `skillmux init --target <name> --yes` writes these and scopes newly added targets to the current hostname. Hand-editing is fine as long as `sync` is still allowed to own the directory (see below). An optional `host` limits the target to an exact machine-hostname match; omit it for a global, backward-compatible target. A host mismatch is reported and skipped before any target filesystem operation. `project_groups` is an explicit list, not a boolean — a target only receives the specific groups it names, never every group in the manifest.
|
|
99
120
|
|
|
100
121
|
**Pin/unpin without hand-editing.** `skillmux manifest pin`/`unpin` mutate `[core]`/`[project.*]` for you, validating with the same rules `sync`/`doctor` enforce (skill must resolve from `vault_path`, no duplicate pins, `[core]` stays under the 25-skill cap) before writing anything:
|
|
101
122
|
|
|
102
123
|
```sh
|
|
103
124
|
skillmux manifest pin csv-formatter --core # add to [core]
|
|
104
125
|
skillmux manifest pin pdf-extractor --project repo1 # add to an existing group
|
|
105
|
-
skillmux manifest pin pdf-extractor --project repo2 --
|
|
126
|
+
skillmux manifest pin pdf-extractor --project repo2 --path ~/code/repo2 # create a new group
|
|
106
127
|
skillmux manifest unpin csv-formatter --core # remove from [core]
|
|
107
128
|
skillmux manifest unpin pdf-extractor --project repo1 # remove from a group (group stays, even if empty)
|
|
108
129
|
```
|
|
109
130
|
|
|
110
|
-
`--
|
|
131
|
+
`--path` is only accepted when `--project <group>` names a group that doesn't exist yet — passing it for an existing group is rejected, since changing an existing group's `paths` isn't this command's job (append another entry by hand-editing `skillmux.toml` instead). Hand-editing `skillmux.toml` directly is still fully supported; these commands are a convenience layer over the same file, not a replacement for it.
|
|
111
132
|
|
|
112
133
|
> **Breaking change:** `[targets.<name>].project` (a boolean) has been replaced by `project_groups` (an array of `[project.*]` names). A manifest still using the old field fails to parse with an error pointing at the new one. To migrate, replace `project = true` with `project_groups = [...]` listing every group that target previously received (previously *all* groups, unconditionally); replace `project = false` with `project_groups = []`.
|
|
134
|
+
>
|
|
135
|
+
> **Breaking change:** `[project.<group>].repos` has been renamed to `paths` — it was never required to be a git repository, just a local directory, and the old name collided in meaning with `skillmux install <repo>`'s unrelated git-source `repo` concept. A manifest still using `repos` fails to parse with an error pointing at `paths`; migrate by renaming the key (values are unchanged).
|
|
113
136
|
|
|
114
137
|
Every `[core]`/`[project.*]` skill_id must resolve from the canonical `vault_path` — pinning a skill that only exists in a `local_vault_paths` entry (see below) fails `sync`/`doctor` with a distinct error, since the manifest is meant to be portable across machines and a machine-local override wouldn't exist elsewhere.
|
|
115
138
|
|
|
116
139
|
### Ownership marker
|
|
117
140
|
|
|
118
|
-
Every directory `sync` manages gets a `.skillmux` marker
|
|
119
|
-
|
|
120
|
-
|
|
141
|
+
Every directory `sync` manages gets a versioned `.skillmux` marker. A target
|
|
142
|
+
marker records `schema_version: 1`, `managed_by: "skillmux"`, `role:
|
|
143
|
+
"target"`, its target name, `vault_path`, `created_at`, and
|
|
144
|
+
`managed_entries`. The last field is the exact list of directory entries
|
|
145
|
+
Skillmux created. Sync removes only those tracked entries, preserves unrelated
|
|
146
|
+
content, and rejects a desired skill that collides with an unmanaged entry
|
|
147
|
+
before changing anything.
|
|
148
|
+
|
|
149
|
+
`sync` refuses to touch a directory that exists but has no marker — run
|
|
150
|
+
`skillmux init --target <name> --yes` first, which either creates the
|
|
151
|
+
directory fresh or adopts an existing one in place (contents untouched).
|
|
152
|
+
`sync --restore-monolith` likewise refuses a `local_vault` marker or any
|
|
153
|
+
unmanaged target content before replacing a target directory with a symlink
|
|
154
|
+
to the vault.
|
|
155
|
+
|
|
156
|
+
The same `.skillmux` filename is used for `local_vault_paths` entries (see
|
|
157
|
+
below), distinguished by `role: "local_vault"` and never accepted as target
|
|
158
|
+
ownership. Legacy unversioned markers are read for compatibility. An empty
|
|
159
|
+
legacy target is upgraded safely on its next sync; one containing untracked
|
|
160
|
+
entries is rejected with a migration diagnostic because their ownership
|
|
161
|
+
cannot be inferred.
|
|
121
162
|
|
|
122
163
|
### Local vault overlays
|
|
123
164
|
|
package/package.json
CHANGED