@klhapp/skillmux 1.5.2 → 1.7.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,27 @@ 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.7.0](https://github.com/klhq/skillmux/compare/v1.6.0...v1.7.0) (2026-08-21)
9
+
10
+
11
+ ### Added
12
+
13
+ * **calibration:** remove obsolete threshold calibration ([#125](https://github.com/klhq/skillmux/issues/125)) ([1432948](https://github.com/klhq/skillmux/commit/143294848c333c35186d70742ef59c230dc850bb))
14
+ * **eval:** rank Skillmux 2.0 evaluation ([#124](https://github.com/klhq/skillmux/issues/124)) ([2fab68d](https://github.com/klhq/skillmux/commit/2fab68d73702913fea5a6e4d8f892c2802a65a88))
15
+ * **ranking:** ranked-only Skillmux 2.0 runtime contract ([#122](https://github.com/klhq/skillmux/issues/122)) ([00810df](https://github.com/klhq/skillmux/commit/00810df92b7de60289dad41fe1fcb5a982686493))
16
+
17
+
18
+ ### Changed
19
+
20
+ * **audit:** remove legacy classifier outcomes ([#126](https://github.com/klhq/skillmux/issues/126)) ([953edc4](https://github.com/klhq/skillmux/commit/953edc40147fb2f87eec5a57d53d6fa022566b77))
21
+
22
+ ## [1.6.0](https://github.com/klhq/skillmux/compare/v1.5.2...v1.6.0) (2026-08-18)
23
+
24
+
25
+ ### Added
26
+
27
+ * **calibrate:** add tune safety buffers ([#120](https://github.com/klhq/skillmux/issues/120)) ([66d501c](https://github.com/klhq/skillmux/commit/66d501c4ac16956e8e887622e5178caef743bec7))
28
+
8
29
  ## [1.5.2](https://github.com/klhq/skillmux/compare/v1.5.1...v1.5.2) (2026-08-17)
9
30
 
10
31
 
package/README.md CHANGED
@@ -231,18 +231,18 @@ Skillmux exposes two tools:
231
231
 
232
232
  | Tool | Input | Result |
233
233
  | --- | --- | --- |
234
- | `resolve_skill` | Natural-language task description | A matched skill, an ordered shortlist, or no match |
234
+ | `resolve_skill` | Natural-language task description | A ranked shortlist of candidates |
235
235
  | `fetch_skill` | Exact `skill_id` | The current `SKILL.md` body, SHA-256 digest, and supporting-file paths |
236
236
 
237
237
  Skillmux uses the best available capability:
238
238
 
239
239
  1. SQLite FTS5 provides lexical retrieval and offline fallback.
240
240
  2. Local or remote embeddings add semantic recall.
241
- 3. An optional reranker orders candidates and can produce calibrated automatic matches.
241
+ 3. An optional reranker scores and reorders candidates.
242
242
 
243
- 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.
243
+ Skillmux returns a ranked shortlist and lets the calling model choose. Endpoint failures degrade to a healthy lower retrieval mode instead of taking the MCP server down.
244
244
 
245
- Read [MCP routing](docs/mcp-routing.md) for transports, outcomes, client instructions, retrieval modes, and the wire contract.
245
+ Read [MCP routing](docs/mcp-routing.md) for transports, client instructions, retrieval modes, and the wire contract.
246
246
 
247
247
  ## Supported clients
248
248
 
@@ -264,7 +264,7 @@ Skillmux preserves existing instruction files and unmanaged target content. Run
264
264
  - **Managed ownership:** sync removes only entries recorded in the target's `.skillmux` marker.
265
265
  - **Current bytes:** MCP delivery hashes the file on disk and never serves a stale indexed body.
266
266
  - **Graceful retrieval:** embedding and reranker failures fall back without hiding the active capability.
267
- - **Auditable decisions:** each `resolve_skill` call records its outcome, candidates, scores, and latency in the state database.
267
+ - **Auditable decisions:** each `resolve_skill` call records its query, retrieval capability, candidates, scores, and latency in the state database.
268
268
 
269
269
  ## Documentation
270
270
 
@@ -275,11 +275,11 @@ Start with the [documentation hub](docs/README.md).
275
275
  | [Getting started](docs/getting-started.md) | Native management, local MCP, and shared-service recipes |
276
276
  | [Concepts](docs/concepts.md) | Delivery tiers, deployment topologies, retrieval modes, and ownership |
277
277
  | [Managing skills](docs/skill-management.md) | Install, scan, pin, sync, report, overlays, and recovery |
278
- | [MCP routing](docs/mcp-routing.md) | Tools, outcomes, transports, retrieval, fallback, and integrity |
278
+ | [MCP routing](docs/mcp-routing.md) | Tools, ranked candidate retrieval, transports, fallback, and integrity |
279
279
  | [Deployment](docs/deployment.md) | Docker, container command boundaries, HTTP surfaces and auth, CORS, rate limits, and comparable CLI, health, and metrics status |
280
280
  | [Configuration](docs/configuration.md) | Machine config, inference, HTTP surfaces, manifests, overlays, and container read-only configuration |
281
281
  | [CLI reference](docs/cli.md) | Host and container command surfaces, administrative contexts, automation, JSON output, and exit codes |
282
- | [Policy calibration](docs/calibration.md) | Labelled datasets, certification, and threshold application |
282
+ | [Ranked-shortlist migration](docs/ranked-shortlist-migration.md) | Upgrade guide for the ranked-only contract |
283
283
  | [Troubleshooting](docs/troubleshooting.md) | `doctor`, deployment identity, common failures, and migration notes |
284
284
  | [MCP schema](docs/schema.json) | JSON Schema 2020-12 tool contract |
285
285
 
@@ -15,3 +15,8 @@ vault_path = "~/skills"
15
15
  # vault_path for a given skill_id. Never holds skillmux.toml or the sync git
16
16
  # hook — those always stay in vault_path. See docs/configuration.md#local-vault-overlays.
17
17
  # local_vault_paths = ["~/skills-local"]
18
+
19
+ # Optional: output configuration for resolve_skill ranked candidates.
20
+ # [output]
21
+ # top_k = 10
22
+ # max_top_k = 50
@@ -28,10 +28,7 @@ endpoint = "https://reranker.example.com/v1/rerank"
28
28
  model = "your-reranker-model"
29
29
  api_key_env = "RERANKER_API_KEY"
30
30
 
31
- # Optional. Without these values, reranked results remain ambiguous.
32
- # Calibrate locally against your corpus before enabling automatic matches.
33
- # See docs/calibration.md; these example values are not universal defaults.
34
- [inference.thresholds]
35
- match_score = 0.90
36
- match_margin = 0.30
37
- candidate_floor = 0.50
31
+ # Optional: output configuration for resolve_skill ranked candidates.
32
+ # [output]
33
+ # top_k = 10
34
+ # max_top_k = 50
package/docs/README.md CHANGED
@@ -49,8 +49,8 @@ deployed server only, never remote client skill directories. See
49
49
  retrieval capability.
50
50
  - [Managing skills](skill-management.md): install, scan, pin, sync, inspect,
51
51
  and recover skills.
52
- - [MCP routing](mcp-routing.md): register stdio or HTTP MCP and understand
53
- retrieval outcomes.
52
+ - [MCP routing](mcp-routing.md): register stdio or HTTP MCP and route queries
53
+ to ranked candidate shortlists.
54
54
 
55
55
  ## Operate Skillmux
56
56
 
@@ -62,8 +62,8 @@ deployed server only, never remote client skill directories. See
62
62
  server settings, local overlays, and container read-only configuration.
63
63
  - [CLI reference](cli.md): use host and container command surfaces,
64
64
  administrative contexts, JSON output, and exit codes.
65
- - [Policy calibration](calibration.md): create labelled datasets and certify
66
- reranker thresholds.
65
+ - [Ranked-shortlist migration](ranked-shortlist-migration.md): upgrade to the ranked-only
66
+ shortlist contract.
67
67
  - [Troubleshooting](troubleshooting.md): diagnose vault, sync, model, and server
68
68
  problems.
69
69
 
@@ -149,6 +149,6 @@
149
149
 
150
150
  <rect x="420" y="608" width="740" height="82" rx="14" fill="#0f172a"/>
151
151
  <text x="444" y="633" class="chip" fill="#cbd5e1">MCP TOOL CONTRACT · STDIO + HTTP</text>
152
- <text x="444" y="655" class="mono mono-light" style="font-size: 12px">resolve_skill → retrieve + fuse → optional rerank → matched / ambiguous / no_match</text>
152
+ <text x="444" y="655" class="mono mono-light" style="font-size: 12px">resolve_skill → lexical + vectorRRF → optional rerank → top_k ranked candidates</text>
153
153
  <text x="444" y="677" class="mono mono-light" style="font-size: 12px">fetch_skill → exact current SKILL.md + SHA-256</text>
154
154
  </svg>
package/docs/cli.md CHANGED
@@ -24,7 +24,7 @@ CLI. Its `skillmux --help` surface is intentionally limited to `serve`,
24
24
  `index`, `doctor`, `report`, `scan`, `skill which`, and read-only `config`
25
25
  inspection (`show`, `get`, `validate`, `diff`, and `status`). Run `init`,
26
26
  `install`, pinning, `sync`, project or target management, model downloads,
27
- contexts, calibration, evaluation, and configuration changes on the host.
27
+ contexts, evaluation, and configuration changes on the host.
28
28
 
29
29
  When the image rejects one of those commands, it exits with code 2. JSON mode
30
30
  uses `CONTAINER_COMMAND_UNSUPPORTED` and includes `rejected_command`,
@@ -267,8 +267,8 @@ whole call fails and the manifest file is left untouched. To pin into a
267
267
 
268
268
  Config changes are categorized into live-reloadable and restart-required settings:
269
269
 
270
- - **Reloadable**: `vault_path`, `recall.*`, `thresholds.*`, `inference.embedding.*`, `server.rate_limit.*`
271
- - **Restart Required**: `server.hostname`, `server.auth_enabled`, `server.auth_token_env`, `server.admin.enabled`, `server.admin.token_env`, `inference.mode`, `state_dir`
270
+ - **Reloadable**: `config.environment_overrides`, `vault_path`, `recall.k_lexical`, `recall.k_vector`, `recall.k_rerank`, `output.top_k`, `output.max_top_k`, `inference.embedding.endpoint`, `inference.embedding.api_key_env`, `inference.reranker.adapter`, `inference.reranker.endpoint`, `inference.reranker.model`, `inference.reranker.api_key_env`, `inference.timeout_ms`, `server.rate_limit.enabled`, `server.rate_limit.requests_per_minute`, `server.rate_limit.trust_proxy`
271
+ - **Restart Required**: `server.hostname`, `server.auth_enabled`, `server.auth_token_env`, `server.admin.enabled`, `server.admin.token_env`, `inference.mode`, `inference.bundle`, `inference.models_dir`, `state_dir`, `inference.embedding.model`, `inference.embedding.dimension`, `inference.embedding.device`, `inference.embedding.dtype`
272
272
 
273
273
  The config file is optional. `skillmux serve` starts with defaults if its
274
274
  config path or parent directory is absent. In that case reload is inactive
@@ -287,44 +287,6 @@ skillmux skill which csv-formatter
287
287
 
288
288
  ---
289
289
 
290
- ## Policy calibration (`skillmux calibrate`)
291
-
292
- Calibrate decision thresholds (`match_score`, `match_margin`, `candidate_floor`) against synthetic or labeled query datasets.
293
- Calibration is local-only in this release. Remote targets advertise the
294
- capability as unavailable and return `not_implemented`; a local dataset path is
295
- never uploaded or represented as remotely executed. See
296
- [`docs/calibration.md`](calibration.md) for dataset responsibilities,
297
- certification gates, run evidence, reference values, and the complete operator
298
- lifecycle.
299
-
300
- ```sh
301
- # Run calibration on a dataset with the default four workers
302
- skillmux calibrate run --dataset ./eval/queries.json
303
-
304
- # Set the bounded worker count
305
- skillmux calibrate run --dataset ./eval/queries.json --concurrency 6
306
-
307
- # Print aggregate performance timing to stderr
308
- skillmux calibrate run --dataset ./eval/queries.json --timing
309
-
310
- # Resume a running or interrupted attempt with the same inputs and gates
311
- skillmux calibrate run --dataset ./eval/queries.json --resume <run_id>
312
-
313
- # List stored calibration runs in the evidence store
314
- skillmux calibrate list
315
-
316
- # Inspect detailed metrics and confusion matrix for a run
317
- skillmux calibrate show <run_id>
318
-
319
- # Apply calibrated thresholds to configuration (with fingerprint validation)
320
- skillmux calibrate apply <run_id>
321
-
322
- # Generate a synthetic decision dataset from vault skills
323
- skillmux calibrate generate-dataset --out ./eval/queries.json
324
- ```
325
-
326
- ---
327
-
328
290
  ## Administrative HTTP API (`/admin/v1/*`)
329
291
 
330
292
  The HTTP server has two separate surfaces:
@@ -351,12 +313,9 @@ Requests require `Authorization: Bearer <token>` where `<token>` matches the env
351
313
 
352
314
  | Endpoint | Method | Description |
353
315
  |----------|--------|-------------|
354
- | `/admin/v1/capabilities` | `GET` | Advertises server features (`config_read`, `config_write`, `calibration`, `persistence`) |
316
+ | `/admin/v1/capabilities` | `GET` | Advertises server features (`config_read`, `config_write`, `persistence`) |
355
317
  | `/admin/v1/config` | `GET` | Returns desired/effective config, sources, and `ETag` revision hash |
356
318
  | `/admin/v1/config` | `PATCH` | Applies dotted-key updates; requires matching `If-Match` header |
357
- | `/admin/v1/calibrations` | `GET`, `POST` | Returns `501 not_implemented` (calibration is local-only) |
358
- | `/admin/v1/calibrations/{run_id}` | `GET` | Returns `501 not_implemented`; raw evaluation queries are not exposed |
359
- | `/admin/v1/calibrations/{run_id}/apply` | `POST` | Returns `501 not_implemented` |
360
319
 
361
320
  ---
362
321
 
package/docs/concepts.md CHANGED
@@ -168,21 +168,19 @@ Skillmux reports the active retrieval capability:
168
168
  | `reranked` | A configured reranker reorders the fused candidates |
169
169
  | `exact` | An exact skill ID resolves directly |
170
170
 
171
- A reranker does not enable automatic matches by itself. Skillmux needs
172
- calibrated `match_score`, `match_margin`, and `candidate_floor` thresholds
173
- before it returns a semantic result as `matched`.
171
+ A reranker scores and reorders the fused candidates. Reranking does not classify
172
+ outcomes or filter by score thresholds; Skillmux delivers the top-ranked candidates
173
+ directly to the calling model.
174
174
 
175
- ## Retrieval outcomes
175
+ ## Ranked shortlist retrieval
176
176
 
177
- `resolve_skill` returns one of three outcomes:
177
+ `resolve_skill` always returns a ranked candidate list:
178
178
 
179
- - `matched`: one skill passed the calibrated policy, so Skillmux delivers its
180
- `SKILL.md` body inline;
181
- - `ambiguous`: Skillmux returns an ordered candidate list and the calling model
182
- chooses one with `fetch_skill`;
183
- - `no_match`: no candidate passed the policy and the agent continues without a
184
- skill.
179
+ - each candidate contains a `rank`, `skill_id`, `description`, and a nullable `score`;
180
+ - `top_k` controls the maximum candidate count returned, bounded by `output.max_top_k`;
181
+ - if no candidates match the query, `resolve_skill` returns an empty list (`candidates: []`);
182
+ - the calling model reviews the candidate shortlist and calls `fetch_skill` with the chosen `skill_id` to retrieve complete instructions.
185
183
 
186
- Embedding or reranker failures reduce the active capability. Vault and index
187
- failures make the server unready because Skillmux can no longer guarantee
188
- valid retrieval.
184
+ Embedding or reranker failures reduce the active capability and return
185
+ structured degradation metadata. Vault and index failures make the server
186
+ unready because Skillmux can no longer guarantee valid retrieval.
@@ -27,9 +27,8 @@ commands, target resolution, and automation envelopes, see
27
27
  [CLI reference](cli.md). For Linux CLI installation, see the
28
28
  [pinned checksum-verified download](getting-started.md#install-the-cli) or the
29
29
  [attested GitHub CLI path](getting-started.md#install-with-github-cli-attestation).
30
- For labelled datasets, threshold certification,
31
- reference values, and the apply lifecycle, see
32
- [Policy calibration](calibration.md).
30
+ For ranking evaluation and upgrading from earlier releases, see
31
+ [Ranked-shortlist migration](ranked-shortlist-migration.md).
33
32
 
34
33
  ## Machine config bootstrap
35
34
 
@@ -70,7 +69,7 @@ loads it and cache it in `~/.cache/skillmux/models`. The full image
70
69
  already contains the model.
71
70
 
72
71
  Skillmux combines FTS5 and cosine result lists with reciprocal-rank fusion.
73
- Without a reranker, the calling model selects from the ordered shortlist.
72
+ Skillmux returns the fused candidates as a ranked shortlist.
74
73
 
75
74
  Advanced local overrides:
76
75
 
@@ -120,9 +119,8 @@ Remote embedding `dimension` is required. `endpoint`, `api_key_env`, and the
120
119
  shared timeout reload live; model, dimension, device, and dtype require a
121
120
  restart. Changing only endpoint does not invalidate stored vectors.
122
121
 
123
- Reranker adapter and model form the calibration identity. Moving an unchanged
124
- deployment to another endpoint does not invalidate calibration; changing the
125
- adapter or model does.
122
+ Reranker configuration pairs an adapter (such as `jina-v1` or `bifrost-v1`) with a
123
+ model name and a complete endpoint URL.
126
124
 
127
125
  ## Configuration authority
128
126
 
@@ -142,7 +140,7 @@ Inspect provenance and active policy with `skillmux config show --sources` or `s
142
140
 
143
141
  ## Advanced retrieval
144
142
 
145
- Candidate-generation depth, reranking candidate budgets, and agent-context delivery are separate controls:
143
+ Candidate-generation depth, reranking candidate budgets, and output candidate shortlist size are separate controls:
146
144
 
147
145
  ```toml
148
146
  [recall]
@@ -151,12 +149,14 @@ k_vector = 20
151
149
  k_rerank = 10
152
150
 
153
151
  [output]
154
- ambiguous_candidate_limit = 5
152
+ top_k = 10
153
+ max_top_k = 50
155
154
  ```
156
155
 
157
156
  - `recall.k_lexical` and `recall.k_vector` control initial candidate generation depth.
158
157
  - `recall.k_rerank` bounds the candidate shortlist sent to the reranker adapter (defaults to `10`, cannot exceed `k_lexical + k_vector`).
159
- - `output.ambiguous_candidate_limit` controls agent context: it caps the ambiguous candidate list returned to the calling LLM after retrieval, reranking, and threshold filtering (`thresholds.candidate_limit` is deprecated in 1.x).
158
+ - `output.top_k` sets the default maximum number of candidates returned by `resolve_skill` (defaults to `10`).
159
+ - `output.max_top_k` sets the upper bound for per-request `top_k` overrides (defaults to `50`).
160
160
 
161
161
  ### Failure visibility and degraded retrieval
162
162
 
@@ -164,7 +164,6 @@ When remote embedding or reranking fails or times out, Skillmux gracefully falls
164
164
 
165
165
  ```json
166
166
  {
167
- "outcome": "ambiguous",
168
167
  "retrieval": "hybrid",
169
168
  "degraded_from": "reranked",
170
169
  "degradation_reason": "reranker_timeout",
@@ -113,7 +113,7 @@ The supported container commands are `serve`, `index`, `doctor`, `report`,
113
113
 
114
114
  The image rejects host-management commands, including `init`, `sync`,
115
115
  `install`, `project`, `target`, `core`, `local-vault`, `models download`,
116
- context management, calibration, evaluation, and configuration initialization
116
+ context management, evaluation, and configuration initialization
117
117
  or mutation. Install the Skillmux CLI on the host when a command needs to
118
118
  manage a local vault or agent directory.
119
119
 
@@ -141,8 +141,8 @@ docker run -d \
141
141
  ghcr.io/klhq/skillmux:latest-slim
142
142
  ```
143
143
 
144
- Set `SKILLMUX_CONFIG` and mount a TOML file when you need reranking, calibrated
145
- thresholds, server policy, or API-key environment names:
144
+ Set `SKILLMUX_CONFIG` and mount a TOML file when you need reranking, custom
145
+ recall/output settings, server policy, or API-key environment names:
146
146
 
147
147
  ```sh
148
148
  docker run -d \
@@ -242,15 +242,18 @@ The HTTP server provides:
242
242
  | `GET /health/ready` | Vault, index, inference, active capability, version, runtime, and image variant |
243
243
  | `GET /health` | Compatibility alias for liveness |
244
244
  | `GET /metrics` | Prometheus text exposition |
245
- | `GET /stats` | Aggregated routing outcomes for `skillmux report` |
245
+ | `GET /stats` | Aggregated routing statistics for `skillmux report` |
246
246
  | `POST /mcp` | Streamable HTTP MCP transport |
247
247
  | `/admin/v1/*` | Administrative configuration API (when enabled) |
248
248
 
249
249
  The Docker health check calls `/health/ready`.
250
250
 
251
- Prometheus metrics cover request totals, resolve outcomes, latency, errors,
252
- rate-limit rejections, and a `skill_router_deployment_info` gauge labelled with
253
- `version`, `runtime`, and `image_variant`. The values match `skillmux doctor`,
251
+ `GET /stats` returns JSON aggregated from audit rows over a query window (using `?since=`, defaulting to 24 hours). The response contains `since`, `until`, `total_requests`, `empty_shortlist_count`, `empty_shortlist_rate`, `retrieval_totals` (counts for `exact`, `reranked`, `hybrid`, and `lexical`), `degraded_count`, `average_latency_ms`, per-skill candidate counts in `skills` (`skill_id`, `candidate_count`), and `top_empty_shortlist_queries` (`query`, `count`). See [Managing skills](skill-management.md#use-routing-data-to-tune-tiers) for using these statistics to tune delivery tiers.
252
+
253
+ Prometheus metrics cover request totals, resolve latency histograms, errors,
254
+ rate-limit rejections, degraded retrieval totals by stage and reason, readiness
255
+ and active retrieval capability gauges, and a `skill_router_deployment_info` gauge
256
+ labelled with `version`, `runtime`, and `image_variant`. The values match `skillmux doctor`,
254
257
  `skillmux config status`, and `/health/ready`; use `image_variant="none"` for
255
258
  a host runtime. These operational outputs never include credentials, API keys,
256
259
  or token values. Health and metrics do not require bearer authentication, but
@@ -286,7 +289,7 @@ their mounted vault checkout and do not manage host agent directories.
286
289
 
287
290
  ## Persistent data and backups
288
291
 
289
- Persist `state_dir` to retain the index, audit log, and calibration evidence.
292
+ Persist `state_dir` to retain the index and audit log.
290
293
  Skill content remains in the server's vault checkout and should use its own
291
294
  backup or Git workflow.
292
295
 
@@ -212,7 +212,7 @@ Register it with your MCP client:
212
212
  ```
213
213
 
214
214
  The client launches the process and closes it with the MCP session. Continue
215
- with [MCP routing](mcp-routing.md) for client behavior and retrieval outcomes.
215
+ with [MCP routing](mcp-routing.md) for client behavior and ranked candidate retrieval.
216
216
 
217
217
  ## Run a shared MCP service
218
218
 
@@ -70,16 +70,30 @@ Input:
70
70
 
71
71
  ```json
72
72
  {
73
- "query": "convert this spreadsheet to a Markdown table"
73
+ "query": "convert this spreadsheet to a Markdown table",
74
+ "top_k": 5
74
75
  }
75
76
  ```
76
77
 
77
- Skillmux returns one outcome:
78
+ Skillmux returns a ranked candidates response:
78
79
 
79
- - `matched`: `structuredContent` contains match metadata and the text content
80
- contains the `SKILL.md` body once;
81
- - `ambiguous`: `structuredContent` contains up to `candidate_limit` candidates;
82
- - `no_match`: the agent continues with its normal workflow.
80
+ ```json
81
+ {
82
+ "retrieval": "reranked",
83
+ "candidates": [
84
+ {
85
+ "rank": 1,
86
+ "skill_id": "csv-formatter",
87
+ "description": "Convert CSV and spreadsheets into formatted Markdown tables.",
88
+ "score": 0.92
89
+ }
90
+ ]
91
+ }
92
+ ```
93
+
94
+ - `retrieval`: the effective retrieval capability (`reranked`, `hybrid`, or `lexical`).
95
+ - `candidates`: zero through effective `top_k` candidates ordered by descending score with contiguous 1-based ranks.
96
+ - If reranking or embedding fails, degradation metadata (`degraded_from`, `degradation_reason`) is included.
83
97
 
84
98
  ### `fetch_skill`
85
99
 
@@ -102,13 +116,9 @@ The complete wire contract lives in [schema.json](schema.json).
102
116
  Give the calling client these rules:
103
117
 
104
118
  1. Call `resolve_skill` when a task may benefit from a specialized workflow.
105
- 2. Follow the delivered skill on `matched`.
106
- 3. On `ambiguous`, choose the best candidate and call `fetch_skill`.
107
- 4. On `no_match`, continue without loading a skill.
108
-
109
- Do not treat the first ambiguous candidate as an automatic match. Skillmux
110
- uses ambiguity to keep the final choice with the calling model when it lacks
111
- enough confidence.
119
+ 2. Review the returned ranked candidates shortlist.
120
+ 3. If a relevant candidate exists, call `fetch_skill` with its `skill_id` to retrieve complete instructions.
121
+ 4. If no candidate is relevant (or `candidates` is empty), continue under your normal workflow.
112
122
 
113
123
  ## Retrieval pipeline
114
124
 
@@ -118,7 +128,7 @@ Skillmux builds candidates in stages:
118
128
  2. Local or remote embeddings rank semantic similarity.
119
129
  3. Reciprocal-rank fusion combines both lists.
120
130
  4. An optional reranker scores the fused candidates.
121
- 5. Calibrated thresholds select `matched`, `ambiguous`, or `no_match`.
131
+ 5. Returns up to effective `top_k` ranked candidates.
122
132
 
123
133
  The default local inference configuration uses FTS5 and quantized
124
134
  `Xenova/gte-small` embeddings. Skillmux CLI installations cache the
@@ -128,13 +138,8 @@ OpenAI-compatible embedding endpoint.
128
138
 
129
139
  Remote inference also supports `jina-v1` or `bifrost-v1` reranker adapters.
130
140
 
131
- Without a reranker, Skillmux returns a shortlist and does not auto-match.
132
- Without calibrated thresholds, a configured reranker orders the shortlist but
133
- still does not auto-match.
134
-
135
141
  Read [Configuration](configuration.md#local-inference) for local and remote
136
- inference settings. Read [Policy calibration](calibration.md) before enabling
137
- automatic matches.
142
+ inference settings.
138
143
 
139
144
  ## Fallback and readiness
140
145
 
@@ -169,10 +174,10 @@ access.
169
174
  Each resolve request records:
170
175
 
171
176
  - timestamp and query;
172
- - retrieval capability and outcome;
177
+ - retrieval capability;
178
+ - degradation metadata (`degraded_from`, `degradation_reason`) when degraded;
173
179
  - candidates with scores;
174
- - selected skill ID, when present;
175
- - latency.
180
+ - latency in milliseconds.
176
181
 
177
182
  Skillmux stores audit rows in the SQLite database under `state_dir`. Use
178
183
  `skillmux report` to summarize activity. Treat raw queries as private user
@@ -0,0 +1,160 @@
1
+ # Ranked-shortlist migration
2
+
3
+ The ranked-shortlist release replaces threshold-based classification with ranked candidate retrieval. Instead of classifying a query as `matched`, `ambiguous`, or `no_match` and returning inline skill text on match, `resolve_skill` always returns a ranked shortlist of candidate summaries. The calling client reviews the shortlist and invokes `fetch_skill` to load the full instructions for the chosen skill.
4
+
5
+ ## Upgrading configuration
6
+
7
+ Legacy threshold configuration tables and candidate limits are obsolete. Threshold values do not map semantically to candidate list lengths; replace threshold tables with retrieval depth and output bounds.
8
+
9
+ In `~/.config/skillmux/config.toml`, configure `[recall]` to control candidate generation and `[output]` to set candidate shortlist limits:
10
+
11
+ ```toml
12
+ vault_path = "~/skills"
13
+ state_dir = "~/.local/state/skillmux"
14
+
15
+ [recall]
16
+ k_lexical = 20
17
+ k_vector = 20
18
+ k_rerank = 10
19
+
20
+ [output]
21
+ top_k = 10
22
+ max_top_k = 50
23
+ ```
24
+
25
+ `recall.k_lexical` and `recall.k_vector` set the number of candidates retrieved from FTS5 lexical search and vector similarity before reciprocal rank fusion. `recall.k_rerank` limits the candidate shortlist sent to an optional remote reranker adapter and cannot exceed `k_lexical + k_vector`.
26
+
27
+ `output.top_k` sets the default maximum number of candidates returned by `resolve_skill`. `output.max_top_k` sets the upper bound for per-request `top_k` overrides. When a remote reranker is configured, `output.max_top_k` cannot exceed `recall.k_rerank`.
28
+
29
+ Existing `calibrate.sqlite3` databases in `state_dir` remain untouched on disk. Skillmux does not delete or modify historical calibration data.
30
+
31
+ ## Obsolete configuration keys
32
+
33
+ Startup fails with an explicit error when obsolete configuration keys are present:
34
+
35
+ | Obsolete configuration key | Replacement | Migration guidance |
36
+ | --- | --- | --- |
37
+ | `[thresholds]` | `[output].top_k` | The `[thresholds]` table is obsolete. Threshold calibration was removed; use `[output]` with `top_k`. |
38
+ | `output.ambiguous_candidate_limit` | `output.top_k` | `output.ambiguous_candidate_limit` is obsolete. Use `output.top_k` instead. |
39
+ | `inference.thresholds` | Removed | `inference.thresholds` is obsolete. Threshold calibration was removed. |
40
+ | `inference.calibration` | `skillmux eval` | `inference.calibration` is obsolete and should be deleted. Threshold calibration was removed; use `skillmux eval` for ranking evaluation. |
41
+ | `skillmux calibrate` | `skillmux eval` | `skillmux calibrate` was removed. Threshold calibration was removed; use `skillmux eval` for ranking evaluation. |
42
+
43
+ ## Wire contract changes
44
+
45
+ In the legacy classifier contract, `resolve_skill` returned an `outcome` classification and delivered the complete `SKILL.md` body directly when a single match met threshold criteria:
46
+
47
+ ```json
48
+ {
49
+ "outcome": "matched",
50
+ "retrieval": "reranked",
51
+ "skill_id": "csv-formatter",
52
+ "title": "CSV Formatter",
53
+ "content_sha256": "8a3f...",
54
+ "body": "# CSV Formatter\n...",
55
+ "files": [],
56
+ "candidates": [
57
+ {
58
+ "rank": 1,
59
+ "skill_id": "csv-formatter",
60
+ "score": 0.95
61
+ }
62
+ ]
63
+ }
64
+ ```
65
+
66
+ In the current contract, `resolve_skill` returns ranked candidate summaries with descriptions and scores. The client reviews candidate descriptions and calls `fetch_skill` with the desired `skill_id` to retrieve instructions and supporting files:
67
+
68
+ ```json
69
+ {
70
+ "retrieval": "reranked",
71
+ "candidates": [
72
+ {
73
+ "rank": 1,
74
+ "skill_id": "csv-formatter",
75
+ "description": "Convert CSV and spreadsheet data into clean Markdown tables.",
76
+ "score": 0.92
77
+ },
78
+ {
79
+ "rank": 2,
80
+ "skill_id": "table-helper",
81
+ "description": "Format ASCII and Markdown tables.",
82
+ "score": 0.74
83
+ }
84
+ ]
85
+ }
86
+ ```
87
+
88
+ When retrieval finds no candidates, `resolve_skill` returns an empty candidate list:
89
+
90
+ ```json
91
+ {
92
+ "retrieval": "hybrid",
93
+ "candidates": []
94
+ }
95
+ ```
96
+
97
+ When upstream embedding or reranking endpoints fail or time out, Skillmux falls back to the next available retrieval lane and reports structured degradation metadata:
98
+
99
+ ```json
100
+ {
101
+ "retrieval": "hybrid",
102
+ "degraded_from": "reranked",
103
+ "degradation_reason": "reranker_timeout",
104
+ "candidates": [
105
+ {
106
+ "rank": 1,
107
+ "skill_id": "csv-formatter",
108
+ "description": "Convert CSV and spreadsheet data into clean Markdown tables.",
109
+ "score": 0.033
110
+ }
111
+ ]
112
+ }
113
+ ```
114
+
115
+ ## Audit database migration
116
+
117
+ On startup, Skillmux inspects the `audit` table in `state_dir/index.sqlite3`. If legacy classifier columns (`outcome`, `selected_skill_id`, `degraded`) are present, it migrates the table inside an atomic SQLite transaction:
118
+
119
+ ```sql
120
+ CREATE TABLE audit (
121
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
122
+ ts TEXT NOT NULL,
123
+ query TEXT NOT NULL,
124
+ retrieval TEXT NOT NULL DEFAULT 'lexical',
125
+ degraded_from TEXT,
126
+ degradation_reason TEXT,
127
+ candidates TEXT NOT NULL,
128
+ latency_ms INTEGER NOT NULL
129
+ );
130
+ ```
131
+
132
+ Historical rows retain their `id`, `ts`, `query`, `retrieval`, `candidates`, and `latency_ms` values. Classifier-only columns are removed.
133
+
134
+ ## Ranking evaluation
135
+
136
+ Use `skillmux eval` to evaluate retrieval and ranking quality across lexical and hybrid pipelines:
137
+
138
+ ```sh
139
+ skillmux eval
140
+ ```
141
+
142
+ The `skillmux eval` command reads the default `eval/queries.json` dataset from the repository because the CLI currently has no `--dataset` flag.
143
+
144
+ Evaluation cases specify `relevant_skill_ids` as an array of skill identifiers rather than legacy outcome fields:
145
+
146
+ ```json
147
+ {
148
+ "query": "format a csv file",
149
+ "relevant_skill_ids": ["csv-formatter"],
150
+ "split": "test"
151
+ }
152
+ ```
153
+
154
+ Legacy fields `expected` and `expected_outcome` are rejected with validation errors. Cases with empty `relevant_skill_ids: []` represent unjudged queries and are excluded from aggregate ranking metrics without penalizing the evaluation score.
155
+
156
+ The evaluation report computes four ranking metrics for lexical and hybrid retrieval:
157
+ - Recall@5 measures the fraction of relevant skills found in the top 5 candidates.
158
+ - Recall@10 measures the fraction of relevant skills found in the top 10 candidates.
159
+ - Mean Reciprocal Rank (MRR) measures the reciprocal rank of the first relevant candidate.
160
+ - Binary nDCG@10 discounts relevance logarithmically across the top 10 positions.