@klhapp/skillmux 1.7.1 → 1.9.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,41 @@ 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
+ ## [1.9.0](https://github.com/klhq/skillmux/compare/v1.8.0...v1.9.0) (2026-08-30)
9
+
10
+
11
+ ### Added
12
+
13
+ * track skill provenance and add outdated/update commands ([#133](https://github.com/klhq/skillmux/issues/133)) ([4d4f8c9](https://github.com/klhq/skillmux/commit/4d4f8c94a7e34e1ad030f9904995d02fa5fa2712))
14
+
15
+
16
+ ### Fixed
17
+
18
+ * **install:** guard findSymlinks against a symlinked skill_path directory itself ([#146](https://github.com/klhq/skillmux/issues/146)) ([a264afc](https://github.com/klhq/skillmux/commit/a264afc19710206c4f77c61e3a9dccafb54c2894))
19
+ * **install:** prevent symlink smuggling in skill content ([#136](https://github.com/klhq/skillmux/issues/136)) ([2df318c](https://github.com/klhq/skillmux/commit/2df318cfdc974b0f7b9042c3d68fa4fece9109d9))
20
+ * **provenance:** refuse to hash a symlinked SKILL.md instead of following it ([#141](https://github.com/klhq/skillmux/issues/141)) ([74d1b9c](https://github.com/klhq/skillmux/commit/74d1b9c2f8fb2891ce743ccf09b9632fea58aa84))
21
+ * **provenance:** refuse to read a symlinked .skillmux-origin sidecar ([#144](https://github.com/klhq/skillmux/issues/144)) ([c9c0b32](https://github.com/klhq/skillmux/commit/c9c0b327f8cf26e1a9cd9971263cfa4f35235de3))
22
+ * **scan:** guard readTextFileOrNull against symlinks at every call site ([#143](https://github.com/klhq/skillmux/issues/143)) ([6692060](https://github.com/klhq/skillmux/commit/66920601bb4969911063407afa3dbffcf09c00be))
23
+ * **scan:** refuse to scan a symlinked SKILL.md in single-skill-dir mode ([#142](https://github.com/klhq/skillmux/issues/142)) ([b20cd66](https://github.com/klhq/skillmux/commit/b20cd6621a30067643034dd155383afab3540cf2))
24
+ * **security:** validate provenance sidecar values before they reach git subprocess calls ([#135](https://github.com/klhq/skillmux/issues/135)) ([01d643a](https://github.com/klhq/skillmux/commit/01d643a789e353d0d944b7b467f3c9f0894718ce))
25
+ * **sync:** skip symlinking core skill dirs with internal links ([#137](https://github.com/klhq/skillmux/issues/137)) ([f992b39](https://github.com/klhq/skillmux/commit/f992b39720dcdd3e946c6628817bd11b54380f40))
26
+ * **update:** skip file:// source_url in outdated/update by default ([#147](https://github.com/klhq/skillmux/issues/147)) ([9b127d0](https://github.com/klhq/skillmux/commit/9b127d0a65f89cfd32e6ed8d75155ba388349fae))
27
+ * **vault:** guard against a symlinked skill directory, not just its leaf files ([#145](https://github.com/klhq/skillmux/issues/145)) ([63d34e3](https://github.com/klhq/skillmux/commit/63d34e32bc4d91221f03fbbfdf22d3a0fdc7a492))
28
+ * **vault:** refuse to read a symlinked SKILL.md ([#140](https://github.com/klhq/skillmux/issues/140)) ([3220fe3](https://github.com/klhq/skillmux/commit/3220fe393a81922f76729284d156644662f177f2))
29
+ * **vault:** secure listSupportingFiles against symlinks and traversal ([#138](https://github.com/klhq/skillmux/issues/138)) ([6343a30](https://github.com/klhq/skillmux/commit/6343a30747844c5f83b810cbfe3d19ed569ca7cd))
30
+
31
+
32
+ ### Changed
33
+
34
+ * **update:** skip cloning drifted skills before fetching ([1b247b6](https://github.com/klhq/skillmux/commit/1b247b6379b021692c839a77d44a81bd736f2bea))
35
+
36
+ ## [1.8.0](https://github.com/klhq/skillmux/compare/v1.7.1...v1.8.0) (2026-08-28)
37
+
38
+
39
+ ### Added
40
+
41
+ * **audit:** add fetch-outcome routing quality flywheel ([#131](https://github.com/klhq/skillmux/issues/131)) ([c55e5ec](https://github.com/klhq/skillmux/commit/c55e5ec794453ccbdbf7ffe9263684356d2a71de))
42
+
8
43
  ## [1.7.1](https://github.com/klhq/skillmux/compare/v1.7.0...v1.7.1) (2026-08-21)
9
44
 
10
45
 
package/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  <p align="center">
2
- <img src="https://raw.githubusercontent.com/klhq/skillmux/main/docs/assets/logo.png" alt="skillmux" width="400">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/klhq/skillmux/main/docs/assets/logo-dark.png">
4
+ <img src="https://raw.githubusercontent.com/klhq/skillmux/main/docs/assets/logo-light.png" alt="skillmux" width="400">
5
+ </picture>
3
6
  </p>
4
7
 
5
8
  <p align="center">
@@ -9,9 +12,12 @@
9
12
  <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
10
13
  </p>
11
14
 
12
- Skillmux manages [`SKILL.md`](https://agentskills.io) collections across AI
13
- coding clients. Keep one **vault source of truth**—the logical skill
14
- collection—pin a small set into native skill directories, and retrieve the
15
+ <p align="center"><strong>One skill vault. Every AI coding client. Nothing lost in translation.</strong></p>
16
+
17
+ Every AI coding client wants its own skill folder and its own format. Skillmux
18
+ manages [`SKILL.md`](https://agentskills.io) collections across all of them
19
+ from one place. Keep one **vault source of truth** (the logical skill
20
+ collection), pin a small set into native skill directories, and retrieve the
15
21
  rest through MCP. A **vault checkout** is a physical copy of that collection.
16
22
  On one machine, `~/skills` can be both the source of truth and its checkout.
17
23
 
@@ -55,7 +61,10 @@ command to run; see the [container command contract](docs/deployment.md#containe
55
61
  ## One vault source of truth, three ways to use it
56
62
 
57
63
  <p align="center">
58
- <img src="docs/assets/architecture.svg" alt="Three ways to use Skillmux: manage native skills, add local MCP retrieval, or run a shared MCP service" width="100%">
64
+ <picture>
65
+ <source media="(prefers-color-scheme: dark)" srcset="docs/assets/architecture-dark.svg">
66
+ <img src="docs/assets/architecture-light.svg" alt="Three ways to use Skillmux: manage native skills, add local MCP retrieval, or run a shared MCP service" width="100%">
67
+ </picture>
59
68
  </p>
60
69
 
61
70
  “Local” describes where Skillmux runs. “Local inference” means the embedding
@@ -204,6 +213,7 @@ Useful management commands:
204
213
 
205
214
  ```sh
206
215
  skillmux scan ~/skills
216
+ skillmux outdated
207
217
  skillmux core pin csv-formatter --yes
208
218
  skillmux project pin my-project code-context --yes
209
219
  skillmux skill which csv-formatter
@@ -0,0 +1,160 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 720" role="img" aria-labelledby="title desc">
2
+ <title id="title">One vault source of truth, three ways to use Skillmux</title>
3
+ <desc id="desc">One Git-backed vault source of truth holds one SKILL.md per child directory and feeds a client checkout and a server checkout. On a client machine, Skillmux CLI manages native skills and serves local stdio MCP; a server checkout serves shared Streamable HTTP MCP. resolve_skill fuses lexical and vector results and optionally reranks them; fetch_skill returns the current SKILL.md bytes with a SHA-256. Git and deployment own checkout replication and freshness.</desc>
4
+
5
+ <defs>
6
+ <filter id="shadow" x="-15%" y="-15%" width="130%" height="140%">
7
+ <feDropShadow dx="0" dy="5" stdDeviation="8" flood-color="#000000" flood-opacity="0.35"/>
8
+ </filter>
9
+ <marker id="arrow-teal" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
10
+ <path d="M0 0L10 5L0 10Z" fill="#2dd4bf"/>
11
+ </marker>
12
+ <marker id="arrow-blue" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
13
+ <path d="M0 0L10 5L0 10Z" fill="#60a5fa"/>
14
+ </marker>
15
+ <marker id="arrow-violet" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
16
+ <path d="M0 0L10 5L0 10Z" fill="#a78bfa"/>
17
+ </marker>
18
+ <style>
19
+ text {
20
+ font-family: "DejaVu Sans", Arial, sans-serif;
21
+ }
22
+ .title {
23
+ font-size: 27px;
24
+ font-weight: 750;
25
+ fill: #e2e8f0;
26
+ }
27
+ .subtitle {
28
+ font-size: 16px;
29
+ font-weight: 400;
30
+ fill: #94a3b8;
31
+ }
32
+ .card-title {
33
+ font-size: 21px;
34
+ font-weight: 750;
35
+ fill: #e2e8f0;
36
+ }
37
+ .label {
38
+ font-size: 15px;
39
+ font-weight: 650;
40
+ fill: #cbd5e1;
41
+ }
42
+ .body {
43
+ font-size: 14px;
44
+ font-weight: 400;
45
+ fill: #94a3b8;
46
+ }
47
+ .mono {
48
+ font-family: "DejaVu Sans Mono", Consolas, monospace;
49
+ font-size: 14px;
50
+ font-weight: 650;
51
+ fill: #cbd5e1;
52
+ }
53
+ .mono-light {
54
+ fill: #ffffff;
55
+ }
56
+ .chip {
57
+ font-size: 12px;
58
+ font-weight: 750;
59
+ letter-spacing: .5px;
60
+ }
61
+ </style>
62
+ </defs>
63
+
64
+ <rect width="1200" height="720" rx="24" fill="#0d1117"/>
65
+ <rect x="1" y="1" width="1198" height="718" rx="23" fill="none" stroke="#30363d" stroke-width="2"/>
66
+
67
+ <text x="48" y="50" class="title">One vault source of truth, three ways to use Skillmux</text>
68
+ <text x="48" y="78" class="subtitle">Git and deployment replicate checkouts; Skillmux uses each checkout where it runs.</text>
69
+
70
+ <g filter="url(#shadow)">
71
+ <rect x="280" y="106" width="640" height="118" rx="18" fill="#161b22" stroke="#30363d" stroke-width="2"/>
72
+ <circle cx="324" cy="147" r="18" fill="#334155"/>
73
+ <path d="M314 141H327L333 147L327 153H314M320 135V159" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
74
+ <text x="358" y="144" class="card-title">Git-backed vault source of truth</text>
75
+ <text x="358" y="172" class="mono">SKILL.md per child directory</text>
76
+ <text x="358" y="200" class="body">A checkout is a physical copy of it on one machine.</text>
77
+ <rect x="751" y="155" width="137" height="34" rx="9" fill="#1e293b" stroke="#475569"/>
78
+ <text x="819.5" y="177" text-anchor="middle" class="mono">skillmux.toml</text>
79
+ </g>
80
+
81
+ <path d="M520 224V252H410V277" fill="none" stroke="#2dd4bf" stroke-width="3" marker-end="url(#arrow-teal)"/>
82
+ <path d="M720 224V252H980V277" fill="none" stroke="#a78bfa" stroke-width="3" marker-end="url(#arrow-violet)"/>
83
+ <text x="394" y="270" text-anchor="end" class="body">client checkout</text>
84
+ <text x="996" y="270" text-anchor="start" class="body">server checkout</text>
85
+
86
+ <g filter="url(#shadow)">
87
+ <rect x="40" y="284" width="740" height="302" rx="18" fill="#161b22" stroke="#0f766e" stroke-width="2"/>
88
+ <rect x="62" y="306" width="124" height="26" rx="13" fill="#134e4a"/>
89
+ <text x="124" y="324" text-anchor="middle" class="chip" fill="#5eead4">SKILLMUX CLI</text>
90
+ <text x="62" y="365" class="card-title">On one client machine</text>
91
+ <text x="62" y="390" class="body">Manage native skills, add local MCP retrieval, or do both.</text>
92
+
93
+ <rect x="62" y="414" width="276" height="48" rx="10" fill="#0f2e2b" stroke="#0f766e"/>
94
+ <circle cx="85" cy="438" r="11" fill="#2dd4bf"/>
95
+ <text x="85" y="442.5" text-anchor="middle" style="font-size: 13px; font-weight: 750" fill="#0d1117">1</text>
96
+ <text x="200" y="433" text-anchor="middle" class="label" style="font-size: 17px">Manage native skills</text>
97
+ <text x="200" y="453" text-anchor="middle" class="mono">skillmux init · sync</text>
98
+ <path d="M200 462V487" fill="none" stroke="#2dd4bf" stroke-width="2.5" marker-end="url(#arrow-teal)"/>
99
+ <rect x="62" y="493" width="276" height="49" rx="10" fill="#1e293b" stroke="#475569"/>
100
+ <text x="200" y="514" text-anchor="middle" class="label">Native skill directories</text>
101
+ <text x="200" y="533" text-anchor="middle" class="body">managed core and project links</text>
102
+
103
+ <text x="62" y="570" class="body">Install Skillmux CLI with</text>
104
+ <rect x="270" y="550" width="85" height="27" rx="8" fill="#0f172a" stroke="#334155"/>
105
+ <text x="312.5" y="568" text-anchor="middle" class="chip" style="font-size: 10px" fill="#ffffff">BUN PACKAGE</text>
106
+ <rect x="361" y="550" width="87" height="27" rx="8" fill="#1e293b" stroke="#475569"/>
107
+ <text x="404.5" y="561" text-anchor="middle" class="chip" style="font-size: 10px" fill="#cbd5e1"><tspan x="404.5">LINUX</tspan><tspan x="404.5" dy="11">EXECUTABLE</tspan></text>
108
+ </g>
109
+
110
+ <g filter="url(#shadow)">
111
+ <rect x="420" y="414" width="338" height="128" rx="10" fill="#172554" stroke="#3b82f6"/>
112
+ <circle cx="453" cy="435" r="11" fill="#60a5fa"/>
113
+ <text x="453" y="439.5" text-anchor="middle" style="font-size: 13px; font-weight: 750" fill="#0d1117">2</text>
114
+ <text x="476" y="441" class="label" style="font-size: 17px">Add local MCP retrieval</text>
115
+ <text x="442" y="463" class="body">Reaches the whole indexed vault on demand.</text>
116
+
117
+ <rect x="442" y="475" width="92" height="48" rx="10" fill="#1e293b" stroke="#475569"/>
118
+ <text x="488" y="505" text-anchor="middle" class="label">AI client</text>
119
+ <path d="M534 499H578" fill="none" stroke="#60a5fa" stroke-width="2.5" marker-end="url(#arrow-blue)"/>
120
+ <text x="559" y="489" text-anchor="middle" class="body">stdio</text>
121
+ <rect x="584" y="470" width="152" height="62" rx="10" fill="#161b22" stroke="#3b82f6"/>
122
+ <text x="660" y="492" text-anchor="middle" class="mono">skillmux serve</text>
123
+ <text x="660" y="511" text-anchor="middle" class="body">default: FTS5 +</text>
124
+ <text x="660" y="527" text-anchor="middle" class="body">local GTE-small</text>
125
+
126
+ </g>
127
+
128
+ <g filter="url(#shadow)">
129
+ <rect x="800" y="284" width="360" height="302" rx="18" fill="#161b22" stroke="#7c3aed" stroke-width="2"/>
130
+ <rect x="822" y="306" width="136" height="26" rx="13" fill="#312e81"/>
131
+ <text x="890" y="324" text-anchor="middle" class="chip" fill="#c4b5fd">SKILLMUX SERVER</text>
132
+ <circle cx="833" cy="358" r="11" fill="#a78bfa"/>
133
+ <text x="833" y="362.5" text-anchor="middle" style="font-size: 13px; font-weight: 750" fill="#0d1117">3</text>
134
+ <text x="856" y="365" class="card-title">Run a shared MCP service</text>
135
+ <text x="822" y="390" class="body">Read a server checkout to serve several clients.</text>
136
+
137
+ <rect x="822" y="414" width="92" height="48" rx="10" fill="#1e293b" stroke="#475569"/>
138
+ <text x="868" y="435" text-anchor="middle" class="label">AI clients</text>
139
+ <text x="868" y="453" text-anchor="middle" class="body">one or more</text>
140
+ <path d="M914 438H963" fill="none" stroke="#a78bfa" stroke-width="2.5" marker-end="url(#arrow-violet)"/>
141
+ <text x="939" y="428" text-anchor="middle" class="body">HTTP</text>
142
+ <rect x="969" y="414" width="169" height="48" rx="10" fill="#2e1065" stroke="#7c3aed"/>
143
+ <text x="1053.5" y="435" text-anchor="middle" class="label">Skillmux server</text>
144
+ <text x="1053.5" y="453" text-anchor="middle" class="body" style="font-size: 13px">Streamable HTTP /mcp</text>
145
+
146
+ <rect x="822" y="484" width="148" height="58" rx="10" fill="#2e1065" stroke="#7c3aed"/>
147
+ <text x="896" y="507" text-anchor="middle" class="label">Full image</text>
148
+ <text x="896" y="530" text-anchor="middle" class="body">GTE-small included</text>
149
+ <rect x="982" y="484" width="156" height="58" rx="10" fill="#1e293b" stroke="#475569"/>
150
+ <text x="1060" y="507" text-anchor="middle" class="label">Slim image</text>
151
+ <text x="1060" y="530" text-anchor="middle" class="body">remote or lexical</text>
152
+
153
+ <text x="822" y="570" class="body">Full image is the default deployment.</text>
154
+ </g>
155
+
156
+ <rect x="420" y="608" width="740" height="82" rx="14" fill="#1e293b"/>
157
+ <text x="444" y="633" class="chip" fill="#cbd5e1">MCP TOOL CONTRACT · STDIO + HTTP</text>
158
+ <text x="444" y="655" class="mono mono-light" style="font-size: 12px">resolve_skill → lexical + vector → RRF → optional rerank → top_k → ranked candidates</text>
159
+ <text x="444" y="677" class="mono mono-light" style="font-size: 12px">fetch_skill → current SKILL.md bytes + SHA-256</text>
160
+ </svg>
@@ -1,6 +1,6 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 720" role="img" aria-labelledby="title desc">
2
2
  <title id="title">One vault source of truth, three ways to use Skillmux</title>
3
- <desc id="desc">One Git-backed vault source of truth has a client checkout for Skillmux CLI native management and local MCP retrieval, plus a server checkout for shared Streamable HTTP MCP. Resolve uses retrieval, fusion, and optional reranking; fetch returns the current SKILL.md directly. Git and deployment own checkout replication and freshness.</desc>
3
+ <desc id="desc">One Git-backed vault source of truth holds one SKILL.md per child directory and feeds a client checkout and a server checkout. On a client machine, Skillmux CLI manages native skills and serves local stdio MCP; a server checkout serves shared Streamable HTTP MCP. resolve_skill fuses lexical and vector results and optionally reranks them; fetch_skill returns the current SKILL.md bytes with a SHA-256. Git and deployment own checkout replication and freshness.</desc>
4
4
 
5
5
  <defs>
6
6
  <filter id="shadow" x="-15%" y="-15%" width="130%" height="140%">
@@ -68,14 +68,14 @@
68
68
  <text x="48" y="78" class="subtitle">Git and deployment replicate checkouts; Skillmux uses each checkout where it runs.</text>
69
69
 
70
70
  <g filter="url(#shadow)">
71
- <rect x="330" y="106" width="540" height="118" rx="18" fill="#ffffff" stroke="#cbd5e1" stroke-width="2"/>
72
- <circle cx="374" cy="147" r="18" fill="#0f172a"/>
73
- <path d="M364 141H377L383 147L377 153H364M370 135V159" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
74
- <text x="408" y="144" class="card-title">Git-backed vault source of truth</text>
75
- <text x="408" y="172" class="mono">logical SKILL.md collection</text>
76
- <text x="408" y="200" class="body">Git + deployment own replication and freshness</text>
77
- <rect x="701" y="139" width="137" height="34" rx="9" fill="#f1f5f9" stroke="#cbd5e1"/>
78
- <text x="769.5" y="161" text-anchor="middle" class="mono">skillmux.toml</text>
71
+ <rect x="280" y="106" width="640" height="118" rx="18" fill="#ffffff" stroke="#cbd5e1" stroke-width="2"/>
72
+ <circle cx="324" cy="147" r="18" fill="#0f172a"/>
73
+ <path d="M314 141H327L333 147L327 153H314M320 135V159" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
74
+ <text x="358" y="144" class="card-title">Git-backed vault source of truth</text>
75
+ <text x="358" y="172" class="mono">SKILL.md per child directory</text>
76
+ <text x="358" y="200" class="body">A checkout is a physical copy of it on one machine.</text>
77
+ <rect x="751" y="155" width="137" height="34" rx="9" fill="#f1f5f9" stroke="#cbd5e1"/>
78
+ <text x="819.5" y="177" text-anchor="middle" class="mono">skillmux.toml</text>
79
79
  </g>
80
80
 
81
81
  <path d="M520 224V252H410V277" fill="none" stroke="#0f766e" stroke-width="3" marker-end="url(#arrow-teal)"/>
@@ -87,11 +87,13 @@
87
87
  <rect x="40" y="284" width="740" height="302" rx="18" fill="#ffffff" stroke="#99d5cc" stroke-width="2"/>
88
88
  <rect x="62" y="306" width="124" height="26" rx="13" fill="#ccfbf1"/>
89
89
  <text x="124" y="324" text-anchor="middle" class="chip" fill="#115e59">SKILLMUX CLI</text>
90
- <text x="62" y="365" class="card-title">Skillmux CLI</text>
91
- <text x="62" y="390" class="body">A client-machine checkout supports native management and/or local MCP.</text>
90
+ <text x="62" y="365" class="card-title">On one client machine</text>
91
+ <text x="62" y="390" class="body">Manage native skills, add local MCP retrieval, or do both.</text>
92
92
 
93
93
  <rect x="62" y="414" width="276" height="48" rx="10" fill="#f0fdfa" stroke="#99d5cc"/>
94
- <text x="200" y="435" text-anchor="middle" class="label">Native management</text>
94
+ <circle cx="85" cy="438" r="11" fill="#0f766e"/>
95
+ <text x="85" y="442.5" text-anchor="middle" style="font-size: 13px; font-weight: 750" fill="#ffffff">1</text>
96
+ <text x="200" y="433" text-anchor="middle" class="label" style="font-size: 17px">Manage native skills</text>
95
97
  <text x="200" y="453" text-anchor="middle" class="mono">skillmux init · sync</text>
96
98
  <path d="M200 462V487" fill="none" stroke="#0f766e" stroke-width="2.5" marker-end="url(#arrow-teal)"/>
97
99
  <rect x="62" y="493" width="276" height="49" rx="10" fill="#f8fafc" stroke="#cbd5e1"/>
@@ -107,17 +109,19 @@
107
109
 
108
110
  <g filter="url(#shadow)">
109
111
  <rect x="420" y="414" width="338" height="128" rx="10" fill="#eff6ff" stroke="#93c5fd"/>
110
- <text x="442" y="441" class="label">Local MCP retrieval</text>
111
- <text x="442" y="463" class="body">Skillmux CLI beside one MCP client.</text>
112
-
113
- <rect x="442" y="475" width="102" height="48" rx="10" fill="#f8fafc" stroke="#cbd5e1"/>
114
- <text x="493" y="505" text-anchor="middle" class="label">AI client</text>
115
- <path d="M544 499H573" fill="none" stroke="#2563eb" stroke-width="2.5" marker-end="url(#arrow-blue)"/>
116
- <text x="558" y="489" text-anchor="middle" class="body">stdio</text>
117
- <rect x="579" y="470" width="157" height="62" rx="10" fill="#ffffff" stroke="#93c5fd"/>
118
- <text x="657.5" y="492" text-anchor="middle" class="label">Skillmux CLI</text>
119
- <text x="657.5" y="511" text-anchor="middle" class="body">default: FTS5 +</text>
120
- <text x="657.5" y="527" text-anchor="middle" class="body">local GTE-small</text>
112
+ <circle cx="453" cy="435" r="11" fill="#2563eb"/>
113
+ <text x="453" y="439.5" text-anchor="middle" style="font-size: 13px; font-weight: 750" fill="#ffffff">2</text>
114
+ <text x="476" y="441" class="label" style="font-size: 17px">Add local MCP retrieval</text>
115
+ <text x="442" y="463" class="body">Reaches the whole indexed vault on demand.</text>
116
+
117
+ <rect x="442" y="475" width="92" height="48" rx="10" fill="#f8fafc" stroke="#cbd5e1"/>
118
+ <text x="488" y="505" text-anchor="middle" class="label">AI client</text>
119
+ <path d="M534 499H578" fill="none" stroke="#2563eb" stroke-width="2.5" marker-end="url(#arrow-blue)"/>
120
+ <text x="559" y="489" text-anchor="middle" class="body">stdio</text>
121
+ <rect x="584" y="470" width="152" height="62" rx="10" fill="#ffffff" stroke="#93c5fd"/>
122
+ <text x="660" y="492" text-anchor="middle" class="mono">skillmux serve</text>
123
+ <text x="660" y="511" text-anchor="middle" class="body">default: FTS5 +</text>
124
+ <text x="660" y="527" text-anchor="middle" class="body">local GTE-small</text>
121
125
 
122
126
  </g>
123
127
 
@@ -125,17 +129,19 @@
125
129
  <rect x="800" y="284" width="360" height="302" rx="18" fill="#ffffff" stroke="#c4b5fd" stroke-width="2"/>
126
130
  <rect x="822" y="306" width="136" height="26" rx="13" fill="#ede9fe"/>
127
131
  <text x="890" y="324" text-anchor="middle" class="chip" fill="#6d28d9">SKILLMUX SERVER</text>
128
- <text x="822" y="365" class="card-title">Run a shared MCP service</text>
132
+ <circle cx="833" cy="358" r="11" fill="#7c3aed"/>
133
+ <text x="833" y="362.5" text-anchor="middle" style="font-size: 13px; font-weight: 750" fill="#ffffff">3</text>
134
+ <text x="856" y="365" class="card-title">Run a shared MCP service</text>
129
135
  <text x="822" y="390" class="body">Read a server checkout to serve several clients.</text>
130
136
 
131
- <rect x="822" y="414" width="102" height="48" rx="10" fill="#f8fafc" stroke="#cbd5e1"/>
132
- <text x="873" y="435" text-anchor="middle" class="label">AI clients</text>
133
- <text x="873" y="453" text-anchor="middle" class="body">one or more</text>
134
- <path d="M924 438H953" fill="none" stroke="#7c3aed" stroke-width="2.5" marker-end="url(#arrow-violet)"/>
135
- <text x="938" y="428" text-anchor="middle" class="body">HTTP</text>
136
- <rect x="959" y="414" width="179" height="48" rx="10" fill="#f5f3ff" stroke="#c4b5fd"/>
137
- <text x="1048.5" y="435" text-anchor="middle" class="label">Skillmux server</text>
138
- <text x="1048.5" y="453" text-anchor="middle" class="body" style="font-size: 13px">Streamable HTTP /mcp</text>
137
+ <rect x="822" y="414" width="92" height="48" rx="10" fill="#f8fafc" stroke="#cbd5e1"/>
138
+ <text x="868" y="435" text-anchor="middle" class="label">AI clients</text>
139
+ <text x="868" y="453" text-anchor="middle" class="body">one or more</text>
140
+ <path d="M914 438H963" fill="none" stroke="#7c3aed" stroke-width="2.5" marker-end="url(#arrow-violet)"/>
141
+ <text x="939" y="428" text-anchor="middle" class="body">HTTP</text>
142
+ <rect x="969" y="414" width="169" height="48" rx="10" fill="#f5f3ff" stroke="#c4b5fd"/>
143
+ <text x="1053.5" y="435" text-anchor="middle" class="label">Skillmux server</text>
144
+ <text x="1053.5" y="453" text-anchor="middle" class="body" style="font-size: 13px">Streamable HTTP /mcp</text>
139
145
 
140
146
  <rect x="822" y="484" width="148" height="58" rx="10" fill="#f5f3ff" stroke="#c4b5fd"/>
141
147
  <text x="896" y="507" text-anchor="middle" class="label">Full image</text>
@@ -144,11 +150,11 @@
144
150
  <text x="1060" y="507" text-anchor="middle" class="label">Slim image</text>
145
151
  <text x="1060" y="530" text-anchor="middle" class="body">remote or lexical</text>
146
152
 
147
- <text x="822" y="570" class="body">Recommended for a shared HTTP deployment</text>
153
+ <text x="822" y="570" class="body">Full image is the default deployment.</text>
148
154
  </g>
149
155
 
150
156
  <rect x="420" y="608" width="740" height="82" rx="14" fill="#0f172a"/>
151
157
  <text x="444" y="633" class="chip" fill="#cbd5e1">MCP TOOL CONTRACT · STDIO + HTTP</text>
152
158
  <text x="444" y="655" class="mono mono-light" style="font-size: 12px">resolve_skill → lexical + vector → RRF → optional rerank → top_k → ranked candidates</text>
153
- <text x="444" y="677" class="mono mono-light" style="font-size: 12px">fetch_skill → exact current SKILL.md + SHA-256</text>
159
+ <text x="444" y="677" class="mono mono-light" style="font-size: 12px">fetch_skill → current SKILL.md bytes + SHA-256</text>
154
160
  </svg>
Binary file
Binary file
package/docs/cli.md CHANGED
@@ -21,10 +21,11 @@ or [Managing skills](skill-management.md).
21
21
 
22
22
  The Docker image is a shared-server runtime, not a replacement for the host
23
23
  CLI. Its `skillmux --help` surface is intentionally limited to `serve`,
24
- `index`, `doctor`, `report`, `scan`, `skill which`, and read-only `config`
25
- inspection (`show`, `get`, `validate`, `diff`, and `status`). Run `init`,
26
- `install`, pinning, `sync`, project or target management, model downloads,
27
- contexts, evaluation, and configuration changes on the host.
24
+ `index`, `doctor`, `report`, `audit prune`, `eval promote`, `scan`,
25
+ `skill which`, and read-only `config` inspection (`show`, `get`, `validate`,
26
+ `diff`, and `status`). Run `init`, `install`, pinning, `sync`, project or
27
+ target management, model downloads, contexts, and bare `eval` (vault ranking
28
+ evaluation, which needs local embeddings and the vault) on the host.
28
29
 
29
30
  When the image rejects one of those commands, it exits with code 2. JSON mode
30
31
  uses `CONTAINER_COMMAND_UNSUPPORTED` and includes `rejected_command`,
@@ -247,7 +248,7 @@ command prints the preserved path so cleanup remains an explicit user action.
247
248
 
248
249
  ## Core skills (`skillmux core`)
249
250
 
250
- Pin or unpin skills into `[core]` the tier every target receives by
251
+ Pin or unpin skills into `[core]`, the tier every target receives by
251
252
  default, capped at 25 skills:
252
253
 
253
254
  ```sh
@@ -287,6 +288,63 @@ skillmux skill which csv-formatter
287
288
 
288
289
  ---
289
290
 
291
+ ## Observability and evaluation (`skillmux report`, `audit`, `eval`)
292
+
293
+ `resolve_skill` records every request to an audit log; `fetch_skill` records
294
+ what was actually opened and, when the caller passes back the `request_id`
295
+ from a prior resolve, correlates the fetch to that resolve and its rank in
296
+ the shortlist. `skillmux report` summarizes this data, `skillmux audit prune`
297
+ reclaims space, and `skillmux eval promote` turns correlated fetches into
298
+ eval cases.
299
+
300
+ ```sh
301
+ # Summarize activity from the local state or a remote server
302
+ skillmux report --since 7d
303
+ skillmux report --server https://skillmux.internal:3000 --since 24h
304
+ skillmux report --db ~/.local/state/skillmux/audit.sqlite3 --since 2026-08-01
305
+
306
+ # Prune audit rows older than the configured retention window (default 90 days)
307
+ skillmux audit prune --yes
308
+ skillmux audit prune --older-than 30d --dry-run
309
+ skillmux audit prune --older-than 30d --json
310
+
311
+ # Promote observed, correlated fetches into an eval case file
312
+ skillmux eval promote --since 7d --dry-run
313
+ skillmux eval promote --since 7d --yes
314
+ skillmux eval promote --since 7d --target eval/observed.json --yes
315
+ ```
316
+
317
+ `report` reads `--server <url>`, `--db <path>` (an explicit SQLite file,
318
+ opened read-only), or the configured local `state_dir` by default;
319
+ `--server` and `--db` are mutually exclusive. Alongside request totals,
320
+ empty-shortlist rate, retrieval-lane totals, degradation counts, and
321
+ per-skill candidate counts, `report` prints an acceptance signal derived
322
+ from correlated fetches: `acceptance_rate`, `observed_mrr` (reciprocal rank
323
+ of the first fetched candidate), and `top1_acceptance_rate`, each computed
324
+ over resolves that returned at least one candidate. When a window has no
325
+ correlated fetches, `report` marks the signal `unavailable` and states the
326
+ uncorrelated fetch count instead of printing a misleading `0.000`. It also
327
+ lists the top queries that returned candidates but received no correlated
328
+ fetch, distinct from the existing top empty-shortlist list.
329
+
330
+ `audit prune` deletes resolve and fetch rows older than `--older-than` (same
331
+ window syntax as `--since`), or `audit.retention_days` from configuration
332
+ (default 90; `0` disables pruning). `--dry-run` reports counts without
333
+ writing. Non-interactive runs require `--yes`. The server also prunes
334
+ automatically once at startup and at most once per 24 hours while running;
335
+ manual pruning is for on-demand cleanup or a tighter window.
336
+
337
+ `eval promote` reads correlated fetches since `--since`, deduplicates them by
338
+ normalized query, and writes `{ query, split: "observed", relevant_skill_ids
339
+ }` cases to `--target` (default an `eval-observed.json` file under
340
+ `state_dir`; never the hand-curated `eval/queries.json` unless given
341
+ explicitly). It never rewrites a case for a query already present in the
342
+ target file; skipped counts are reported in the summary. Because promoted
343
+ cases carry raw user queries, `eval promote` always prints a stderr warning.
344
+ Both `--dry-run` and `--yes` behave as elsewhere in the CLI.
345
+
346
+ ---
347
+
290
348
  ## Administrative HTTP API (`/admin/v1/*`)
291
349
 
292
350
  The HTTP server has two separate surfaces:
package/docs/concepts.md CHANGED
@@ -63,6 +63,16 @@ checkout over HTTP.
63
63
 
64
64
  ## Deployment topologies
65
65
 
66
+ ```mermaid
67
+ flowchart TD
68
+ V[Git-backed vault source of truth]
69
+ V -->|client checkout| CLI[Skillmux CLI]
70
+ V -->|server checkout| SRV[Skillmux server]
71
+ CLI --> NM[Native management: filesystem links]
72
+ CLI --> LM[Local MCP: stdio]
73
+ SRV --> SM[Shared MCP: Streamable HTTP]
74
+ ```
75
+
66
76
  | Topology | Process location | Transport | Typical installation |
67
77
  | --- | --- | --- | --- |
68
78
  | Native management | Client machine | Filesystem links | Skillmux CLI |