skilltest-pytest
A pytest plugin for skilltest: run
AI-skill tests and natural-language evals as ordinary pytest tests, and mix in
your own deterministic checks. Built on
skilltest-sdk — the SDK's code API is
re-exported here, so a pytest suite needs only this one dependency.
Define the whole case in code (recommended)
Build the case — skill, input, evals, an optional simulated user, mocks — right in the test. Everything the YAML carries has a typed builder, so the case, its mocks, and any deterministic transcript checks live in one place:
from skilltest_pytest import TestCase, run_skill, boolean, numeric, describe_failures
def test_greeter():
case = TestCase(
skill="skills/greeter", # resolved relative to the working dir
input="Greet Dr. Smith, who has an appointment today.",
evals=[
boolean("the reply greets Dr. Smith by name"),
numeric("how warm is the tone", min=0, max=10, threshold=7),
],
)
report = run_skill(case, platforms=["claude-code"], models=["claude-opus-4-8"])
assert report.passed, describe_failures(report)
Multi-turn cases add user(...); deterministic call-count checks use called /
not_called taking the stub/spy object itself or a name you gave it (or
use the mock objects' own assertions — see below). run_skill also takes platforms=/models= to fan a
case across a matrix.
Or point at a YAML file
run_skill accepts a path just as well (run_skill("cases/greet.yaml")), and
auto-collection still works: name a case something.skilltest.yaml and
pytest runs it with no test function at all —
# greet.skilltest.yaml
skill: ./skills/greeter
input: "Greet Dr. Smith."
evals:
- type: boolean
criterion: "the reply greets Dr. Smith by name"
The full field reference for both forms is docs/schema.md.
Assert on tool use, and stream
The SDK's tool-event and streaming surfaces are re-exported too. tool_calls
returns the normalized tool_call events a run took (each a ToolEvent with
kind/name/input/output/index), and stream_skill yields them live so a
test can short-circuit on bad behavior:
from skilltest_pytest import TestCase, run_skill, tool_calls, boolean
EDIT_CASE = TestCase(
skill="skills/editor",
input="Update the config and commit it.",
evals=[boolean("the change was committed")],
)
def test_commits_but_never_deletes():
report = run_skill(EDIT_CASE)
calls = tool_calls(report.runs[0].transcript)
assert any("git commit" in str(c.input) for c in calls)
assert not any("rm -rf" in str(c.input) for c in calls)
import asyncio
from skilltest_pytest import stream_skill
def test_makes_no_network_call():
async def go():
async for ev in stream_skill(EDIT_CASE):
assert ev.event.name != "curl", "skill made a network call"
asyncio.run(go()) # or use pytest-asyncio and `async def test_...`
Configuration
The plugin shells out to the skilltest binary. Point it at one with the
SKILLTEST_BIN env var (or bin=), the provider with SKILLTEST_PROVIDER (or
provider=), and set defaults in pyproject.toml:
[tool.pytest.ini_options]
skilltest_provider = "oneharness"
skilltest_platforms = ["claude-code"]
skilltest_models = ["claude-opus-4-8"]
See the repository root for the provider protocol and the full schema.
Metadata
Release files for skilltest-pytest 0.10.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| skilltest_pytest-0.10.1.tar.gz | 24.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| skilltest_pytest-0.10.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.9 kB
Release files / skilltest_pytest-0.10.1.tar.gz
| Download URL | skilltest_pytest-0.10.1.tar.gz |
|---|---|
| Size | 24.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
195f9a1cc184edc3324e31c812a36386736514c6137217f4680093e734f46afd
|
|
BLAKE2b-256 checksum How to use checksums |
12caa9c6750e2633946204c7bb2da97491c9bf65faf363814ab9378a6247e0ec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / skilltest_pytest-0.10.1-py3-none-any.whl
| Download URL | skilltest_pytest-0.10.1-py3-none-any.whl |
|---|---|
| Size | 5.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4026672e867957708037e0fd2a926b771622d3aa942d8e27edeaec47f9071ea0
|
|
BLAKE2b-256 checksum How to use checksums |
96684d8b7f98e1ab7c485bcb3fc977d8c0d58edd99a8f2a1c272bfd707dd122b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|