skillbench-cli 0.1.0__tar.gz → 0.2.0__tar.gz

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.
Files changed (24) hide show
  1. skillbench_cli-0.2.0/.gitattributes +1 -0
  2. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/LICENSE +21 -21
  3. skillbench_cli-0.2.0/PKG-INFO +347 -0
  4. skillbench_cli-0.2.0/README.md +326 -0
  5. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/pyproject.toml +46 -46
  6. skillbench_cli-0.2.0/scripts/release.sh +142 -0
  7. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/src/skillbench/assertions.py +261 -250
  8. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/src/skillbench/claude.py +281 -277
  9. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/src/skillbench/cli.py +151 -93
  10. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/src/skillbench/config.py +299 -269
  11. skillbench_cli-0.2.0/src/skillbench/dashboard.py +822 -0
  12. skillbench_cli-0.2.0/src/skillbench/eval_creator/SKILL.md +149 -0
  13. skillbench_cli-0.2.0/src/skillbench/progress.py +195 -0
  14. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/src/skillbench/runner.py +548 -471
  15. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/src/skillbench/scaffold.py +2 -1
  16. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/src/skillbench/skills.py +68 -6
  17. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/src/skillbench/workspace.py +171 -124
  18. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/uv.lock +2 -2
  19. skillbench_cli-0.1.0/PKG-INFO +0 -218
  20. skillbench_cli-0.1.0/README.md +0 -197
  21. skillbench_cli-0.1.0/src/skillbench/dashboard.py +0 -543
  22. skillbench_cli-0.1.0/src/skillbench/progress.py +0 -219
  23. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/.gitignore +0 -0
  24. {skillbench_cli-0.1.0 → skillbench_cli-0.2.0}/src/skillbench/__init__.py +0 -0
