@dungle-scrubs/skillval 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dungle-scrubs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,250 @@
1
+ # skillval
2
+
3
+ `skillval` evaluates [Agent Skills](https://agentskills.io/) with deterministic graders and no
4
+ model judges. Each case can run a skill arm and a baseline arm, measuring whether a skill changes
5
+ agent behavior instead of merely checking whether the final answer looks acceptable. When the
6
+ baseline also passes, the rule is flagged as a no-op and a possible prune candidate. You can only
7
+ trust what you test.
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ pnpm add -g @dungle-scrubs/skillval
13
+ ```
14
+
15
+ Node.js 22 or newer is required. The Codex CLI must be installed and authenticated for evaluation
16
+ runs. Discovery with `skillval list` does not invoke Codex.
17
+
18
+ ## Quickstart
19
+
20
+ Create `~/.config/skillval/config.yml`:
21
+
22
+ ```yaml
23
+ roots:
24
+ - ~/dev/agent-skills
25
+ executor: codex
26
+ ```
27
+
28
+ Given `~/dev/agent-skills/typescript-style/SKILL.md`, add
29
+ `~/dev/agent-skills/typescript-style/skillval.yml`:
30
+
31
+ ```yaml
32
+ skill: typescript-style
33
+ class: preference
34
+ cases:
35
+ - id: prefer-const-object
36
+ mode: generation
37
+ type: preference
38
+ rule: enums-as-const
39
+ arms: [skill, baseline]
40
+ prompt: >-
41
+ Create sizes.ts with a fixed set of small, medium, and large values.
42
+ assert:
43
+ must_match: ["as const"]
44
+ must_not_match: ["\\benum\\s"]
45
+ graders: [tsc]
46
+ trials: 1
47
+ ```
48
+
49
+ Run the case:
50
+
51
+ ```console
52
+ $ skillval run typescript-style
53
+ typescript-style (preference, e8342aa91a17):
54
+ prefer-const-object [skill] ...
55
+ prefer-const-object [skill] pass
56
+ prefer-const-object [baseline] ...
57
+ prefer-const-object [baseline] FAIL
58
+ report: /Users/example/.local/state/skillval/reports/0f47c8d4....json
59
+ all cases passed
60
+ ```
61
+
62
+ Run every discovered skill that has a `skillval.yml` by omitting the skill names. Use `--case <id>`
63
+ to select one case, `--no-cache` to ignore cached arm results, `--skip-baseline` to omit baseline
64
+ arms, and `--json` for the complete report. The command exits with status 1 when any selected
65
+ case's skill arm fails.
66
+
67
+ ## Configuration
68
+
69
+ The configuration follows the [configuration JSON Schema](schemas/config.schema.json):
70
+
71
+ ```yaml
72
+ roots:
73
+ - ~/dev/skills/skills/standards
74
+ - $HOME/dev/shared/skills/backend
75
+ executor: codex
76
+ ```
77
+
78
+ `roots` contains directories whose immediate children have the form `<skill>/SKILL.md`. Both `~`
79
+ and `$HOME` are expanded. Missing roots are skipped during `run`; `list` returns them in
80
+ `missingRoots` with JSON output and prints each as `missing root: <path>` in human output.
81
+
82
+ Configuration path precedence is:
83
+
84
+ 1. `--config <path>`
85
+ 2. `SKILLVAL_CONFIG`
86
+ 3. `$XDG_CONFIG_HOME/skillval/config.yml`
87
+ 4. `~/.config/skillval/config.yml`
88
+
89
+ There is no legacy `~/.skillval` lookup. State uses `$XDG_STATE_HOME/skillval`, or
90
+ `~/.local/state/skillval` when `XDG_STATE_HOME` is unset:
91
+
92
+ - `cache/` stores arm results.
93
+ - `reports/` stores run reports named by a hash of the participating skills and their content
94
+ hashes. Each report also includes every participating skill's content hash and the executor's
95
+ name, version, and model identity.
96
+
97
+ `skillval list` returns the skill name, configured root, class, case count, whether `skillval.yml`
98
+ exists, and a `missing`, `invalid`, or `ready` status in JSON output. Invalid case files include a
99
+ validation error. Discovery only requires `SKILL.md`; evaluation requires a valid `skillval.yml`.
100
+
101
+ ## Case files
102
+
103
+ Only a file named `skillval.yml` next to `SKILL.md` is recognized. There is no `evals.yml`
104
+ fallback. The complete format is described by the
105
+ [case-file JSON Schema](schemas/skillval.schema.json).
106
+ The published configuration and case-file schemas are generated from the same executable TypeBox
107
+ contracts used for runtime validation. Contributors can regenerate them with `pnpm schema` and
108
+ check freshness with `pnpm schema:check`.
109
+
110
+ Top-level fields:
111
+
112
+ - `skill`: the directory and skill name.
113
+ - `class`: `preference` or `capability`.
114
+ - `cases`: an array of deterministic evaluation cases.
115
+ - `fixture`: optional suite-wide workspace fixture applied to every case that does not declare
116
+ its own. See [Fixtures](#fixtures).
117
+
118
+ Case fields:
119
+
120
+ - `id`: unique case identifier.
121
+ - `mode`: `trigger` grades the final agent message; `generation` grades files produced in the
122
+ temporary workspace.
123
+ - `type`: optional `preference` or `capability` classification.
124
+ - `rule`: optional stable rule identifier included in reports.
125
+ - `should_trigger`: optional expected invocation verdict. It is checked only on the skill arm.
126
+ - `arms`: `skill`, or `skill` and `baseline`. The default is `[skill]`.
127
+ - `prompt`: the complete trial prompt.
128
+ - `assert.must_match`: JavaScript regular expressions that must match, with the `m` flag.
129
+ - `assert.must_not_match`: JavaScript regular expressions that must not match, with the `m` flag.
130
+ - `assert.graders`: deterministic graders. `tsc` is supported for generation cases. Unknown
131
+ graders and graders used with an unsupported mode are validation errors.
132
+ - `trials`: an integer from 1 through 5. Results use a strict majority. If configured trials
133
+ disagree, the arm escalates to 5 trials.
134
+ - `fixture`: optional workspace fixture for this case. It replaces the suite-level `fixture`
135
+ entirely; `path` and `setup` never merge across levels.
136
+
137
+ Every trial must also contain a complete executor trace. For generation cases, regex assertions
138
+ see only produced files, prefixed with `=== filename ===`; prose cannot satisfy a file assertion.
139
+ The `tsc` grader injects a module package file when needed and a strict bundler-resolution
140
+ TypeScript configuration, then runs the TypeScript installation shipped with `skillval`.
141
+
142
+ ## Fixtures
143
+
144
+ By default every trial starts in an empty temporary workspace. A fixture populates that workspace
145
+ before the trial runs, for cases that need a realistic repository or document tree. A fixture has
146
+ two fields, and at least one is required:
147
+
148
+ - `path`: a directory relative to `skillval.yml`, copied recursively into the workspace before
149
+ the trial. `.git` and `node_modules` directories are never copied. The path must exist and be a
150
+ directory, and it may not contain symbolic links (create links with `setup` commands instead);
151
+ anything else is a validation error at load time.
152
+ - `setup`: shell commands run sequentially inside the workspace after the copy, with a minimal
153
+ environment (`PATH` plus a throwaway `HOME`). A non-zero exit fails the trial with a
154
+ `fixture-setup` error before the agent runs; it is never a grading failure. Each command's
155
+ stdout and stderr are captured into the trial record.
156
+
157
+ A suite-level `fixture` applies to every case; a case-level `fixture` replaces it entirely.
158
+ Fixture directory contents and setup commands are part of the arm cache identity, so editing a
159
+ fixture file or a setup command invalidates cached results for the cases that use it.
160
+
161
+ Generation-mode regex assertions read every workspace file except `.git` and `node_modules`
162
+ contents and the injected `package.json`/`tsconfig.json`, so fixture files are graded alongside
163
+ anything the agent produced. Graders access the workspace directly (`tsc` compiles what it finds
164
+ there). Write `must_match` patterns against the state you expect after the agent acts, not only
165
+ against new files.
166
+
167
+ Nested `.git` directories inside a fixture are not supported. Express git state with `setup`
168
+ commands instead - this example stages a merge conflict for the agent to resolve:
169
+
170
+ ```yaml
171
+ skill: resolve-conflicts
172
+ class: capability
173
+ cases:
174
+ - id: merge-conflict
175
+ mode: generation
176
+ prompt: Resolve the merge conflict in notes.md, keeping both sections.
177
+ assert:
178
+ must_not_match: ["^<{7} ", "^={7}$", "^>{7} "]
179
+ fixture:
180
+ path: fixtures/notes-repo
181
+ setup:
182
+ - git init -q -b main
183
+ - git config user.name fixture && git config user.email fixture@skillval.invalid
184
+ - git add -A && git commit -qm base
185
+ - git switch -qc feature
186
+ - printf 'feature section\n' >> notes.md && git commit -qam feature
187
+ - git switch -q main
188
+ - printf 'main section\n' >> notes.md && git commit -qam main
189
+ - git merge feature || true
190
+ ```
191
+
192
+ The final `|| true` matters: `git merge` exits non-zero on conflict, which would otherwise fail
193
+ the trial as a fixture-setup error - here the conflict is the point.
194
+
195
+ ## Executors
196
+
197
+ Executors are adapters with three responsibilities: report stable metadata for cache keys, prepare
198
+ provider-specific skill and environment state, and run one trial request to return a normalized
199
+ `Trace`. The runner owns temporary workspace lifecycle, grading, caching, majority voting, and
200
+ reports. `codex` is the only adapter today.
201
+
202
+ The Codex adapter runs:
203
+
204
+ ```text
205
+ codex exec --json --skip-git-repo-check --ephemeral -s <sandbox> -C <workspace> <prompt>
206
+ ```
207
+
208
+ Trigger cases use a read-only sandbox. Generation cases use `workspace-write`. Codex has no
209
+ dedicated skill-invocation event, so its adapter detects invocation when a `command_execution`
210
+ command contains `<skill>/SKILL.md`. The adapter also gives the skill arm a workspace-local
211
+ `.agents/skills/<name>` symlink to the evaluated skill.
212
+
213
+ Baseline arms are not seeded. Their `HOME` points to an empty temporary directory so globally
214
+ installed skills are invisible, while `CODEX_HOME` still points to the user's real `~/.codex` for
215
+ authentication and model configuration. A Claude executor is planned.
216
+
217
+ Cached arm results are keyed by runner version, skill content hash, serialized case, arm, executor
218
+ name, executor version, and configured model. A trial has a 15-minute timeout and a 64 MB output
219
+ buffer.
220
+
221
+ ## Roadmap
222
+
223
+ - Add a Claude executor, then support multi-executor runs through the same normalized trace
224
+ interface.
225
+ - Run multiple models and emit per-model reports. A passing binding or trigger result on a weaker
226
+ tier is a conservative bound for stronger tiers. Baseline no-op results remain model-specific,
227
+ and a rule is a prune candidate only when every model in normal use passes at baseline.
228
+ - Add contested-boundary cases with `expect_invoked` and `expect_not_invoked` outcomes.
229
+ - Include the discovered skill-listing hash in trigger-case invalidation so description changes in
230
+ neighboring skills invalidate affected results.
231
+ - Add cheap trigger simulations for broad description coverage before expensive executor trials.
232
+ - Add a `lint` subcommand for Agent Skills format, references, case coverage, and regular
233
+ expressions.
234
+ - Evaluate agent instruction files (`CLAUDE.md`, `AGENTS.md`) with the same arm comparison, so
235
+ instruction rules can be proven load-bearing or flagged as no-ops the way skill rules are. The
236
+ shape is undecided: likely instructions-present vs instructions-absent arms over cases derived
237
+ from the file's rules.
238
+ - Harvest missed triggers, false invocations, and behavioral regressions from real session
239
+ transcripts as new cases.
240
+ - Support multi-model interpretation and no-op pruning in report summaries, not only raw reports.
241
+
242
+ ## Contributing
243
+
244
+ See [CONTRIBUTING.md](CONTRIBUTING.md). Commits follow Conventional Commits, PRs are
245
+ squash-merged, and every change must pass
246
+ `pnpm typecheck && pnpm lint && pnpm schema:check && pnpm test && pnpm build`.
247
+
248
+ ## License
249
+
250
+ [MIT](LICENSE)