@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 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. Discover surfaces and adopt one
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
- Lists candidate surfaces (default: `~/.claude/skills`, `~/.agents/skills`) with their dir/symlink status and skill count. Nothing is written until you pass `--target`:
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 --target claude --yes
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
- This writes `skillmux.toml` at the vault root and marks `~/.claude/skills` as skillmux-owned — a `.skillmux` marker file that `sync` requires before it will touch the directory.
244
+ After conversion and `skillmux sync`, the client sees the selected core pins
245
+ instead of every vault skill.
202
246
 
203
- ### 2. Pick which skills are pinned
247
+ ### 3. Add or remove pins later
204
248
 
205
- `init` always starts `[core]` empty there's no heuristic yet for which skills belong there. Pin with the CLI instead of hand-editing `skillmux.toml`:
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 `--repo <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.
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 repo and machine-local overlay vaults via `local_vault_paths`, is in [`docs/configuration.md`](docs/configuration.md#tiers-and-the-manifest).
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
- ### 3. Materialize
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
- ### 4. See what's actually getting used
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
 
@@ -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
- repos = ["/Users/you/code/repo1"] # only synced for repos paths that exist locally
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 `<repo>/<relative path from $HOME to the target dir>`, for each `repos` entry, and only for targets whose `project_groups` names that group. `repos` 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.
98
- - `[targets.<name>]` one entry per adopted surface. `skillmux init --target <name> --yes` writes these; hand-editing is fine as long as `sync` is still allowed to own the directory (see below). `project_groups` is an explicit list, not a boolean a target only receives the specific groups it names, never every group in the manifest.
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 --repo ~/code/repo2 # create a new group
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
- `--repo` 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 `repos` isn't this command's job. Hand-editing `skillmux.toml` directly is still fully supported; these commands are a convenience layer over the same file, not a replacement for it.
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 file (`{"managed_by": "skillmux", "role": "target", "target": "<name>", "created_at": ...}`). `sync` refuses to touch a directory that exists but has no marker — run `skillmux init --target <name> --yes` first, which either creates the directory fresh or adopts an existing one in place (contents untouched). This is also why `sync --restore-monolith` (which deletes the marker and replaces the whole directory with one symlink straight to the vault) requires re-running `init` before that target can be `sync`'d again.
119
-
120
- The same `.skillmux` marker filename and JSON shape is also used for `local_vault_paths` entries (see below), distinguished by `role: "local_vault"` with a `vault_path` field instead of `target`. Markers written before this `role` field existed have no `role` key at all — they're read back as `role: "target"`, so nothing already on disk needs migrating.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klhapp/skillmux",
3
- "version": "0.4.4",
3
+ "version": "0.5.0",
4
4
  "description": "Local read-only MCP server routing natural-language task queries to skills in a SKILL.md vault, with zero-loss delivery",
5
5
  "type": "module",
6
6
  "private": false,