@klhapp/skillmux 1.1.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 +22 -0
- package/README.md +155 -516
- package/config.example.toml +5 -4
- package/config.remote.example.toml +8 -3
- package/docs/README.md +52 -0
- package/docs/assets/architecture.svg +156 -0
- package/docs/assets/logo.png +0 -0
- package/docs/calibration.md +111 -0
- package/docs/cli.md +350 -0
- package/docs/concepts.md +165 -0
- package/docs/configuration.md +41 -8
- 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 -5
- package/src/adapters.ts +33 -40
- package/src/calibrate.ts +165 -9
- package/src/cli.ts +51 -6
- package/src/config-watcher.ts +5 -1
- package/src/dataset-generator.ts +75 -96
- package/src/server.ts +10 -70
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Managing skills
|
|
2
|
+
|
|
3
|
+
Skillmux keeps skill content in a canonical vault and materializes selected
|
|
4
|
+
skills into client directories. This guide covers the commands that change or
|
|
5
|
+
inspect that state.
|
|
6
|
+
|
|
7
|
+
Run these commands on the machine that owns the vault and client directories.
|
|
8
|
+
For a retrieval-only Docker service, manage the mounted vault on the host and
|
|
9
|
+
keep the container mount read-only.
|
|
10
|
+
|
|
11
|
+
## Install from Git
|
|
12
|
+
|
|
13
|
+
`skillmux install` accepts a GitHub shorthand or a full Git URL:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
skillmux install owner/repo
|
|
17
|
+
skillmux install owner/repo/path/to/skill
|
|
18
|
+
skillmux install https://git.example.com/team/skill.git
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The repository root must contain `SKILL.md`. If a repository contains several
|
|
22
|
+
skill directories, add the path for the one you want.
|
|
23
|
+
|
|
24
|
+
Skillmux clones into a temporary directory, validates the selected skill,
|
|
25
|
+
scans its text files, and copies it to `vault_path`. Existing skill IDs require
|
|
26
|
+
`--force`.
|
|
27
|
+
|
|
28
|
+
Preview the destination without copying:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
skillmux install owner/repo --dry-run
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Set a scan gate when you want findings to block installation:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
skillmux install owner/repo --fail-on high
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The scanner detects suspicious prompt-injection patterns, secrets, and risky
|
|
41
|
+
instructions. Findings remain advisory unless you pass `--fail-on`.
|
|
42
|
+
|
|
43
|
+
## Scan a vault or candidate
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
skillmux scan
|
|
47
|
+
skillmux scan ~/skills/candidate
|
|
48
|
+
skillmux scan --format json
|
|
49
|
+
skillmux scan --fail-on medium
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
With no path, `scan` checks the configured vault. `--json` wraps the result in
|
|
53
|
+
the standard CLI automation envelope, while `--format json` selects the
|
|
54
|
+
scanner's raw JSON rendering.
|
|
55
|
+
|
|
56
|
+
## Plan client delivery
|
|
57
|
+
|
|
58
|
+
Use product names for common clients:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
skillmux init --client claude-code --client codex --dry-run
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Use a direct target when you need a known path:
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
skillmux init --target agent-skills --yes
|
|
68
|
+
skillmux init --target custom --dir /srv/my-agent/skills --yes
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Skillmux refuses to adopt a target that points to the whole vault because sync
|
|
72
|
+
would reduce its visible skills. Review that migration first:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
skillmux init --client claude-code --migrate-full-vault \
|
|
76
|
+
--core csv-formatter --dry-run
|
|
77
|
+
skillmux init --client claude-code --migrate-full-vault \
|
|
78
|
+
--core csv-formatter --yes
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Manage core pins
|
|
82
|
+
|
|
83
|
+
Core skills go to each configured target:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
skillmux core pin csv-formatter --yes
|
|
87
|
+
skillmux core pin code-context systematic-debugging --yes
|
|
88
|
+
skillmux core unpin csv-formatter --yes
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
One command can change several skill IDs. Skillmux validates the complete
|
|
92
|
+
change before writing, so a conflict prevents the whole operation. Core stays
|
|
93
|
+
capped at 25 skills.
|
|
94
|
+
|
|
95
|
+
Run `skillmux sync` after a direct pin or unpin command.
|
|
96
|
+
|
|
97
|
+
## Manage project groups
|
|
98
|
+
|
|
99
|
+
Create a group with the guided command:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
skillmux project init
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Maintain it with explicit commands:
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
skillmux project list
|
|
109
|
+
skillmux project show my-project
|
|
110
|
+
skillmux project add-path my-project ~/code/my-project --yes
|
|
111
|
+
skillmux project pin my-project code-context --yes
|
|
112
|
+
skillmux project attach my-project --client claude-code --client codex --yes
|
|
113
|
+
skillmux project unpin my-project code-context --yes
|
|
114
|
+
skillmux project detach my-project --target codex --yes
|
|
115
|
+
skillmux project remove-path my-project ~/code/my-project --yes
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Create the group with `project init` or `project add-path` before pinning.
|
|
119
|
+
Project setup syncs by default. Direct maintenance commands update the
|
|
120
|
+
manifest but leave materialization to the next `skillmux sync`.
|
|
121
|
+
|
|
122
|
+
## Synchronize targets
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
skillmux sync --dry-run
|
|
126
|
+
skillmux sync
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Sync compares the manifest with entries recorded in each target's `.skillmux`
|
|
130
|
+
marker. It creates missing symlinks and removes stale managed links.
|
|
131
|
+
|
|
132
|
+
Install a vault Git hook when merges can change `skillmux.toml`:
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
skillmux sync --install-hook
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The hook lives in the canonical vault and runs `skillmux sync` after a merge.
|
|
139
|
+
|
|
140
|
+
## Inspect active state
|
|
141
|
+
|
|
142
|
+
Find which vault root serves a skill:
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
skillmux skill which code-context
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
If a local overlay shadows the canonical copy, the output lists both paths.
|
|
149
|
+
|
|
150
|
+
Inspect configuration and readiness:
|
|
151
|
+
|
|
152
|
+
```sh
|
|
153
|
+
skillmux config show
|
|
154
|
+
skillmux config diff
|
|
155
|
+
skillmux config status
|
|
156
|
+
skillmux doctor
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Use routing data to tune tiers
|
|
160
|
+
|
|
161
|
+
`resolve_skill` writes an audit row for each request. Summarize recent usage:
|
|
162
|
+
|
|
163
|
+
```sh
|
|
164
|
+
skillmux report --since 7d
|
|
165
|
+
skillmux report --server http://host:3000 --since 7d
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Repeatedly matched skills may belong in core or a project group. Repeated
|
|
169
|
+
`no_match` queries point to missing skills or weak skill descriptions.
|
|
170
|
+
|
|
171
|
+
`--since` accepts windows such as `1h`, `7d`, and `1m`, plus absolute dates and
|
|
172
|
+
timestamps.
|
|
173
|
+
|
|
174
|
+
## Target ownership and recovery
|
|
175
|
+
|
|
176
|
+
`skillmux target remove <name> --yes` removes the manifest record and preserves
|
|
177
|
+
the target directory, marker, and files. Cleanup stays under your control.
|
|
178
|
+
|
|
179
|
+
Restore a managed target to one symlink that exposes the full vault:
|
|
180
|
+
|
|
181
|
+
```sh
|
|
182
|
+
skillmux sync --restore-monolith
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
This operation removes the target marker and per-skill links. It refuses to
|
|
186
|
+
run when unmanaged content makes the replacement unsafe. Re-adopt the target
|
|
187
|
+
with `skillmux init` before running managed sync again.
|
|
188
|
+
|
|
189
|
+
Do not delete `.skillmux` markers by hand. The marker gives sync the ownership
|
|
190
|
+
record it needs to preserve unrelated content.
|
|
191
|
+
|
|
192
|
+
## Local overlays
|
|
193
|
+
|
|
194
|
+
Configure machine-specific override roots:
|
|
195
|
+
|
|
196
|
+
```toml
|
|
197
|
+
vault_path = "~/skills"
|
|
198
|
+
local_vault_paths = ["~/skills-local"]
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Then record the relationship:
|
|
202
|
+
|
|
203
|
+
```sh
|
|
204
|
+
skillmux local-vault init ~/skills-local --yes
|
|
205
|
+
skillmux skill which my-skill
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Read [Configuration](configuration.md#local-vault-overlays) for precedence,
|
|
209
|
+
pinning restrictions, and watcher behavior.
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Start with:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
skillmux doctor
|
|
7
|
+
skillmux config show
|
|
8
|
+
skillmux config validate
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Add `--json` when you need machine-readable diagnostics.
|
|
12
|
+
|
|
13
|
+
## Vault failures
|
|
14
|
+
|
|
15
|
+
### Vault path does not exist
|
|
16
|
+
|
|
17
|
+
Check the effective path and its source:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
skillmux config show
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Create the directory or initialize config against a populated vault:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
skillmux config init --vault ~/skills --yes
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`config init` requires at least one valid `SKILL.md`.
|
|
30
|
+
|
|
31
|
+
### A skill does not appear
|
|
32
|
+
|
|
33
|
+
Each skill must sit one directory below the vault:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
~/skills/<skill-id>/SKILL.md
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Run:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
skillmux scan ~/skills/<skill-id>
|
|
43
|
+
skillmux index
|
|
44
|
+
skillmux skill which <skill-id>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The scanner reports invalid frontmatter and unreadable content. `skill which`
|
|
48
|
+
also reveals local-overlay shadowing.
|
|
49
|
+
|
|
50
|
+
## Sync failures
|
|
51
|
+
|
|
52
|
+
### Target has no ownership marker
|
|
53
|
+
|
|
54
|
+
Skillmux will not change an existing unmarked directory. Adopt it first:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
skillmux init --client claude-code --dry-run
|
|
58
|
+
skillmux init --client claude-code --yes
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Target points to the full vault
|
|
62
|
+
|
|
63
|
+
Review the smaller pinned set before converting:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
skillmux init --client claude-code \
|
|
67
|
+
--migrate-full-vault \
|
|
68
|
+
--core code-context \
|
|
69
|
+
--dry-run
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Apply the same command with `--yes` after checking the plan.
|
|
73
|
+
|
|
74
|
+
### Unmanaged file collides with a pin
|
|
75
|
+
|
|
76
|
+
Skillmux preserves unmanaged target content. Rename or remove the conflicting
|
|
77
|
+
entry yourself, then rerun `skillmux sync`.
|
|
78
|
+
|
|
79
|
+
### Target belongs to another host
|
|
80
|
+
|
|
81
|
+
New targets include the current hostname. `sync` skips a target when its
|
|
82
|
+
manifest `host` differs. Run `skillmux target show <name>` and add a separate
|
|
83
|
+
target for the current machine instead of reusing the other machine's path.
|
|
84
|
+
|
|
85
|
+
### A local-overlay skill cannot be pinned
|
|
86
|
+
|
|
87
|
+
Core and project pins must exist in the canonical `vault_path`. Copy or commit
|
|
88
|
+
the skill there before pinning it. Routed lookup can still serve the overlay.
|
|
89
|
+
|
|
90
|
+
## Retrieval failures
|
|
91
|
+
|
|
92
|
+
### `resolve_skill` returns `ambiguous`
|
|
93
|
+
|
|
94
|
+
Ambiguity is the expected result without calibrated reranker thresholds. The
|
|
95
|
+
calling model should select a candidate and call `fetch_skill`.
|
|
96
|
+
|
|
97
|
+
Improve a weak shortlist by:
|
|
98
|
+
|
|
99
|
+
- writing a concrete skill description with task vocabulary;
|
|
100
|
+
- enabling embeddings;
|
|
101
|
+
- increasing recall depth when the relevant skill falls outside the fused
|
|
102
|
+
candidate set.
|
|
103
|
+
|
|
104
|
+
Use a labelled dataset and [Policy calibration](calibration.md) before enabling
|
|
105
|
+
automatic matches.
|
|
106
|
+
|
|
107
|
+
### Server reports lexical mode
|
|
108
|
+
|
|
109
|
+
Lexical mode means Skillmux can query FTS5 but cannot use embeddings. The next
|
|
110
|
+
step depends on the installation:
|
|
111
|
+
|
|
112
|
+
| Installation | Expected action |
|
|
113
|
+
| --- | --- |
|
|
114
|
+
| Skillmux CLI with local inference | Download the local model and rebuild the index |
|
|
115
|
+
| Full Docker image | Confirm the running tag is the full image and inspect `doctor` output |
|
|
116
|
+
| Slim Docker image | Configure remote embeddings or keep lexical fallback |
|
|
117
|
+
|
|
118
|
+
For a Skillmux CLI installation, run:
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
skillmux doctor
|
|
122
|
+
skillmux models download
|
|
123
|
+
skillmux index
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
For remote inference, verify the endpoint, model, dimension, API-key
|
|
127
|
+
environment variable, and network path. The slim image does not contain
|
|
128
|
+
GTE-small, so `models download` is not its recovery path.
|
|
129
|
+
|
|
130
|
+
### Reranker is unavailable
|
|
131
|
+
|
|
132
|
+
Skillmux keeps the hybrid shortlist when a reranker probe or request fails.
|
|
133
|
+
Check `inference.reranker.endpoint`, `adapter`, `model`, and the environment
|
|
134
|
+
variable named by `api_key_env`.
|
|
135
|
+
|
|
136
|
+
Use the complete request URL. Skillmux does not append `/rerank` or infer an
|
|
137
|
+
adapter from the endpoint.
|
|
138
|
+
|
|
139
|
+
### Delivered content changed after indexing
|
|
140
|
+
|
|
141
|
+
Skillmux checks the file before delivery and refreshes stale metadata. If a
|
|
142
|
+
skill cannot be parsed during a live edit, the index keeps the previous good
|
|
143
|
+
metadata but does not serve stale body bytes. Finish the write with valid
|
|
144
|
+
frontmatter and retry.
|
|
145
|
+
|
|
146
|
+
## HTTP failures
|
|
147
|
+
|
|
148
|
+
### Another machine cannot connect
|
|
149
|
+
|
|
150
|
+
The Skillmux CLI binds HTTP to `127.0.0.1`. Set `server.hostname` or
|
|
151
|
+
`HTTP_HOSTNAME` to a reachable interface, then restart the server. Docker
|
|
152
|
+
binds `0.0.0.0` inside the container, but the host still needs a published
|
|
153
|
+
port. Enable authentication before exposing either deployment.
|
|
154
|
+
|
|
155
|
+
### Browser receives `403`
|
|
156
|
+
|
|
157
|
+
Add the browser origin to `server.allowed_origins`. The value must match the
|
|
158
|
+
request's `Origin` header. Curl and server-to-server clients omit this header
|
|
159
|
+
and do not use the CORS list.
|
|
160
|
+
|
|
161
|
+
### Client receives `401`
|
|
162
|
+
|
|
163
|
+
Confirm `server.auth_enabled = true`, export the environment variable named by
|
|
164
|
+
`auth_token_env`, and send `Authorization: Bearer <token>`.
|
|
165
|
+
|
|
166
|
+
An enabled server with an empty token environment variable returns a server
|
|
167
|
+
configuration error rather than accepting an empty token.
|
|
168
|
+
|
|
169
|
+
### Client receives `429`
|
|
170
|
+
|
|
171
|
+
The rate limiter rejected the request. Read `Retry-After` and the
|
|
172
|
+
`X-RateLimit-*` response headers. Increase `requests_per_minute` only after
|
|
173
|
+
checking for a retry loop or shared-token traffic.
|
|
174
|
+
|
|
175
|
+
## Configuration migration errors
|
|
176
|
+
|
|
177
|
+
Skillmux rejects removed fields with migration guidance:
|
|
178
|
+
|
|
179
|
+
- replace `[targets.<name>].project` with `project_groups = [...]`;
|
|
180
|
+
- rename `[project.<group>].repos` to `paths`;
|
|
181
|
+
- use `skillmux core pin|unpin` instead of removed `manifest pin|unpin`;
|
|
182
|
+
- replace legacy reranker base-URL variables with
|
|
183
|
+
`SKILLMUX_RERANK_ENDPOINT` and `SKILLMUX_RERANK_ADAPTER`.
|
|
184
|
+
|
|
185
|
+
Run `skillmux config validate` after editing TOML.
|
|
186
|
+
|
|
187
|
+
## Collect diagnostics
|
|
188
|
+
|
|
189
|
+
For a bug report, include:
|
|
190
|
+
|
|
191
|
+
```sh
|
|
192
|
+
skillmux --help
|
|
193
|
+
skillmux config show
|
|
194
|
+
skillmux doctor --json
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Remove tokens, private endpoint credentials, local usernames, and raw audit
|
|
198
|
+
queries before posting output. Open an issue at
|
|
199
|
+
<https://github.com/klhq/skillmux/issues>.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@klhapp/skillmux",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Skill management and retrieval for AI agents: sync native skills across clients and route the long tail over MCP",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"author": "Lance Hsu <lance@klh.app>",
|
|
@@ -22,9 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"src",
|
|
25
|
-
"docs
|
|
26
|
-
"docs/configuration.md",
|
|
27
|
-
"docs/releasing.md",
|
|
25
|
+
"docs",
|
|
28
26
|
"README.md",
|
|
29
27
|
"LICENSE",
|
|
30
28
|
"CHANGELOG.md",
|
package/src/adapters.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { applyCalibrationRun, getCalibrationRun, insertCalibrationRun, listCalibrationRuns, loadDecisionCasesFromFile, openCalibrateDb, runCalibration, type CalibrationResult } from "./calibrate";
|
|
3
|
+
import { applyCalibrationRun, getCalibrationRun, insertCalibrationRun, listCalibrationRuns, loadDecisionCasesFromFile, openCalibrateDb, runCalibration, summarizeDatasetProvenance, type CalibrationResult } from "./calibrate";
|
|
4
4
|
import { createClients } from "./clients";
|
|
5
5
|
import { DEFAULT_CONFIG_PATH, embeddingFingerprint, expandHome, loadConfig, rerankerFingerprint } from "./config";
|
|
6
6
|
import { openIndex } from "./db";
|
|
@@ -139,7 +139,19 @@ export class LocalAdapter implements TargetAdapter {
|
|
|
139
139
|
}): Promise<{ run_id?: string; result?: CalibrationResult }> {
|
|
140
140
|
const config = await loadConfig(this.configPath);
|
|
141
141
|
const datasetFile = opts?.datasetPath ?? join(expandHome(config.state_dir), "queries.json");
|
|
142
|
-
const
|
|
142
|
+
const indexDb = openIndex(expandHome(config.state_dir));
|
|
143
|
+
let indexedSkills: Array<{ skill_id: string; content_sha256: string }>;
|
|
144
|
+
try {
|
|
145
|
+
indexedSkills = indexDb
|
|
146
|
+
.query("SELECT skill_id, content_sha256 FROM skills ORDER BY skill_id")
|
|
147
|
+
.all() as Array<{ skill_id: string; content_sha256: string }>;
|
|
148
|
+
} finally {
|
|
149
|
+
indexDb.close();
|
|
150
|
+
}
|
|
151
|
+
const cases = loadDecisionCasesFromFile(
|
|
152
|
+
datasetFile,
|
|
153
|
+
indexedSkills.map((skill) => skill.skill_id),
|
|
154
|
+
);
|
|
143
155
|
const clients = createClients(config);
|
|
144
156
|
configure({ config, clients });
|
|
145
157
|
const result = await runCalibration({
|
|
@@ -168,18 +180,9 @@ export class LocalAdapter implements TargetAdapter {
|
|
|
168
180
|
throw new Error("A configured remote reranker is required to record calibration.");
|
|
169
181
|
}
|
|
170
182
|
const datasetText = await Bun.file(datasetFile).text();
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const rows = indexDb
|
|
175
|
-
.query("SELECT skill_id, content_sha256 FROM skills ORDER BY skill_id")
|
|
176
|
-
.all();
|
|
177
|
-
corpusFingerprint =
|
|
178
|
-
"vault:" +
|
|
179
|
-
createHash("sha256").update(JSON.stringify(rows)).digest("hex");
|
|
180
|
-
} finally {
|
|
181
|
-
indexDb.close();
|
|
182
|
-
}
|
|
183
|
+
const corpusFingerprint =
|
|
184
|
+
"vault:" +
|
|
185
|
+
createHash("sha256").update(JSON.stringify(indexedSkills)).digest("hex");
|
|
183
186
|
const runId = `run_${crypto.randomUUID()}`;
|
|
184
187
|
const db = openCalibrateDb(expandHome(config.state_dir));
|
|
185
188
|
try {
|
|
@@ -191,6 +194,7 @@ export class LocalAdapter implements TargetAdapter {
|
|
|
191
194
|
embedding_fingerprint: embeddingFingerprint(config),
|
|
192
195
|
corpus_fingerprint: corpusFingerprint,
|
|
193
196
|
dataset_hash: createHash("sha256").update(datasetText).digest("hex"),
|
|
197
|
+
dataset_provenance: summarizeDatasetProvenance(cases),
|
|
194
198
|
candidate_limit: config.thresholds.candidate_limit,
|
|
195
199
|
min_auto_match_precision: opts?.minAutoMatchPrecision ?? 0.99,
|
|
196
200
|
min_auto_match_count: opts?.minAutoMatchCount ?? 30,
|
|
@@ -420,41 +424,30 @@ export class RemoteAdapter implements TargetAdapter {
|
|
|
420
424
|
minDeliveredShortlistRecallAtK?: number;
|
|
421
425
|
minAutoMatchCount?: number;
|
|
422
426
|
}): Promise<{ run_id?: string; result?: CalibrationResult }> {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
headers: { "Content-Type": "application/json" },
|
|
426
|
-
body: JSON.stringify({
|
|
427
|
-
dataset_path: opts?.datasetPath,
|
|
428
|
-
min_auto_match_precision: opts?.minAutoMatchPrecision,
|
|
429
|
-
min_retrieval_recall_at_k: opts?.minRetrievalRecallAtK,
|
|
430
|
-
min_delivered_shortlist_recall_at_k: opts?.minDeliveredShortlistRecallAtK,
|
|
431
|
-
min_auto_match_count: opts?.minAutoMatchCount,
|
|
432
|
-
}),
|
|
433
|
-
});
|
|
434
|
-
if (status !== 202) {
|
|
435
|
-
throw new Error(`Remote calibration start failed (${status}): ${data?.message || data}`);
|
|
436
|
-
}
|
|
437
|
-
return data;
|
|
427
|
+
void opts;
|
|
428
|
+
throw this.remoteCalibrationNotImplemented();
|
|
438
429
|
}
|
|
439
430
|
|
|
440
431
|
async calibrateList(): Promise<any[]> {
|
|
441
|
-
|
|
442
|
-
if (status !== 200) throw new Error(`Remote calibration list failed (${status}): ${data?.message || data}`);
|
|
443
|
-
return data;
|
|
432
|
+
throw this.remoteCalibrationNotImplemented();
|
|
444
433
|
}
|
|
445
434
|
|
|
446
435
|
async calibrateShow(runId: string): Promise<any> {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
return data;
|
|
436
|
+
void runId;
|
|
437
|
+
throw this.remoteCalibrationNotImplemented();
|
|
450
438
|
}
|
|
451
439
|
|
|
452
440
|
async calibrateApply(runId: string): Promise<any> {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
441
|
+
void runId;
|
|
442
|
+
throw this.remoteCalibrationNotImplemented();
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
private remoteCalibrationNotImplemented(): CliError {
|
|
446
|
+
return new CliError(
|
|
447
|
+
`Remote calibration is not implemented for target ${this.serverUrl}; ` +
|
|
448
|
+
"run `skillmux calibrate` against a local target.",
|
|
449
|
+
2,
|
|
450
|
+
);
|
|
458
451
|
}
|
|
459
452
|
}
|
|
460
453
|
|