@klhapp/skillmux 1.2.0 → 1.3.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 +12 -0
- package/README.md +155 -521
- package/config.example.toml +5 -4
- package/config.remote.example.toml +5 -2
- package/docs/README.md +52 -0
- package/docs/assets/architecture.svg +156 -0
- package/docs/assets/logo.png +0 -0
- package/docs/calibration.md +6 -1
- package/docs/cli.md +350 -0
- package/docs/concepts.md +165 -0
- package/docs/configuration.md +34 -10
- package/docs/deployment.md +250 -0
- package/docs/getting-started.md +239 -0
- package/docs/mcp-routing.md +172 -0
- package/docs/releasing.md +4 -3
- package/docs/skill-management.md +209 -0
- package/docs/troubleshooting.md +199 -0
- package/package.json +3 -6
- package/src/cli.ts +39 -2
- package/src/config-watcher.ts +5 -1
package/README.md
CHANGED
|
@@ -2,617 +2,251 @@
|
|
|
2
2
|
<img src="https://raw.githubusercontent.com/klhq/skillmux/main/docs/assets/logo.png" alt="skillmux" width="400">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
A local, read-only [MCP](https://modelcontextprotocol.io) stdio server that gives agents **on-demand skill discovery**: route a natural-language task description to the right skill in your vault and deliver its `SKILL.md` byte-for-byte, verified by SHA-256.
|
|
6
|
-
|
|
7
|
-
Built for agents that lack native skill triggering (Goose recipe workers, opencode, and friends). Agents that already trigger skills natively (e.g. Claude Code) don't need it.
|
|
8
|
-
|
|
9
|
-
- [How it works](#how-it-works)
|
|
10
|
-
- [Tiers: routed vs. pinned](#tiers-routed-vs-pinned)
|
|
11
|
-
- [Install](#install)
|
|
12
|
-
- [Quick start](#quick-start) — the fastest path to seeing it respond
|
|
13
|
-
- [Pinning skills across surfaces](#pinning-skills-across-surfaces) — optional: statically load a curated set across multiple agents
|
|
14
|
-
- [Docker Usage](#docker-usage)
|
|
15
|
-
- [Configuration](#configuration) — inference modes, security scanning, installing skills, env vars
|
|
16
|
-
- [CLI & Automation](docs/cli.md) — context management, remote target resolution, policy calibration, JSON envelopes
|
|
17
|
-
- [Policy Calibration](docs/calibration.md) — labelled datasets, certification, apply lifecycle, and reference profile
|
|
18
|
-
- [Benchmarks & Evaluation](#benchmarks--evaluation)
|
|
19
|
-
- [FAQ & Troubleshooting](#faq--troubleshooting)
|
|
20
|
-
- [Guarantees](#guarantees)
|
|
21
|
-
- [Development](#development)
|
|
22
|
-
|
|
23
|
-
## How it works
|
|
24
|
-
|
|
25
5
|
<p align="center">
|
|
26
|
-
<
|
|
6
|
+
<a href="https://github.com/klhq/skillmux/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/klhq/skillmux/actions/workflows/ci.yml/badge.svg"></a>
|
|
7
|
+
<a href="https://github.com/klhq/skillmux/releases/latest"><img alt="GitHub release" src="https://img.shields.io/github/v/release/klhq/skillmux"></a>
|
|
8
|
+
<a href="https://www.npmjs.com/package/@klhapp/skillmux"><img alt="npm" src="https://img.shields.io/npm/v/@klhapp/skillmux"></a>
|
|
9
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
|
|
27
10
|
</p>
|
|
28
11
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
▼
|
|
33
|
-
hybrid recall: SQLite FTS5 (BM25) ∪ embedding cosine (brute-force)
|
|
34
|
-
│
|
|
35
|
-
▼
|
|
36
|
-
reciprocal-rank fusion → shortlist
|
|
37
|
-
optional reranker → matched | ambiguous | no_match
|
|
38
|
-
```
|
|
12
|
+
Skillmux manages [`SKILL.md`](https://agentskills.io) collections across AI
|
|
13
|
+
coding clients. Keep one canonical vault, pin a small set into native skill
|
|
14
|
+
directories, and retrieve the rest through MCP.
|
|
39
15
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- **no_match** — proceed under your normal workflow; don't load an unrelated skill.
|
|
16
|
+
The same Skillmux CLI manages native skills and can serve local stdio MCP.
|
|
17
|
+
Choose a setup by the job:
|
|
43
18
|
|
|
44
|
-
|
|
19
|
+
1. Need native skills or local MCP for one client? Install the **Skillmux CLI**.
|
|
20
|
+
2. On Linux without Bun? Install the standalone Linux executable instead; it is
|
|
21
|
+
the same CLI.
|
|
22
|
+
3. Need one shared HTTP MCP service? Deploy the **full Docker image**—the
|
|
23
|
+
self-contained default with GTE-small.
|
|
24
|
+
4. Already have remote embeddings, or intentionally want lexical-only
|
|
25
|
+
retrieval? Use the **slim** image; see [Deployment](docs/deployment.md).
|
|
26
|
+
5. Need native pins and shared retrieval? Run the CLI on the machines that own
|
|
27
|
+
client directories and one shared server for routed retrieval.
|
|
45
28
|
|
|
46
|
-
|
|
29
|
+
A shared service focuses on routed retrieval; manage its mounted vault on the
|
|
30
|
+
host with the CLI.
|
|
47
31
|
|
|
48
|
-
|
|
49
|
-
| --------------- | ---------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
50
|
-
| `resolve_skill` | `query` | outcome + metadata in `structuredContent`; on match the verbatim body as text content (exactly once on the wire) |
|
|
51
|
-
| `fetch_skill` | `skill_id` | verbatim body, `content_sha256`, supporting-file paths |
|
|
32
|
+
## One vault, three ways to use it
|
|
52
33
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
34
|
+
<p align="center">
|
|
35
|
+
<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%">
|
|
36
|
+
</p>
|
|
56
37
|
|
|
57
|
-
|
|
38
|
+
“Local” describes where Skillmux runs. “Local inference” means the embedding
|
|
39
|
+
model runs in the Skillmux process. Both stdio and HTTP expose the same
|
|
40
|
+
`resolve_skill` and `fetch_skill` MCP tools.
|
|
58
41
|
|
|
59
|
-
|
|
60
|
-
- **pinned** (`core` / `project`) — a small, hand-picked set of skills symlinked directly into an agent's own skill directory (e.g. `~/.claude/skills`), so they load the same way any other skill on that agent does — no MCP round-trip, no query. `core` pins apply everywhere; `project` pins apply only inside one repo.
|
|
42
|
+
## Install the CLI
|
|
61
43
|
|
|
62
|
-
|
|
44
|
+
The Bun package supports macOS, Linux, and Windows and requires
|
|
45
|
+
[Bun 1.3 or newer](https://bun.sh/docs/installation):
|
|
63
46
|
|
|
64
|
-
|
|
47
|
+
```sh
|
|
48
|
+
bun add -g @klhapp/skillmux
|
|
49
|
+
skillmux --help
|
|
50
|
+
```
|
|
65
51
|
|
|
66
|
-
|
|
52
|
+
Native target sync needs permission to create directory symlinks on Windows.
|
|
67
53
|
|
|
68
|
-
|
|
54
|
+
On Linux, you can install a compiled AMD64 or ARM64 binary instead:
|
|
69
55
|
|
|
70
56
|
```sh
|
|
71
|
-
|
|
72
|
-
gh release download --repo klhq/skillmux \
|
|
73
|
-
--pattern 'skillmux-linux-*'
|
|
74
|
-
|
|
75
|
-
# Optional: verify build provenance
|
|
57
|
+
gh release download --repo klhq/skillmux --pattern 'skillmux-linux-*'
|
|
76
58
|
gh attestation verify skillmux-linux-amd64 --repo klhq/skillmux
|
|
77
|
-
|
|
78
|
-
# Install the binary matching your machine (amd64 or arm64)
|
|
79
59
|
chmod +x skillmux-linux-amd64
|
|
80
60
|
sudo install skillmux-linux-amd64 /usr/local/bin/skillmux
|
|
81
|
-
skillmux config show
|
|
82
61
|
```
|
|
83
62
|
|
|
84
|
-
|
|
63
|
+
Use `skillmux-linux-arm64` on ARM64. See [Deployment](docs/deployment.md) for
|
|
64
|
+
the full and slim Docker images.
|
|
85
65
|
|
|
86
|
-
|
|
66
|
+
## Quick starts
|
|
87
67
|
|
|
88
|
-
|
|
89
|
-
- Optional remote OpenAI-compatible embeddings and Infinity-native reranking. The full binary uses local GTE-small embeddings by default.
|
|
68
|
+
Skillmux uses `~/skills` as its default vault:
|
|
90
69
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
### 1. Put a skill in your vault
|
|
96
|
-
|
|
97
|
-
A skill is just a directory with a `SKILL.md`. Author one by hand to try against:
|
|
98
|
-
|
|
99
|
-
```sh
|
|
100
|
-
mkdir -p ~/skills/csv-formatter
|
|
101
|
-
cat > ~/skills/csv-formatter/SKILL.md <<'EOF'
|
|
102
|
-
---
|
|
103
|
-
name: CSV Formatter
|
|
104
|
-
description: Converts CSV or spreadsheet data into clean, aligned Markdown tables. Use whenever the user asks to convert, format, or clean up tabular/CSV/spreadsheet data into Markdown.
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
# CSV Formatter
|
|
108
|
-
|
|
109
|
-
Given raw CSV input, emit a well-aligned Markdown table: infer column headers
|
|
110
|
-
from the first row, right-align numeric columns, left-align text columns.
|
|
111
|
-
EOF
|
|
70
|
+
```text
|
|
71
|
+
~/skills/
|
|
72
|
+
└── csv-formatter/
|
|
73
|
+
└── SKILL.md
|
|
112
74
|
```
|
|
113
75
|
|
|
114
|
-
|
|
76
|
+
### Manage native skills
|
|
115
77
|
|
|
116
|
-
|
|
78
|
+
Run the setup planner, then verify its managed links:
|
|
117
79
|
|
|
118
80
|
```sh
|
|
119
|
-
skillmux
|
|
81
|
+
skillmux init
|
|
82
|
+
skillmux sync
|
|
120
83
|
skillmux doctor
|
|
121
84
|
```
|
|
122
85
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
### 3. Serve it
|
|
86
|
+
The planner detects clients, asks which skills belong in the core tier, and
|
|
87
|
+
shows every write before confirmation. Use explicit flags for automation:
|
|
126
88
|
|
|
127
89
|
```sh
|
|
128
|
-
skillmux
|
|
129
|
-
|
|
90
|
+
skillmux init \
|
|
91
|
+
--client claude-code \
|
|
92
|
+
--client codex \
|
|
93
|
+
--core csv-formatter \
|
|
94
|
+
--dry-run
|
|
130
95
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
"skillmux": {
|
|
137
|
-
"command": "skillmux",
|
|
138
|
-
"args": ["serve"]
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
96
|
+
skillmux init \
|
|
97
|
+
--client claude-code \
|
|
98
|
+
--client codex \
|
|
99
|
+
--core csv-formatter \
|
|
100
|
+
--yes
|
|
142
101
|
```
|
|
143
102
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
To see `resolve_skill` respond without wiring up a client, run the HTTP transport instead (`skillmux serve --transport http`, default port `3000`) and speak MCP's Streamable HTTP protocol directly:
|
|
147
|
-
|
|
148
|
-
```sh
|
|
149
|
-
# 1. Initialize a session, capture the session id from the response header
|
|
150
|
-
SESSION=$(curl -sS -D - -o /dev/null http://127.0.0.1:3000/mcp \
|
|
151
|
-
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
|
|
152
|
-
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"try-it","version":"1.0.0"}}}' \
|
|
153
|
-
| grep -i '^mcp-session-id:' | tr -d '\r' | cut -d' ' -f2)
|
|
154
|
-
|
|
155
|
-
# 2. Complete the handshake
|
|
156
|
-
curl -sS -o /dev/null -X POST http://127.0.0.1:3000/mcp \
|
|
157
|
-
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
|
|
158
|
-
-H "mcp-session-id: $SESSION" \
|
|
159
|
-
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}'
|
|
160
|
-
|
|
161
|
-
# 3. Call resolve_skill
|
|
162
|
-
curl -sS -X POST http://127.0.0.1:3000/mcp \
|
|
163
|
-
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
|
|
164
|
-
-H "mcp-session-id: $SESSION" \
|
|
165
|
-
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"resolve_skill","arguments":{"query":"convert this spreadsheet to markdown"}}}'
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Against the `csv-formatter` skill authored above, that returns a real match — trimmed here for length:
|
|
169
|
-
|
|
170
|
-
```json
|
|
171
|
-
{
|
|
172
|
-
"result": {
|
|
173
|
-
"structuredContent": {
|
|
174
|
-
"outcome": "ambiguous",
|
|
175
|
-
"retrieval": "hybrid",
|
|
176
|
-
"candidates": [
|
|
177
|
-
{
|
|
178
|
-
"skill_id": "csv-formatter",
|
|
179
|
-
"title": "CSV Formatter",
|
|
180
|
-
"description": "Converts CSV or spreadsheet data..."
|
|
181
|
-
}
|
|
182
|
-
]
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
`outcome` is `"ambiguous"` here specifically because the vault only has one skill in it — with more skills installed, a clear top match returns `"matched"` with the full `SKILL.md` body inline instead of a candidate list.
|
|
189
|
-
|
|
190
|
-
### Run from source instead
|
|
191
|
-
|
|
192
|
-
```sh
|
|
193
|
-
bun install --frozen-lockfile
|
|
194
|
-
bun run src/cli.ts index
|
|
195
|
-
bun run src/cli.ts serve
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
## Pinning skills across surfaces
|
|
199
|
-
|
|
200
|
-
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).
|
|
201
|
-
|
|
202
|
-
Run `skillmux init` with no arguments in a terminal for guided setup. It checks
|
|
203
|
-
the vault, preselects clients with concrete filesystem evidence, asks for core
|
|
204
|
-
skills, shows one review, and applies after one confirmation. The wizard uses
|
|
205
|
-
line-oriented prompts and does not take over the terminal screen.
|
|
206
|
-
|
|
207
|
-
### 1. Check the plan
|
|
208
|
-
|
|
209
|
-
```sh
|
|
210
|
-
skillmux init --client claude-code --client codex --core csv-formatter --dry-run
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
`--client` names the tool you use. Skillmux maps it to the correct user-level
|
|
214
|
-
skill directory and merges clients that share one directory. Gemini CLI,
|
|
215
|
-
OpenCode, GitHub Copilot, and Windsurf share `~/.agents/skills`. Claude Code
|
|
216
|
-
uses `~/.claude/skills`; Codex uses `$CODEX_HOME/skills` or
|
|
217
|
-
`~/.codex/skills`.
|
|
218
|
-
|
|
219
|
-
Supported clients are `claude-code`, `codex`, `gemini-cli`, `opencode`,
|
|
220
|
-
`github-copilot`, `windsurf`, `antigravity`, `goose`, `hermes`, and
|
|
221
|
-
`skillmux-mcp`. Goose, Hermes, and Skillmux MCP report the manual registration
|
|
222
|
-
work they need instead of inventing a target directory.
|
|
223
|
-
|
|
224
|
-
The dry run prints target classification, config changes, instruction-file
|
|
225
|
-
changes, readiness, and core pins. It does not prompt or write.
|
|
226
|
-
|
|
227
|
-
### 2. Apply the plan
|
|
228
|
-
|
|
229
|
-
```sh
|
|
230
|
-
skillmux init --client claude-code --client codex --core csv-formatter --yes
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
Skillmux writes `skillmux.toml`, adds host-scoped targets, adopts each selected
|
|
234
|
-
directory, and installs one managed discovery block for each client with a
|
|
235
|
-
known safe durable instruction file. Other clients report manual setup.
|
|
236
|
-
Existing manifest entries and instruction text stay intact.
|
|
237
|
-
Explicit flags keep the command deterministic. Without `--yes`, an interactive
|
|
238
|
-
terminal reviews the plan before applying; a pipe or CI job must pass `--yes`.
|
|
239
|
-
Use `--no-instructions` to leave instruction files untouched or `--no-sync` to
|
|
240
|
-
save setup for a later `skillmux sync`.
|
|
241
|
-
|
|
242
|
-
Use direct targets when you want paths rather than clients:
|
|
243
|
-
|
|
244
|
-
```sh
|
|
245
|
-
skillmux init --target agent-skills --yes
|
|
246
|
-
skillmux init --target claude-code --yes
|
|
247
|
-
skillmux init --target codex --yes
|
|
248
|
-
skillmux init --target custom --dir /srv/my-agent/skills --yes
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
The old `agents` and `claude` target names still work and print a deprecation
|
|
252
|
-
warning. Skillmux keeps those names in an existing manifest.
|
|
253
|
-
|
|
254
|
-
If a target points at the whole vault, Skillmux classifies it as `full-vault`
|
|
255
|
-
and refuses managed-pin adoption. Review the visibility change before
|
|
256
|
-
converting it:
|
|
257
|
-
|
|
258
|
-
```sh
|
|
259
|
-
skillmux init --client claude-code --migrate-full-vault \
|
|
260
|
-
--core csv-formatter --dry-run
|
|
261
|
-
skillmux init --client claude-code --migrate-full-vault \
|
|
262
|
-
--core csv-formatter --yes
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
After conversion and `skillmux sync`, the client sees the selected core pins
|
|
266
|
-
instead of every vault skill.
|
|
267
|
-
|
|
268
|
-
### 3. Set up project-scoped skills
|
|
269
|
-
|
|
270
|
-
From a project directory:
|
|
103
|
+
Core pins apply to each configured target and stay capped at 25 skills. Add
|
|
104
|
+
project-specific skills from a repository root:
|
|
271
105
|
|
|
272
106
|
```sh
|
|
273
107
|
skillmux project init
|
|
274
108
|
```
|
|
275
109
|
|
|
276
|
-
|
|
277
|
-
configured clients should receive the group, and accepts project skill IDs.
|
|
278
|
-
For automation:
|
|
279
|
-
|
|
280
|
-
```sh
|
|
281
|
-
skillmux project init ~/code/skillmux --name skillmux \
|
|
282
|
-
--client claude-code --client codex \
|
|
283
|
-
--skill sdd-tdd --skill code-context --yes
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
Re-running the command adds missing paths, skills, and target attachments
|
|
287
|
-
without duplicating existing entries. Project setup runs `sync` unless
|
|
288
|
-
`--no-sync` is supplied.
|
|
110
|
+
### Add local MCP retrieval
|
|
289
111
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
`--core` seeds only the skill IDs you name. Without it, `init` preserves
|
|
293
|
-
existing core pins and makes no guesses. Add another pin with:
|
|
112
|
+
Prefetch the default GTE-small model, index the vault, and start stdio MCP:
|
|
294
113
|
|
|
295
114
|
```sh
|
|
296
|
-
skillmux
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
```sh
|
|
302
|
-
skillmux core pin csv-formatter pdf-extractor terraform-plans --yes
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
Unpin the same way: `skillmux core unpin csv-formatter --yes` (or `skillmux core unpin csv-formatter pdf-extractor --yes` for several at once). `skillmux project pin <group> <skill_id>...` pins into an existing `[project.<group>]` tier instead — create the group first with `skillmux project add-path <group> <path> --yes` if it doesn't exist yet. Every pin is validated before writing — the skill must actually resolve from the vault, and `[core]` stays under its 25-skill cap. When multiple `skill_id`s are given, they're applied to a single in-memory manifest and written once: if any one of them is already pinned elsewhere (or already unpinned, for `unpin`), the whole call fails and nothing is written.
|
|
306
|
-
|
|
307
|
-
Hand-editing `skillmux.toml` still works if you prefer it:
|
|
308
|
-
|
|
309
|
-
```toml
|
|
310
|
-
[core]
|
|
311
|
-
skills = ["csv-formatter"]
|
|
312
|
-
|
|
313
|
-
[targets.claude]
|
|
314
|
-
dir = "/Users/you/.claude/skills"
|
|
315
|
-
host = "workhorse" # optional; sync skips this target on every other hostname
|
|
316
|
-
project_groups = []
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
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).
|
|
320
|
-
|
|
321
|
-
### 4. Materialize
|
|
322
|
-
|
|
323
|
-
```sh
|
|
324
|
-
skillmux sync
|
|
325
|
-
# claude: +1 -0
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
Each pinned skill becomes a symlink from the target dir into the vault. Re-running `sync` is idempotent (`+0 -0` once nothing changed); removing a skill from `[core]` removes its symlink on the next sync.
|
|
329
|
-
|
|
330
|
-
```sh
|
|
331
|
-
skillmux sync --dry-run # preview +added/-removed without touching disk
|
|
332
|
-
skillmux sync --install-hook # add a git post-merge hook in the vault that runs `skillmux sync` automatically
|
|
333
|
-
skillmux sync --restore-monolith # undo: replace a target dir with one symlink straight to the vault
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
`--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.
|
|
337
|
-
|
|
338
|
-
### 5. See what's actually getting used
|
|
339
|
-
|
|
340
|
-
`skillmux report` reads the same audit log `resolve_skill` writes to (see [Guarantees](#guarantees)) — useful for deciding what belongs in `[core]` versus staying routed:
|
|
341
|
-
|
|
342
|
-
```sh
|
|
343
|
-
skillmux report --since 7d # local: reads state_dir's audit db
|
|
344
|
-
skillmux report --server http://host:3000 --since 7d # remote: hits a running server's /stats
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
```
|
|
348
|
-
window: 2026-07-14T00:00:00Z .. 2026-07-21T00:00:00Z
|
|
349
|
-
outcomes: matched=0 ambiguous=2 no_match=0 (ambiguous_rate=1.000)
|
|
350
|
-
skills:
|
|
351
|
-
csv-formatter matched=0 candidate=2
|
|
352
|
-
pdf-extractor matched=0 candidate=2
|
|
353
|
-
top no_match queries:
|
|
354
|
-
(none)
|
|
115
|
+
skillmux models download
|
|
116
|
+
skillmux index
|
|
117
|
+
skillmux doctor
|
|
118
|
+
skillmux serve
|
|
355
119
|
```
|
|
356
120
|
|
|
357
|
-
|
|
121
|
+
The model cache lives at `~/.cache/skillmux/models`. If you skip the prefetch,
|
|
122
|
+
Skillmux downloads the model when local inference first needs it.
|
|
358
123
|
|
|
359
|
-
|
|
124
|
+
### Run a shared MCP service
|
|
360
125
|
|
|
361
|
-
The
|
|
362
|
-
|
|
363
|
-
1. **`skillmux:latest`**: Bundles the small quantized GTE embedding model for local hybrid retrieval.
|
|
364
|
-
2. **`skillmux:latest-slim`**: Excludes model weights and supports configured remote embeddings or lexical fallback.
|
|
365
|
-
|
|
366
|
-
Both tags are multi-architecture manifests for Linux AMD64 and ARM64; Docker selects the correct image automatically. Images are published to both [`ghcr.io/klhq/skillmux`](https://github.com/klhq/skillmux/pkgs/container/skillmux) and [`docker.io/klhq/skillmux`](https://hub.docker.com/r/klhq/skillmux) — either registry works, examples below use GHCR.
|
|
367
|
-
|
|
368
|
-
### Running HTTP Server (Docker Default)
|
|
369
|
-
|
|
370
|
-
To run as an HTTP MCP service (default in Docker):
|
|
126
|
+
The full image includes GTE-small and serves Streamable HTTP on `/mcp`:
|
|
371
127
|
|
|
372
128
|
```sh
|
|
373
|
-
# Battery-included (runs local in-process ONNX models)
|
|
374
129
|
docker run -d \
|
|
375
130
|
--name skillmux \
|
|
376
131
|
-v ~/skills:/vault:ro \
|
|
377
132
|
-v skillmux-data:/data \
|
|
378
133
|
-p 3000:3000 \
|
|
379
134
|
ghcr.io/klhq/skillmux:latest
|
|
380
|
-
|
|
381
|
-
# Slim (configured remote embeddings, or lexical fallback)
|
|
382
|
-
docker run -d \
|
|
383
|
-
--name skillmux-slim \
|
|
384
|
-
-v ~/skills:/vault:ro \
|
|
385
|
-
-v skillmux-data:/data \
|
|
386
|
-
-p 3000:3000 \
|
|
387
|
-
-e EMBED_ENDPOINT="http://embeddings-host:8080/v1/embeddings" \
|
|
388
|
-
ghcr.io/klhq/skillmux:latest-slim
|
|
389
135
|
```
|
|
390
136
|
|
|
391
|
-
|
|
137
|
+
Use `ghcr.io/klhq/skillmux:latest-slim` when you want remote embeddings or
|
|
138
|
+
lexical fallback instead of a bundled model. Docker Hub mirrors both variants
|
|
139
|
+
under `docker.io/klhq/skillmux`.
|
|
392
140
|
|
|
393
|
-
-
|
|
141
|
+
The [getting-started guide](docs/getting-started.md) provides complete recipes
|
|
142
|
+
for all three setups.
|
|
394
143
|
|
|
395
|
-
|
|
144
|
+
## Add and inspect skills
|
|
396
145
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
- **Bind address** (`hostname`, default `127.0.0.1`) — HTTP transport binds loopback-only by default, so a zero-config `skillmux serve --transport http` isn't reachable from the network. Inside Docker (`RUNNING_IN_DOCKER=true`) this defaults to `0.0.0.0` instead, since the container's own loopback isn't reachable through port-mapping. Set `hostname` (or `HTTP_HOSTNAME`) explicitly to expose the server beyond localhost.
|
|
400
|
-
- **Bearer token auth** (off by default) — set `auth_enabled = true` and the token via the env var named by `auth_token_env` (default `SKILLMUX_AUTH_TOKEN`). Requests need `Authorization: Bearer <token>`; missing/mismatched tokens get `401`, and a configured-but-empty token env var gets `500`.
|
|
401
|
-
- **CORS** — `allowed_origins` (default `[]`, deny-by-default) is checked against the request's `Origin` header; disallowed origins get `403`. Requests with no `Origin` header (curl, MCP clients, server-to-server) are unaffected either way — only browser-issued cross-origin requests are gated. `/health` and `/metrics` are excluded from auth but still CORS-checked.
|
|
402
|
-
- **Rate limiting** (off by default) — per-token (when auth is enabled) or per-IP (`server.requestIP`) token-bucket limiting. Enable with `rate_limit.enabled = true` and set `rate_limit.requests_per_minute` (default `60`). The `X-Forwarded-For` header is ignored unless `rate_limit.trust_proxy = true` — it's client-supplied and spoofable, so only opt in when a trusted reverse proxy sets it. Every response carries `X-RateLimit-Limit`/`X-RateLimit-Remaining`/`X-RateLimit-Reset`; over-limit requests get `429` plus `Retry-After`.
|
|
403
|
-
- **`GET /health/live`** — lightweight liveness check. Legacy `GET /health` remains an alias.
|
|
404
|
-
- **`GET /health/ready`** — readiness with active retrieval capability, skill count, index state, and inference status.
|
|
405
|
-
- **`GET /metrics`** — Prometheus text exposition: `skill_router_requests_total`, `skill_router_resolve_outcomes_total`, `skill_router_resolve_latency_seconds` (histogram), `skill_router_errors_total`, `skill_router_rate_limits_exceeded_total`.
|
|
406
|
-
|
|
407
|
-
### Running Stdio Server in Docker
|
|
408
|
-
|
|
409
|
-
If your agent runs locally and expects a piped stdio process:
|
|
146
|
+
Install a skill from a Git repository:
|
|
410
147
|
|
|
411
148
|
```sh
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
ghcr.io/klhq/skillmux:latest serve --transport stdio
|
|
149
|
+
skillmux install owner/repo
|
|
150
|
+
skillmux install owner/repo/path/to/skill
|
|
415
151
|
```
|
|
416
152
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
No config is required for the battery-included local ONNX mode. See [`config.example.toml`](config.example.toml) for the minimal local setup, [`config.remote.example.toml`](config.remote.example.toml) for bring-your-own endpoints, and [`docs/configuration.md`](docs/configuration.md) for advanced settings.
|
|
153
|
+
Skillmux validates `SKILL.md` and scans candidate content before copying it into the vault. Use `--fail-on low|medium|high` to turn selected findings into an install gate.
|
|
420
154
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
- The zero-config default combines SQLite FTS5 with the small `Xenova/gte-small` embedding model and returns an ordered shortlist.
|
|
424
|
-
- Configured OpenAI-compatible embeddings replace the local embedder. An optional versioned reranker protocol adapter enables confident automatic matches without coupling configuration to a server product or URL shape.
|
|
425
|
-
|
|
426
|
-
Run `skillmux doctor` to verify routing capability. Run `skillmux config show` to inspect effective configuration; it prints credential variable names, never values.
|
|
427
|
-
|
|
428
|
-
### Security scanning
|
|
429
|
-
|
|
430
|
-
`skillmux scan [<path>]` inspects skill content for prompt-injection and data-exfiltration risk indicators
|
|
431
|
-
before it's served over MCP or HTTP. It's offline (no network call, no inference config needed),
|
|
432
|
-
read-only, and advisory-only — it never blocks `skillmux index`/`sync`/`init`, which don't call it
|
|
433
|
-
automatically.
|
|
155
|
+
Useful management commands:
|
|
434
156
|
|
|
435
157
|
```sh
|
|
436
|
-
skillmux scan
|
|
437
|
-
skillmux
|
|
438
|
-
skillmux
|
|
439
|
-
skillmux
|
|
158
|
+
skillmux scan ~/skills
|
|
159
|
+
skillmux core pin csv-formatter --yes
|
|
160
|
+
skillmux project pin my-project code-context --yes
|
|
161
|
+
skillmux skill which csv-formatter
|
|
162
|
+
skillmux report --since 7d
|
|
440
163
|
```
|
|
441
164
|
|
|
442
|
-
|
|
443
|
-
`severity`:
|
|
165
|
+
Read [Managing skills](docs/skill-management.md) for target ownership, project groups, local overrides, recovery, and reporting.
|
|
444
166
|
|
|
445
|
-
|
|
446
|
-
| ------------------------- | ---------- | ------------------------------------------------------------------------------------------------- |
|
|
447
|
-
| `prompt-injection-phrase` | `high` | Known instruction-override phrases (e.g. "ignore previous instructions") |
|
|
448
|
-
| `invisible-unicode` | `high` | Zero-width/invisible Unicode code points, including hidden tag-character payloads |
|
|
449
|
-
| `secret-pattern` | `high` | Hardcoded-credential-shaped strings (AWS-style keys, PEM blocks, `api_key=`/`token=` assignments) |
|
|
450
|
-
| `suspicious-url` | `medium` | Bare-IP-address URLs, or URLs paired with exfiltration-suggesting text |
|
|
167
|
+
## MCP retrieval
|
|
451
168
|
|
|
452
|
-
|
|
453
|
-
routed where); `skillmux scan` is content security (what's in the vault).
|
|
169
|
+
Register it with an MCP client:
|
|
454
170
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
skillmux install owner/repo --dry-run # preview id, target path, and scan findings
|
|
465
|
-
skillmux install owner/repo --force # overwrite an existing skill_id
|
|
466
|
-
skillmux install owner/repo --fail-on high # abort the install if scan findings meet the threshold
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
The fetched skill is validated the same way `skillmux scan` validates the vault — malformed `SKILL.md`
|
|
470
|
-
aborts the install, and scan findings are printed before anything is written (advisory by default;
|
|
471
|
-
`--fail-on` opts into blocking, matching `skillmux scan`'s severity levels). Materialization is a plain
|
|
472
|
-
file copy, not a symlink — the temporary clone is deleted once the install completes.
|
|
473
|
-
|
|
474
|
-
`skillmux install` intentionally does **not** handle updates, uninstalls, version pinning, or
|
|
475
|
-
core/project/routed tier assignment (that's `skillmux sync`'s domain) — it only ever fetches one skill,
|
|
476
|
-
once. Use `skillmux sync` afterward if the installed skill needs to be pinned into a tier.
|
|
477
|
-
|
|
478
|
-
### Environment Variable Overrides
|
|
479
|
-
|
|
480
|
-
All core settings can be overridden via environment variables (handy for Docker):
|
|
481
|
-
|
|
482
|
-
- `VAULT_PATH` — overrides `vault_path` (defaults to `/vault` inside Docker)
|
|
483
|
-
- `STATE_DIR` — overrides `state_dir` (defaults to `/data` inside Docker)
|
|
484
|
-
- `EMBED_ENDPOINT` / `SKILLMUX_EMBED_ENDPOINT` — overrides the complete remote `inference.embedding.endpoint`
|
|
485
|
-
- `EMBED_MODEL` / `SKILLMUX_EMBED_MODEL` — overrides `embedding.model`
|
|
486
|
-
- `EMBED_DIMENSION` / `SKILLMUX_EMBED_DIMENSION` — overrides `embedding.dimension`
|
|
487
|
-
- `EMBED_DEVICE` / `EMBED_DTYPE` — overrides local `inference.embedding.device` / `inference.embedding.dtype`
|
|
488
|
-
- `RERANK_ENDPOINT` / `SKILLMUX_RERANK_ENDPOINT` — overrides the complete remote `inference.reranker.endpoint`
|
|
489
|
-
- `RERANK_ADAPTER` / `SKILLMUX_RERANK_ADAPTER` — overrides `inference.reranker.adapter`
|
|
490
|
-
- `RERANK_MODEL` / `SKILLMUX_RERANK_MODEL` — overrides `inference.reranker.model`
|
|
491
|
-
- `SKILLMUX_CONFIG` — path to custom `config.toml` (default `~/.config/skillmux/config.toml`)
|
|
492
|
-
- `SKILLMUX_MODELS_DIR` — path to directory storing downloaded local models (default `~/.cache/skillmux/models`, `/models` inside Docker)
|
|
493
|
-
- `PORT` — HTTP listen port (default `3000`, HTTP transport only)
|
|
494
|
-
- `HTTP_HOSTNAME` — overrides `server.hostname` (default `127.0.0.1`, `0.0.0.0` inside Docker)
|
|
495
|
-
- `HTTP_AUTH_ENABLED` — overrides `server.auth_enabled` (`"true"` to enable)
|
|
496
|
-
- `HTTP_AUTH_TOKEN_ENV` — overrides `server.auth_token_env`
|
|
497
|
-
- `HTTP_ALLOWED_ORIGINS` — comma-separated list, overrides `server.allowed_origins`
|
|
498
|
-
- `HTTP_RATE_LIMIT_ENABLED` / `SKILLMUX_HTTP_RATE_LIMIT_ENABLED` — overrides `server.rate_limit.enabled` (`"true"` to enable)
|
|
499
|
-
- `HTTP_RATE_LIMIT_RPM` / `SKILLMUX_HTTP_RATE_LIMIT_RPM` — overrides `server.rate_limit.requests_per_minute`
|
|
500
|
-
- `HTTP_RATE_LIMIT_TRUST_PROXY` / `SKILLMUX_HTTP_RATE_LIMIT_TRUST_PROXY` — overrides `server.rate_limit.trust_proxy` (`"true"` to trust `X-Forwarded-For`)
|
|
501
|
-
|
|
502
|
-
Remote API keys are read independently from the environment variables named by
|
|
503
|
-
`inference.embedding.api_key_env` and `inference.reranker.api_key_env`. Omit
|
|
504
|
-
`api_key_env` for an intentionally unauthenticated endpoint. If it is present,
|
|
505
|
-
the named variable must be non-empty before clients are created and is sent as
|
|
506
|
-
a Bearer token. Secret values never live in the config file or diagnostics.
|
|
507
|
-
|
|
508
|
-
Rerankers use an exact endpoint plus an explicit adapter. `jina-v1` sends
|
|
509
|
-
string documents; `bifrost-v1` sends Bifrost document objects. Skillmux never
|
|
510
|
-
infers an adapter from the URL and never adds or removes path components.
|
|
511
|
-
|
|
512
|
-
Embeddings likewise use an exact endpoint and the OpenAI-compatible
|
|
513
|
-
`{ model, input }` contract. Skillmux never adds `/v1/embeddings` or rewrites
|
|
514
|
-
the configured path or query string. Replace the removed `base_url` setting
|
|
515
|
-
with the complete endpoint, for example `base_url = "http://host"` or
|
|
516
|
-
`base_url = "http://host/v1"` becomes
|
|
517
|
-
`endpoint = "http://host/v1/embeddings"`. The removed `EMBED_BASE_URL`,
|
|
518
|
-
`SKILLMUX_EMBED_BASE_URL`, and `SKILL_ROUTER_EMBED_BASE_URL` variables are
|
|
519
|
-
startup errors with migration guidance.
|
|
520
|
-
|
|
521
|
-
> **Breaking reranker migration:** replace `provider = "infinity"` with
|
|
522
|
-
> `adapter = "jina-v1"`, and replace `base_url` with the complete `endpoint`.
|
|
523
|
-
> The old client appended `/rerank`. For example,
|
|
524
|
-
> `base_url = "http://host/v1"` becomes
|
|
525
|
-
> `endpoint = "http://host/v1/rerank"`; a bare `http://host` becomes
|
|
526
|
-
> `http://host/rerank`. The removed `RERANK_BASE_URL`,
|
|
527
|
-
> `SKILLMUX_RERANK_BASE_URL`, and `SKILL_ROUTER_RERANK_BASE_URL` variables are
|
|
528
|
-
> startup errors with migration guidance.
|
|
529
|
-
|
|
530
|
-
Verified reranker contracts:
|
|
531
|
-
|
|
532
|
-
| Implementation | Tested version | Endpoint | Adapter | Verification |
|
|
533
|
-
| ------------------- | -------------: | -------------------- | ------------ | ----------------------------------------------------------------- |
|
|
534
|
-
| Bifrost | 1.6.6 | `/v1/rerank` | `bifrost-v1` | Live end-to-end request and recorded contract fixture, 2026-07-28 |
|
|
535
|
-
| Jina-style contract | fixture | exact configured URL | `jina-v1` | Automated request/response contract suite |
|
|
536
|
-
|
|
537
|
-
## Benchmarks & Evaluation
|
|
538
|
-
|
|
539
|
-
Skillmux includes a built-in evaluation framework to benchmark retrieval accuracy (lexical vs. hybrid vector search) against labeled intent datasets.
|
|
540
|
-
|
|
541
|
-
Evaluate lexical and local hybrid retrieval against the checked-in labeled queries:
|
|
542
|
-
|
|
543
|
-
```sh
|
|
544
|
-
bun run src/cli.ts eval
|
|
545
|
-
# holdout queries: 8
|
|
546
|
-
# lexical recall@5: 1.000
|
|
547
|
-
# hybrid recall@5: 1.000
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"mcpServers": {
|
|
174
|
+
"skillmux": {
|
|
175
|
+
"command": "skillmux",
|
|
176
|
+
"args": ["serve"]
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
548
180
|
```
|
|
549
181
|
|
|
550
|
-
|
|
551
|
-
domain-specific query datasets using `skillmux calibrate`. See the
|
|
552
|
-
[calibration guide](docs/calibration.md) for the full operator lifecycle and
|
|
553
|
-
the [CLI reference](docs/cli.md#policy-calibration-skillmux-calibrate) for
|
|
554
|
-
command syntax.
|
|
555
|
-
|
|
556
|
-
## FAQ & Troubleshooting
|
|
557
|
-
|
|
558
|
-
<details>
|
|
559
|
-
<summary><b>Why did my query return <code>ambiguous</code> instead of <code>matched</code>?</b></summary>
|
|
560
|
-
|
|
561
|
-
<br>
|
|
562
|
-
|
|
563
|
-
The router returns `"outcome": "ambiguous"` when multiple candidate skills meet retrieval confidence thresholds, or when no single candidate dominates by a sufficient score margin. In this state, up to 5 candidate skill summaries (`skill_id`, `title`, `description`) are returned so the calling LLM can choose the exact skill and invoke `fetch_skill`.
|
|
564
|
-
|
|
565
|
-
</details>
|
|
566
|
-
|
|
567
|
-
<details>
|
|
568
|
-
<summary><b>Does skillmux require an active internet connection?</b></summary>
|
|
569
|
-
|
|
570
|
-
<br>
|
|
571
|
-
|
|
572
|
-
No. In default local inference mode (`inference.mode = "local"`), skillmux operates 100% offline. The default GTE-small embedding model is quantized to q8 and bundled within the binary/Docker image.
|
|
182
|
+
Skillmux exposes two tools:
|
|
573
183
|
|
|
574
|
-
|
|
184
|
+
| Tool | Input | Result |
|
|
185
|
+
| --- | --- | --- |
|
|
186
|
+
| `resolve_skill` | Natural-language task description | A matched skill, an ordered shortlist, or no match |
|
|
187
|
+
| `fetch_skill` | Exact `skill_id` | The current `SKILL.md` body, SHA-256 digest, and supporting-file paths |
|
|
575
188
|
|
|
576
|
-
|
|
577
|
-
<summary><b>What happens when remote embedding or reranking endpoints fail?</b></summary>
|
|
189
|
+
Skillmux uses the best available capability:
|
|
578
190
|
|
|
579
|
-
|
|
191
|
+
1. SQLite FTS5 provides lexical retrieval and offline fallback.
|
|
192
|
+
2. Local or remote embeddings add semantic recall.
|
|
193
|
+
3. An optional reranker orders candidates and can produce calibrated automatic matches.
|
|
580
194
|
|
|
581
|
-
|
|
195
|
+
Without calibrated reranker thresholds, Skillmux returns an ordered shortlist and lets the calling model choose. Endpoint failures degrade to a healthy lower retrieval mode instead of taking the MCP server down.
|
|
582
196
|
|
|
583
|
-
|
|
197
|
+
Read [MCP routing](docs/mcp-routing.md) for transports, outcomes, client instructions, retrieval modes, and the wire contract.
|
|
584
198
|
|
|
585
|
-
|
|
586
|
-
<summary><b>When should I use routed skills vs. pinned skills?</b></summary>
|
|
199
|
+
## Supported clients
|
|
587
200
|
|
|
588
|
-
|
|
201
|
+
| Client | Native skill delivery | MCP setup |
|
|
202
|
+
| --- | --- | --- |
|
|
203
|
+
| Claude Code | `~/.claude/skills` | Configure in the client |
|
|
204
|
+
| Codex | `$CODEX_HOME/skills` or `~/.codex/skills` | Configure in the client |
|
|
205
|
+
| Gemini CLI, OpenCode, GitHub Copilot, Windsurf | `~/.agents/skills` | Configure in the client |
|
|
206
|
+
| Antigravity | `~/.gemini/config/skills` | Configure in the client |
|
|
207
|
+
| Goose, Hermes | Manual full-vault setup | Manual registration |
|
|
208
|
+
| Custom clients | Any directory through a custom target | Stdio or Streamable HTTP |
|
|
589
209
|
|
|
590
|
-
|
|
591
|
-
- **Pinned (`skillmux sync`)**: Best when running multiple agent surfaces (e.g. Claude Code, opencode) that all require the same core set of 2–5 skills loaded statically at agent startup.
|
|
592
|
-
|
|
593
|
-
</details>
|
|
594
|
-
|
|
595
|
-
<details>
|
|
596
|
-
<summary><b>How do I verify server readiness and routing health?</b></summary>
|
|
597
|
-
|
|
598
|
-
<br>
|
|
599
|
-
|
|
600
|
-
Run `skillmux doctor` locally or hit the HTTP readiness endpoint (`GET /health/ready`). `doctor` checks vault accessibility, state directory permissions, ONNX runtime binding status, and active retrieval lane status.
|
|
601
|
-
|
|
602
|
-
</details>
|
|
210
|
+
Skillmux preserves existing instruction files and unmanaged target content. Run `skillmux init --dry-run` to inspect every planned filesystem change.
|
|
603
211
|
|
|
604
212
|
## Guarantees
|
|
605
213
|
|
|
606
|
-
- **
|
|
607
|
-
- **
|
|
608
|
-
- **
|
|
609
|
-
- **
|
|
214
|
+
- **Controlled sources:** pins come from the canonical vault, while routed delivery follows the configured overlay order.
|
|
215
|
+
- **Scoped writes:** management commands write only to documented config, vault, state, and adopted target paths.
|
|
216
|
+
- **Managed ownership:** sync removes only entries recorded in the target's `.skillmux` marker.
|
|
217
|
+
- **Current bytes:** MCP delivery hashes the file on disk and never serves a stale indexed body.
|
|
218
|
+
- **Graceful retrieval:** embedding and reranker failures fall back without hiding the active capability.
|
|
219
|
+
- **Auditable decisions:** each `resolve_skill` call records its outcome, candidates, scores, and latency in the state database.
|
|
220
|
+
|
|
221
|
+
## Documentation
|
|
222
|
+
|
|
223
|
+
Start with the [documentation hub](docs/README.md).
|
|
224
|
+
|
|
225
|
+
| Guide | Covers |
|
|
226
|
+
| --- | --- |
|
|
227
|
+
| [Getting started](docs/getting-started.md) | Native management, local MCP, and shared-service recipes |
|
|
228
|
+
| [Concepts](docs/concepts.md) | Delivery tiers, deployment topologies, retrieval modes, and ownership |
|
|
229
|
+
| [Managing skills](docs/skill-management.md) | Install, scan, pin, sync, report, overlays, and recovery |
|
|
230
|
+
| [MCP routing](docs/mcp-routing.md) | Tools, outcomes, transports, retrieval, fallback, and integrity |
|
|
231
|
+
| [Deployment](docs/deployment.md) | Docker, HTTP, auth, CORS, rate limits, health, and metrics |
|
|
232
|
+
| [Configuration](docs/configuration.md) | Machine config, inference, manifests, and overlays |
|
|
233
|
+
| [CLI reference](docs/cli.md) | Commands, contexts, automation, JSON output, and exit codes |
|
|
234
|
+
| [Policy calibration](docs/calibration.md) | Labelled datasets, certification, and threshold application |
|
|
235
|
+
| [Troubleshooting](docs/troubleshooting.md) | `doctor`, common failures, and migration notes |
|
|
236
|
+
| [MCP schema](docs/schema.json) | JSON Schema 2020-12 tool contract |
|
|
610
237
|
|
|
611
238
|
## Development
|
|
612
239
|
|
|
240
|
+
Skillmux uses Bun for development:
|
|
241
|
+
|
|
613
242
|
```sh
|
|
614
|
-
bun
|
|
615
|
-
bun
|
|
243
|
+
bun install --frozen-lockfile
|
|
244
|
+
bun test
|
|
245
|
+
bun run build
|
|
616
246
|
```
|
|
617
247
|
|
|
618
|
-
|
|
248
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow and [SECURITY.md](SECURITY.md) for vulnerability reporting.
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
[MIT](LICENSE)
|