@@ -0,0 +1 @@
1
+ *.sh text eol=lf
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Adam Saul
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.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Adam Saul
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.
@@ -0,0 +1,347 @@
1
+ Metadata-Version: 2.5
2
+ Name: skillbench-cli
3
+ Version: 0.2.0
4
+ Summary: Test your Claude Code skills and agent workflows, the way you test code.
5
+ Project-URL: Homepage, https://github.com/adamsaul314/skillbench
6
+ Project-URL: Issues, https://github.com/adamsaul314/skillbench/issues
7
+ Author: Adam Saul
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: agents,claude,claude-code,evals,skills,testing
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Software Development :: Testing
17
+ Requires-Python: >=3.11
18
+ Requires-Dist: pyyaml>=6.0
19
+ Requires-Dist: rich>=13.7
20
+ Description-Content-Type: text/markdown
21
+
22
+ # skillbench
23
+
24
+ Test your Claude Code skills and agent workflows, the way you test code.
25
+
26
+ You write a short YAML file: *"send Claude this, then check these things"*. skillbench runs Claude Code for real on a **copy** of a repo, records everything it did, and tells you **pass** or **fail**.
27
+
28
+ **Jump to:** [Get started](#get-started) · [Write a test](#write-a-test) · [Run tests](#run-tests) · [Reference](#reference)
29
+
30
+ ---
31
+
32
+ ## Get started
33
+
34
+ You need Python 3.11+, git, and Claude Code installed and logged in (`claude --version` should work).
35
+
36
+ **1. Install it.** Use whichever tool you normally use:
37
+
38
+ ```
39
+ pip install skillbench-cli
40
+ pipx install skillbench-cli
41
+ uv tool install skillbench-cli
42
+ ```
43
+
44
+ The package is `skillbench-cli`; the command is `skillbench`.
45
+
46
+ **2. Set up your repo.** In the repo you want to test:
47
+
48
+ ```
49
+ skillbench init
50
+ ```
51
+
52
+ This creates one folder, `skillbench/`, with two example tests:
53
+
54
+ ```
55
+ skillbench/
56
+ skillbench.yaml settings for every test
57
+ skills/ skill tests
58
+ agent/ agent tests
59
+ fixtures/ small sample repos for tests to run on
60
+ runs/ results (git-ignored)
61
+ ```
62
+
63
+ **3. Run the examples.**
64
+
65
+ ```
66
+ skillbench skill
67
+ skillbench agent
68
+ ```
69
+
70
+ **4. Look at the results.** Open `skillbench/runs/index.html` in your browser. The list on the left groups runs by what they test (a skill, a plugin, or this repo), newest first. Expand a group to see its tests. Click a test to see its run.
71
+
72
+ Now write your own tests: next section.
73
+
74
+ ---
75
+
76
+ ## Write a test
77
+
78
+ Find what you want to check in this list, then follow that recipe.
79
+
80
+ | I want to check that… | Recipe |
81
+ |---|---|
82
+ | my skill does the right thing when it runs | [A. Test a skill](#a-test-a-skill) |
83
+ | Claude picks my skill when it should, and not when it shouldn't | [B. Test a skill gets picked](#b-test-a-skill-gets-picked) |
84
+ | a normal request gets done, with the right skills | [C. Test a request end to end](#c-test-a-request-end-to-end) |
85
+ | my multi-step workflow works on a real repo | [D. Test a workflow on a repo](#d-test-a-workflow-on-a-repo) |
86
+ | the plugin I'm building works on other projects | [E. Test a plugin you're building](#e-test-a-plugin-youre-building) |
87
+
88
+ **Or let Claude write it.** Install the `/eval-creator` skill once:
89
+
90
+ ```
91
+ skillbench install-skill
92
+ ```
93
+
94
+ Then in Claude Code, in your repo, say what you want to test:
95
+
96
+ ```
97
+ /eval-creator test that my grilling skill asks questions before writing anything
98
+ ```
99
+
100
+ It reads your skills, then proposes the tests in plain words: what each one runs, what it checks, when it passes, and a rough cost. Nothing is written until you reply **approve**. Ask for changes and it proposes again. Once approved, it writes the files and checks them. It never runs them, so you decide when to spend tokens.
101
+
102
+ Run `skillbench install-skill` again after you upgrade skillbench.
103
+
104
+ Whichever way you write tests, check them for free before running:
105
+
106
+ ```
107
+ skillbench check
108
+ ```
109
+
110
+ ### A. Test a skill
111
+
112
+ Runs your skill directly (`/grilling an idea for a todo app`) and checks what it did.
113
+
114
+ Create `skillbench/skills/grilling.yaml`:
115
+
116
+ ```yaml
117
+ description: Grilling asks questions before it writes anything.
118
+ skill: grilling # the skill's name
119
+ input: an idea for a todo app # the text after /grilling
120
+ fixture: . # run on a copy of this repo
121
+
122
+ assert:
123
+ - final_text_contains: "?"
124
+ - tool_not_called: Write
125
+ ```
126
+
127
+ Run it: `skillbench skill grilling`
128
+
129
+ skillbench finds the skill wherever it is: `.claude/skills/`, `skills/`, `.github/skills/`, or inside a plugin.
130
+
131
+ ### B. Test a skill gets picked
132
+
133
+ Checks your skill's description is good enough for Claude to choose it on its own. Each prompt is a short run that stops as soon as Claude decides, so these are cheap.
134
+
135
+ Add `triggers:` to a skill test:
136
+
137
+ ```yaml
138
+ skill: grilling
139
+ triggers:
140
+ should: ["stress-test my plan before I build it"]
141
+ should_not: ["fix the typo in README.md"]
142
+ ```
143
+
144
+ Run it: `skillbench skill grilling`
145
+
146
+ ### C. Test a request end to end
147
+
148
+ Sends a normal message, with nothing forced. Claude sees every skill in the repo and decides for itself; the test checks what it chose and whether the job got done.
149
+
150
+ Create `skillbench/agent/csv-export.yaml`:
151
+
152
+ ```yaml
153
+ description: Adding CSV export uses the planner and leaves the tests passing.
154
+ prompt: add CSV export to the report page
155
+ fixture: .
156
+
157
+ answers: # sent one at a time, each time Claude stops and waits
158
+ - Yes to all your recommendations.
159
+ - approved
160
+
161
+ assert:
162
+ - skill_invoked: planner
163
+ - command_succeeds: python -m pytest -q
164
+ ```
165
+
166
+ Run it: `skillbench agent csv-export`
167
+
168
+ Not sure what Claude will ask? Leave out `answers:` and add `interactive: true`. skillbench then asks *you* in the terminal each time Claude waits for a reply (press Enter on an empty line to stop). Copy your replies into `answers:` afterwards.
169
+
170
+ ### D. Test a workflow on a repo
171
+
172
+ For workflows with several phases, where in Claude Code you'd type things between messages: commit, `/clear`, start the next skill. Put those in `answers:` exactly as you'd type them:
173
+
174
+ | In `answers:` | What happens |
175
+ |---|---|
176
+ | `approved` | Sent to Claude as a message |
177
+ | `/clear` | The next message starts a fresh session |
178
+ | `!git add -A && git commit -m "plan"` | Runs in the repo as a shell command, not sent to Claude |
179
+
180
+ Point `fixture:` at the repo to run on. A git URL is cloned fresh for each run, and pushing from the clone is turned off.
181
+
182
+ Create `skillbench/agent/full-loop.yaml`:
183
+
184
+ ```yaml
185
+ description: The plan, build and review loop adds a dark mode toggle to test-app.
186
+ prompt: /my-plugin:plan add a dark mode toggle. Use the slug dark-mode.
187
+ fixture: https://github.com/you/test-app.git
188
+
189
+ answers:
190
+ - Yes to all your recommendations.
191
+ - approved
192
+ - '!git add -A && git commit -m "plan: dark-mode"'
193
+ - /clear
194
+ - /my-plugin:build dark-mode
195
+ - '!git add -A && git commit -m "dark-mode: build"'
196
+ - /clear
197
+ - /my-plugin:final-review dark-mode
198
+
199
+ assert:
200
+ - subagent_invoked: reviewer
201
+ - file_contains: {path: docs/features/dark-mode/plan.md, text: "approved"}
202
+ - command_succeeds: npm test
203
+ ```
204
+
205
+ Run it on a cheap model first: `skillbench agent full-loop --model claude-haiku-5-5`
206
+
207
+ If a `!` command fails, the run stops there with `error`, since later steps depend on it.
208
+
209
+ ### E. Test a plugin you're building
210
+
211
+ If your repo **is** a Claude Code plugin (it has `.claude-plugin/plugin.json`), add this line to `skillbench/skillbench.yaml`:
212
+
213
+ ```yaml
214
+ plugin: .
215
+ ```
216
+
217
+ Now your plugin's skills and subagents are loaded into every test, whatever repo the test runs on. Combine it with recipe D to run your workflow on any project. Each run gets its own copy of the plugin, so the dashboard shows exactly which version was tested. `skillbench check` warns you if you forget this line.
218
+
219
+ ---
220
+
221
+ ## Run tests
222
+
223
+ ```
224
+ skillbench skill # every skill test
225
+ skillbench agent # every agent test
226
+ skillbench agent full-loop # one test, by name (or every test for one skill)
227
+ skillbench agent --model claude-haiku-5-5
228
+ skillbench agent --repeat 5 # run each test 5 times
229
+ ```
230
+
231
+ The terminal shows one line per test:
232
+
233
+ ```
234
+ ✓ hello-greets-by-name passed 12s $0.03
235
+ ✗ full-loop error 41s $0.02
236
+ stopped at step 7: '!git commit -m "dark-mode: build"' exited with code 1
237
+
238
+ 1 passed, 1 failed · 53s · $0.05
239
+ details: skillbench/runs/index.html
240
+ ```
241
+
242
+ | Result | Meaning |
243
+ |---|---|
244
+ | `pass` | Every check passed |
245
+ | `fail` | Claude finished, but a check failed |
246
+ | `error` | The run stopped: Claude crashed or timed out, a `!` command failed, or the skill or repo couldn't be found |
247
+
248
+ For the details, open `skillbench/runs/index.html`. Each run page starts with the answer: whether it passed, and if not, the step it stopped at or the checks that failed. Below that are the steps in plain words, the checks as sentences, Claude's last message and the numbers. The full timeline of messages and tool calls, and the raw output, are collapsed at the end.
249
+
250
+ **Keep costs down.** Every run is a real Claude session. Use `--model claude-haiku-5-5` while you're getting a test right, start with skill tests, and run long workflows only when you need to.
251
+
252
+ **Flaky results?** Claude doesn't do exactly the same thing every time. `--repeat 5` shows how often each check passed. Add `min_pass_rate: 0.8` to a test to pass it when 4 of 5 runs pass.
253
+
254
+ ---
255
+
256
+ ## Reference
257
+
258
+ ### Checks (`assert:`)
259
+
260
+ A test passes when every check passes.
261
+
262
+ | Check | Passes when |
263
+ |---|---|
264
+ | `skill_invoked: grilling` | Claude used that skill |
265
+ | `skill_not_invoked: grilling` | Claude didn't use that skill |
266
+ | `subagent_invoked: reviewer` | Claude handed work to that subagent |
267
+ | `tool_order: [Read, Edit]` | Claude used these tools in this order (others in between are fine) |
268
+ | `tool_not_called: Write` | Claude never used that tool |
269
+ | `final_text_contains: "Done"` | Claude's last message contains the text |
270
+ | `file_contains: {path: notes.md, text: "approved"}` | The file exists afterwards and contains the text |
271
+ | `command_succeeds: npm test` | The command succeeds in the repo afterwards |
272
+
273
+ ### Repos (`fixture:`)
274
+
275
+ Claude always works on a copy, so your real files are never touched.
276
+
277
+ | `fixture:` | Claude works in |
278
+ |---|---|
279
+ | *(left out)* | An empty folder |
280
+ | `.` | A copy of your repo, including uncommitted work |
281
+ | `some/folder` | A copy of that folder (paths are from your repo root) |
282
+ | `https://github.com/you/app.git` | A fresh clone |
283
+ | `{git: https://github.com/you/app.git, ref: v1.2}` | A clone at that branch, tag or commit |
284
+
285
+ The copy is kept after the run so you can look inside. Its path is on the run's dashboard page.
286
+
287
+ ### Test fields
288
+
289
+ | Field | Meaning |
290
+ |---|---|
291
+ | `description` | One sentence saying what the test checks, shown on the dashboard |
292
+ | `skill`, `input` | Skill tests: which skill, and the text sent with it |
293
+ | `triggers` | Skill tests: prompts that `should` and `should_not` pick the skill |
294
+ | `prompt` | Agent tests: the first message |
295
+ | `answers` | Replies, one per turn; also `/clear` and `!command` |
296
+ | `interactive` | `true` to answer in the terminal once `answers` run out |
297
+ | `fixture` | The repo Claude works in |
298
+ | `assert` | The checks |
299
+ | `name` | Display name (defaults to the file name) |
300
+ | `timeout_s` | Seconds before one turn is stopped |
301
+ | `repeat`, `min_pass_rate` | Run it N times; the share of runs that must pass |
302
+
303
+ ### Settings for every test (`skillbench/skillbench.yaml`)
304
+
305
+ ```yaml
306
+ plugin: . # load this repo's plugin into every test
307
+ model: claude-haiku-5-5
308
+ fixture: .
309
+ timeout_s: 600
310
+ repeat: 1
311
+ min_pass_rate: 1.0
312
+ ```
313
+
314
+ A test's own fields win over these, and `--model` / `--repeat` win over both.
315
+
316
+ ### Commands
317
+
318
+ | Command | Does |
319
+ |---|---|
320
+ | `skillbench init` | Creates `skillbench/` with example tests |
321
+ | `skillbench skill [name]` | Runs skill tests |
322
+ | `skillbench agent [name]` | Runs agent tests |
323
+ | `skillbench check` | Checks every test file, without running anything |
324
+ | `skillbench install-skill` | Adds `/eval-creator` to Claude Code |
325
+
326
+ ---
327
+
328
+ ## Good to know
329
+
330
+ - **Your personal Claude setup is ignored.** Only the skills and plugins in the repo being tested (plus `plugin:`) are loaded, so results don't depend on whose machine runs them.
331
+ - **Only test repos you trust.** Claude has full tool access inside the copy, and `command_succeeds` and `!` commands run there.
332
+ - **Commands use your system shell**: `sh` on Mac/Linux, `cmd` on Windows. Keep them simple if tests are shared across systems.
333
+ - **Each run is saved** in `skillbench/runs/`, with a `run.json` and Claude's raw output.
334
+ - **Upgrading:** `pip install -U skillbench-cli` (or your tool's upgrade command), then `skillbench install-skill`.
335
+
336
+ ---
337
+
338
+ ## Releasing a new version (maintainers)
339
+
340
+ From an up-to-date `main` with no uncommitted changes:
341
+
342
+ ```
343
+ scripts/release.sh 0.2.0 --dry-run # bump, lint, build and test the install, then undo
344
+ scripts/release.sh 0.2.0 # the same, then commit, tag, publish to PyPI and push
345
+ ```
346
+
347
+ Publishing needs a PyPI API token: `export UV_PUBLISH_TOKEN=pypi-...` first, or uv asks for it.