pytest-skill-engineering 0.6.22__tar.gz → 1.0.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 (86) hide show
  1. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/.gitignore +63 -65
  2. pytest_skill_engineering-1.0.0/PKG-INFO +182 -0
  3. pytest_skill_engineering-1.0.0/README.md +134 -0
  4. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/pyproject.toml +28 -35
  5. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/__init__.py +3 -37
  6. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/api.py +1 -3
  7. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/client.py +1 -1
  8. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/contracts.py +0 -8
  9. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/controls.py +83 -9
  10. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/eval.py +0 -4
  11. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/fixtures.py +3 -5
  12. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/requests.py +34 -1
  13. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/runner.py +49 -66
  14. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/__init__.py +0 -26
  15. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/evals.py +6 -6
  16. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/prompt.py +2 -2
  17. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/result.py +14 -28
  18. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/serialization.py +3 -2
  19. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/skill_evals.py +3 -12
  20. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/skill_grading.py +2 -8
  21. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/execution/servers.py +1 -1
  22. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/fixtures/__init__.py +0 -10
  23. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/fixtures/factories.py +2 -2
  24. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/onboarding.py +23 -8
  25. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/plugin.py +18 -114
  26. pytest_skill_engineering-1.0.0/src/pytest_skill_engineering/plugin_options.py +32 -0
  27. pytest_skill_engineering-1.0.0/src/pytest_skill_engineering/plugin_report.py +18 -0
  28. pytest_skill_engineering-1.0.0/src/pytest_skill_engineering/reporting/__init__.py +16 -0
  29. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/reporting/collector.py +12 -8
  30. pytest_skill_engineering-1.0.0/src/pytest_skill_engineering/reporting/generator.py +55 -0
  31. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/reporting/schema.py +1 -1
  32. pytest_skill_engineering-0.6.22/PKG-INFO +0 -211
  33. pytest_skill_engineering-0.6.22/README.md +0 -159
  34. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/cli.py +0 -401
  35. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/copilot/judge.py +0 -186
  36. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/core/scoring.py +0 -68
  37. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/core/skill_benchmark.py +0 -158
  38. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/core/skill_eval_results.py +0 -46
  39. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/core/skill_refiner.py +0 -241
  40. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/fixtures/llm_assert.py +0 -129
  41. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/fixtures/llm_score.py +0 -267
  42. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/fixtures/skill_benchmark.py +0 -204
  43. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/fixtures/skill_eval.py +0 -201
  44. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/fixtures/skill_refine.py +0 -99
  45. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/hooks.py +0 -40
  46. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/plugin_options.py +0 -115
  47. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/plugin_recording.py +0 -77
  48. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/plugin_report.py +0 -262
  49. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/prompts/__init__.py +0 -24
  50. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/prompts/ai_summary.md +0 -398
  51. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/prompts/coding_agent_analysis.md +0 -361
  52. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/__init__.py +0 -30
  53. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/__init__.py +0 -23
  54. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/agent_leaderboard.py +0 -142
  55. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/agent_selector.py +0 -58
  56. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/overlay.py +0 -39
  57. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/report.py +0 -482
  58. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/test_comparison.py +0 -384
  59. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/test_grid.py +0 -333
  60. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/components/types.py +0 -199
  61. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/generator.py +0 -680
  62. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/identity.py +0 -64
  63. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/insights.py +0 -713
  64. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/reporting/markdown.py +0 -498
  65. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/templates/partials/report.css +0 -1002
  66. pytest_skill_engineering-0.6.22/src/pytest_skill_engineering/templates/partials/scripts.js +0 -89
  67. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/LICENSE +0 -0
  68. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/__init__.py +0 -0
  69. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/config.py +0 -0
  70. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/events.py +0 -0
  71. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/personas.py +0 -0
  72. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/copilot/result.py +0 -0
  73. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/errors.py +0 -0
  74. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/plugin.py +0 -0
  75. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/core/skill.py +0 -0
  76. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/execution/__init__.py +0 -0
  77. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/execution/cost.py +0 -0
  78. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/execution/rate_limiter.py +0 -0
  79. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/execution/skill_tools.py +0 -0
  80. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/fixtures/iteration.py +0 -0
  81. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/__init__.py +0 -0
  82. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/banking.py +0 -0
  83. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/banking_mcp.py +0 -0
  84. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/todo.py +0 -0
  85. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/todo_mcp.py +0 -0
  86. {pytest_skill_engineering-0.6.22 → pytest_skill_engineering-1.0.0}/src/pytest_skill_engineering/testing/types.py +0 -0
@@ -1,67 +1,65 @@
1
- # Python
2
- __pycache__/
3
- *.py[cod]
4
- *$py.class
5
- *.so
6
- .Python
7
- build/
8
- develop-eggs/
9
- dist/
10
- downloads/
11
- eggs/
12
- .eggs/
13
- lib/
14
- lib64/
15
- parts/
16
- sdist/
17
- var/
18
- wheels/
19
- *.egg-info/
20
- .installed.cfg
21
- *.egg
22
-
23
- # Virtual environments
24
- .venv/
25
- venv/
26
- ENV/
27
- env/
28
-
29
- # IDE
30
- .idea/
31
- .vscode/
32
- *.swp
33
- *.swo
34
- *~
35
-
36
- # Testing
37
- .pytest_cache/
38
- .coverage
39
- htmlcov/
40
- .tox/
41
- .nox/
42
-
43
- # Type checking
44
- .mypy_cache/
45
-
46
- # Test outputs
47
- test_results/
48
- aitest-reports/
49
- tests/fixtures/reports/html/
50
-
51
- # Node.js (Tailwind build)
52
- node_modules/
53
- src/pytest_aitest/templates/node_modules/
54
- package-lock.json
55
-
56
- # Environment
57
- .env
58
- .env.local
59
-
60
- # OS
61
- .DS_Store
62
- Thumbs.db
63
- site/
64
- .cache/
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual environments
24
+ .venv/
25
+ venv/
26
+ ENV/
27
+ env/
28
+
29
+ # IDE
30
+ .idea/
31
+ .vscode/
32
+ *.swp
33
+ *.swo
34
+ *~
35
+
36
+ # Testing
37
+ .pytest_cache/
38
+ .coverage
39
+ htmlcov/
40
+ .tox/
41
+ .nox/
42
+
43
+ # Type checking
44
+ .mypy_cache/
45
+
46
+ # Test outputs
47
+ test_results/
48
+ aitest-reports/
49
+
50
+ # Node.js
51
+ node_modules/
52
+ package-lock.json
53
+
54
+ # Environment
55
+ .env
56
+ .env.local
57
+
58
+ # OS
59
+ .DS_Store
60
+ Thumbs.db
61
+ site/
62
+ .cache/
65
63
  # Squad: ignore runtime state (logs, inbox, sessions)
66
64
  .squad/orchestration-log/
67
65
  .squad/log/
@@ -71,4 +69,4 @@ site/
71
69
  .squad-workstream
72
70
 
73
71
  # pytest-skill-engineering test scratch (some server tests create a cwd dir)
74
- .pytest-execution-servers/
72
+ .pytest-execution-servers/
@@ -0,0 +1,182 @@
1
+ Metadata-Version: 2.5
2
+ Name: pytest-skill-engineering
3
+ Version: 1.0.0
4
+ Summary: Reliable Copilot execution and evidence for coding-agent-led testing of MCP servers, CLI tools, skills, and custom agents.
5
+ Project-URL: Homepage, https://github.com/sbroenne/pytest-skill-engineering
6
+ Project-URL: Repository, https://github.com/sbroenne/pytest-skill-engineering
7
+ Author: Stefan Brunner
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: agents,ai,custom-agents,llm,mcp,pytest,skill-engineering,skills,testing
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Framework :: Pytest
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Testing
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: github-copilot-sdk>=1.0.16
23
+ Requires-Dist: httpx>=0.28.1
24
+ Requires-Dist: mcp>=2.2.0
25
+ Requires-Dist: pydantic>=2.13.5
26
+ Requires-Dist: pytest-asyncio>=1.4.0
27
+ Requires-Dist: pytest>=9.1.1
28
+ Requires-Dist: python-frontmatter>=1.3.0
29
+ Requires-Dist: tomlkit>=0.15.1
30
+ Requires-Dist: trio>=0.34.0
31
+ Requires-Dist: websockets>=17.1
32
+ Provides-Extra: dev
33
+ Requires-Dist: pre-commit>=4.6.2; extra == 'dev'
34
+ Requires-Dist: pyright>=1.1.414; extra == 'dev'
35
+ Requires-Dist: pytest-cov>=7.1.0; extra == 'dev'
36
+ Requires-Dist: python-dotenv>=1.2.3; extra == 'dev'
37
+ Requires-Dist: ruff>=0.16.9; extra == 'dev'
38
+ Requires-Dist: typeguard>=4.6.0; extra == 'dev'
39
+ Provides-Extra: docs
40
+ Requires-Dist: cairosvg>=2.9.1; extra == 'docs'
41
+ Requires-Dist: mkdocs-material<9.8,>=9.7.7; extra == 'docs'
42
+ Requires-Dist: mkdocs>=1.6.1; extra == 'docs'
43
+ Requires-Dist: mkdocstrings[python]>=1.0.6; extra == 'docs'
44
+ Requires-Dist: pillow>=12.3.0; extra == 'docs'
45
+ Provides-Extra: test
46
+ Requires-Dist: syrupy<7,>=6.1.1; extra == 'test'
47
+ Description-Content-Type: text/markdown
48
+
49
+ # pytest-skill-engineering
50
+
51
+ [![PyPI version](https://img.shields.io/pypi/v/pytest-skill-engineering)](https://pypi.org/project/pytest-skill-engineering/)
52
+ [![CI](https://github.com/sbroenne/pytest-skill-engineering/actions/workflows/ci.yml/badge.svg)](https://github.com/sbroenne/pytest-skill-engineering/actions/workflows/ci.yml)
53
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
54
+
55
+ **A test runner for people working with coding agents.**
56
+
57
+ Test whether real GitHub Copilot sessions can use your MCP servers, CLI tools,
58
+ skills, system prompts, and custom agents. Write a user task, execute it through
59
+ pytest, and verify the actual output with ordinary assertions.
60
+
61
+ The framework runs the task and records what happened. Your existing coding agent
62
+ investigates the evidence, reads the source, and helps you improve the interface.
63
+ **Version 1.0 removes AI judging, report dashboards, rankings, and skill refinement.**
64
+ See the [migration guide](docs/migration.md) for this breaking change.
65
+
66
+ ## Why this exists
67
+
68
+ Your tool can pass its own tests while Copilot chooses the wrong operation,
69
+ supplies the wrong arguments, or misunderstands its descriptions. That is a
70
+ different question from whether the tool implementation works.
71
+
72
+ Use real task execution to test the AI-facing interface, and independent output
73
+ checks to establish correctness. A completed session or a tool call by itself
74
+ does not prove that the requested task succeeded.
75
+
76
+ ## Quick start
77
+
78
+ You need Python 3.11+, [uv](https://docs.astral.sh/uv/), and a GitHub account with
79
+ Copilot access.
80
+
81
+ ```powershell
82
+ uv add pytest-skill-engineering
83
+ gh auth login --hostname github.com
84
+ uv run pytest-skill-engineering init
85
+ uv run pytest-skill-engineering doctor
86
+ uv run python -m pytest "tests\test_copilot_eval.py" -v
87
+ ```
88
+
89
+ `init` creates a Todo MCP starter test, explicit JSON evidence settings, and
90
+ explicit starter-model rates in `pricing.toml`. It refuses conflicting settings
91
+ or an existing starter. Live execution can consume Copilot premium requests.
92
+
93
+ pytest shows ordinary test results and assertion failures. Give your coding
94
+ agent `aitest-reports\results.json` and the relevant source to investigate what
95
+ happened. No dashboard or second AI judgment is generated.
96
+
97
+ ## What we learned by testing our own idea
98
+
99
+ We evaluated a companion skill for coding agents using this framework and chose
100
+ not to ship it. The comparison did not demonstrate a benefit; adding general
101
+ test-writing advice was not evidence that users needed another product layer.
102
+ Use the documentation, examples, and native evidence directly.
103
+
104
+ The [case study](docs/use-cases/companion-skill.md) records the actual results,
105
+ failures, limitations, and removal decision. Its
106
+ [historical experiment](examples/skill-dogfood/) remains reproducible with a
107
+ frozen test fixture, not an installable companion skill. Default sample checks
108
+ are offline; live execution is explicit. The [quickstart](examples/quickstart/)
109
+ is the smaller first example.
110
+
111
+ Testing your own domain skills remains a supported framework capability.
112
+
113
+ ## A test that checks the result
114
+
115
+ ```python
116
+ from __future__ import annotations
117
+
118
+ import subprocess
119
+ import sys
120
+
121
+ from pytest_skill_engineering.copilot import CopilotEval
122
+
123
+
124
+ async def test_addition(copilot_eval, tmp_path):
125
+ agent = CopilotEval(
126
+ name="addition",
127
+ model="gpt-5.6-luna",
128
+ instructions="Write Python code and save the requested file.",
129
+ working_directory=str(tmp_path),
130
+ )
131
+ result = await copilot_eval(agent, "Create calc.py with add(a, b) returning a + b.")
132
+ assert result.success, result.error
133
+ assert (tmp_path / "calc.py").is_file()
134
+ checked = subprocess.run(
135
+ [
136
+ sys.executable,
137
+ "-c",
138
+ "from calc import add; assert add(2, 3) == 5; assert add(-2, 2) == 0",
139
+ ],
140
+ cwd=tmp_path,
141
+ capture_output=True,
142
+ text=True,
143
+ timeout=10,
144
+ )
145
+ assert checked.returncode == 0, checked.stderr
146
+ ```
147
+
148
+ Use your approved isolation when executing generated code. A temporary directory
149
+ is not a security sandbox.
150
+
151
+ ## What stays in the framework
152
+
153
+ | Capability | What it provides |
154
+ | --- | --- |
155
+ | `CopilotEval` and `copilot_eval` | Real SDK sessions with explicit configuration |
156
+ | MCP, CLI, skills, plugins, custom agents | The interfaces and definitions under test |
157
+ | Execution controls | Time, usage, request, tool, and permission controls; one attempt per execution |
158
+ | Captured evidence | Configuration, calls, arguments, outputs, completion flags, errors, and usage |
159
+ | Ordinary pytest checks | Consumer-owned verification and recorded properties |
160
+ | `ab_run` and repetitions | Isolated working directories and repeated observations |
161
+ | Structured JSON | Captured execution and ordinary pytest outcomes, without rankings or advice |
162
+ | Pricing | Explicit USD estimates and recorded Copilot premium requests |
163
+
164
+ A/B entries share one pytest outcome. Record side-specific checks; do not read
165
+ that shared outcome as independent per-side success or causal improvement.
166
+ Missing prices and incomplete evidence are recorded explicitly.
167
+
168
+ ## Let your coding agent investigate
169
+
170
+ Ask your existing coding agent to inspect a failed test, its saved JSON evidence,
171
+ and the source. It can explain the supported cause and help fix it, without
172
+ changing the test's success criteria after seeing the failure.
173
+
174
+ Reading current schema-4.0 evidence needs no authentication or paid call.
175
+ The framework records results; the coding agent interprets them. Subjective
176
+ review is advice, not an automatic pytest verdict.
177
+
178
+ Read the [full documentation](https://sbroenne.github.io/pytest-skill-engineering/).
179
+
180
+ ## License
181
+
182
+ MIT. Inspired by [agent-benchmark](https://github.com/mykhaliev/agent-benchmark).
@@ -0,0 +1,134 @@
1
+ # pytest-skill-engineering
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/pytest-skill-engineering)](https://pypi.org/project/pytest-skill-engineering/)
4
+ [![CI](https://github.com/sbroenne/pytest-skill-engineering/actions/workflows/ci.yml/badge.svg)](https://github.com/sbroenne/pytest-skill-engineering/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+
7
+ **A test runner for people working with coding agents.**
8
+
9
+ Test whether real GitHub Copilot sessions can use your MCP servers, CLI tools,
10
+ skills, system prompts, and custom agents. Write a user task, execute it through
11
+ pytest, and verify the actual output with ordinary assertions.
12
+
13
+ The framework runs the task and records what happened. Your existing coding agent
14
+ investigates the evidence, reads the source, and helps you improve the interface.
15
+ **Version 1.0 removes AI judging, report dashboards, rankings, and skill refinement.**
16
+ See the [migration guide](docs/migration.md) for this breaking change.
17
+
18
+ ## Why this exists
19
+
20
+ Your tool can pass its own tests while Copilot chooses the wrong operation,
21
+ supplies the wrong arguments, or misunderstands its descriptions. That is a
22
+ different question from whether the tool implementation works.
23
+
24
+ Use real task execution to test the AI-facing interface, and independent output
25
+ checks to establish correctness. A completed session or a tool call by itself
26
+ does not prove that the requested task succeeded.
27
+
28
+ ## Quick start
29
+
30
+ You need Python 3.11+, [uv](https://docs.astral.sh/uv/), and a GitHub account with
31
+ Copilot access.
32
+
33
+ ```powershell
34
+ uv add pytest-skill-engineering
35
+ gh auth login --hostname github.com
36
+ uv run pytest-skill-engineering init
37
+ uv run pytest-skill-engineering doctor
38
+ uv run python -m pytest "tests\test_copilot_eval.py" -v
39
+ ```
40
+
41
+ `init` creates a Todo MCP starter test, explicit JSON evidence settings, and
42
+ explicit starter-model rates in `pricing.toml`. It refuses conflicting settings
43
+ or an existing starter. Live execution can consume Copilot premium requests.
44
+
45
+ pytest shows ordinary test results and assertion failures. Give your coding
46
+ agent `aitest-reports\results.json` and the relevant source to investigate what
47
+ happened. No dashboard or second AI judgment is generated.
48
+
49
+ ## What we learned by testing our own idea
50
+
51
+ We evaluated a companion skill for coding agents using this framework and chose
52
+ not to ship it. The comparison did not demonstrate a benefit; adding general
53
+ test-writing advice was not evidence that users needed another product layer.
54
+ Use the documentation, examples, and native evidence directly.
55
+
56
+ The [case study](docs/use-cases/companion-skill.md) records the actual results,
57
+ failures, limitations, and removal decision. Its
58
+ [historical experiment](examples/skill-dogfood/) remains reproducible with a
59
+ frozen test fixture, not an installable companion skill. Default sample checks
60
+ are offline; live execution is explicit. The [quickstart](examples/quickstart/)
61
+ is the smaller first example.
62
+
63
+ Testing your own domain skills remains a supported framework capability.
64
+
65
+ ## A test that checks the result
66
+
67
+ ```python
68
+ from __future__ import annotations
69
+
70
+ import subprocess
71
+ import sys
72
+
73
+ from pytest_skill_engineering.copilot import CopilotEval
74
+
75
+
76
+ async def test_addition(copilot_eval, tmp_path):
77
+ agent = CopilotEval(
78
+ name="addition",
79
+ model="gpt-5.6-luna",
80
+ instructions="Write Python code and save the requested file.",
81
+ working_directory=str(tmp_path),
82
+ )
83
+ result = await copilot_eval(agent, "Create calc.py with add(a, b) returning a + b.")
84
+ assert result.success, result.error
85
+ assert (tmp_path / "calc.py").is_file()
86
+ checked = subprocess.run(
87
+ [
88
+ sys.executable,
89
+ "-c",
90
+ "from calc import add; assert add(2, 3) == 5; assert add(-2, 2) == 0",
91
+ ],
92
+ cwd=tmp_path,
93
+ capture_output=True,
94
+ text=True,
95
+ timeout=10,
96
+ )
97
+ assert checked.returncode == 0, checked.stderr
98
+ ```
99
+
100
+ Use your approved isolation when executing generated code. A temporary directory
101
+ is not a security sandbox.
102
+
103
+ ## What stays in the framework
104
+
105
+ | Capability | What it provides |
106
+ | --- | --- |
107
+ | `CopilotEval` and `copilot_eval` | Real SDK sessions with explicit configuration |
108
+ | MCP, CLI, skills, plugins, custom agents | The interfaces and definitions under test |
109
+ | Execution controls | Time, usage, request, tool, and permission controls; one attempt per execution |
110
+ | Captured evidence | Configuration, calls, arguments, outputs, completion flags, errors, and usage |
111
+ | Ordinary pytest checks | Consumer-owned verification and recorded properties |
112
+ | `ab_run` and repetitions | Isolated working directories and repeated observations |
113
+ | Structured JSON | Captured execution and ordinary pytest outcomes, without rankings or advice |
114
+ | Pricing | Explicit USD estimates and recorded Copilot premium requests |
115
+
116
+ A/B entries share one pytest outcome. Record side-specific checks; do not read
117
+ that shared outcome as independent per-side success or causal improvement.
118
+ Missing prices and incomplete evidence are recorded explicitly.
119
+
120
+ ## Let your coding agent investigate
121
+
122
+ Ask your existing coding agent to inspect a failed test, its saved JSON evidence,
123
+ and the source. It can explain the supported cause and help fix it, without
124
+ changing the test's success criteria after seeing the failure.
125
+
126
+ Reading current schema-4.0 evidence needs no authentication or paid call.
127
+ The framework records results; the coding agent interprets them. Subjective
128
+ review is advice, not an automatic pytest verdict.
129
+
130
+ Read the [full documentation](https://sbroenne.github.io/pytest-skill-engineering/).
131
+
132
+ ## License
133
+
134
+ MIT. Inspired by [agent-benchmark](https://github.com/mykhaliev/agent-benchmark).
@@ -1,11 +1,11 @@
1
1
  [build-system]
2
- requires = ["hatchling"]
2
+ requires = ["hatchling>=1.32.4"]
3
3
  build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pytest-skill-engineering"
7
- version = "0.6.22"
8
- description = "The testing framework for skill engineering. Test tool descriptions, prompt templates, agent skills, and custom agents with real LLMs. AI analyzes results and tells you what to fix."
7
+ version = "1.0.0"
8
+ description = "Reliable Copilot execution and evidence for coding-agent-led testing of MCP servers, CLI tools, skills, and custom agents."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
11
11
  requires-python = ">=3.11"
@@ -26,45 +26,40 @@ classifiers = [
26
26
  "Topic :: Software Development :: Testing",
27
27
  ]
28
28
  dependencies = [
29
- "pytest>=9.0",
30
- "mcp>=2.1.1",
31
- "pydantic>=2.0",
32
- "markdown>=3.10.2",
33
- "htpy>=25.12.0",
34
- "mdutils>=1.8.1",
35
- "python-frontmatter>=1.1.0",
36
- "nh3>=0.3.3",
37
- "github-copilot-sdk>=1.0.13",
29
+ "pytest>=9.1.1",
30
+ "mcp>=2.2.0",
31
+ "pydantic>=2.13.5",
32
+ "python-frontmatter>=1.3.0",
33
+ "github-copilot-sdk>=1.0.16",
38
34
  "httpx>=0.28.1",
39
- "trio>=0.33.0",
35
+ "trio>=0.34.0",
40
36
  "tomlkit>=0.15.1",
41
- "pytest-asyncio>=1.3",
42
- "websockets>=15.0.1",
37
+ "pytest-asyncio>=1.4.0",
38
+ "websockets>=17.1",
43
39
  ]
44
40
 
45
41
  [project.optional-dependencies]
46
42
  dev = [
47
- "pytest-cov>=7.0",
48
- "python-dotenv>=1.2",
49
- "ruff>=0.16.6",
50
- "pyright>=1.1.408",
51
- "pre-commit>=4.5",
52
- "typeguard>=4.5",
43
+ "pytest-cov>=7.1.0",
44
+ "python-dotenv>=1.2.3",
45
+ "ruff>=0.16.9",
46
+ "pyright>=1.1.414",
47
+ "pre-commit>=4.6.2",
48
+ "typeguard>=4.6.0",
53
49
  ]
54
50
  test = [
55
- "syrupy>=6.0.0,<7",
51
+ "syrupy>=6.1.1,<7",
56
52
  ]
57
53
  docs = [
58
- "mkdocs>=1.6",
59
- "mkdocs-material>=9.6,<9.8",
60
- "mkdocstrings[python]>=0.24",
61
- "pillow>=11.0",
62
- "cairosvg>=2.7",
54
+ "mkdocs>=1.6.1",
55
+ "mkdocs-material>=9.7.7,<9.8",
56
+ "mkdocstrings[python]>=1.0.6",
57
+ "pillow>=12.3.0",
58
+ "cairosvg>=2.9.1",
63
59
  ]
64
60
 
65
61
  [project.scripts]
66
62
  pytest-skill-engineering = "pytest_skill_engineering.onboarding:main"
67
- pytest-skill-engineering-report = "pytest_skill_engineering.cli:main"
68
63
 
69
64
  [project.entry-points.pytest11]
70
65
  aitest = "pytest_skill_engineering.plugin"
@@ -83,9 +78,6 @@ packages = ["src/pytest_skill_engineering"]
83
78
  include = [
84
79
  "src/pytest_skill_engineering/**/*.py",
85
80
  "src/pytest_skill_engineering/**/*.md",
86
- "src/pytest_skill_engineering/**/*.html",
87
- "src/pytest_skill_engineering/**/*.css",
88
- "src/pytest_skill_engineering/**/*.js",
89
81
  ]
90
82
 
91
83
  [tool.ruff]
@@ -106,7 +98,7 @@ quote-style = "double"
106
98
  indent-style = "space"
107
99
 
108
100
  [tool.pyright]
109
- include = ["src", "tests"]
101
+ include = ["src", "tests", "examples/skill-dogfood"]
110
102
  pythonVersion = "3.11"
111
103
  typeCheckingMode = "basic"
112
104
 
@@ -125,8 +117,6 @@ filterwarnings = [
125
117
  # LLM auth is handled by the GitHub Copilot SDK (gh auth login or GITHUB_TOKEN)
126
118
  addopts = """
127
119
  --strict-markers
128
- --aitest-summary-model=copilot/gpt-5.6-sol
129
- --aitest-html=aitest-reports/report.html
130
120
  """
131
121
  markers = [
132
122
  "integration: marks tests as integration tests (require LLM credentials)",
@@ -138,7 +128,6 @@ markers = [
138
128
  "skill: tests with skills",
139
129
  "session_test: multi-turn session tests",
140
130
  "clarification: clarification detection tests",
141
- "scoring: LLM scoring / rubric tests",
142
131
  "iterations: iteration reliability tests",
143
132
  "abtest: A/B server comparison tests",
144
133
  "cli: CLI server tests",
@@ -150,4 +139,8 @@ markers = [
150
139
  [dependency-groups]
151
140
  dev = [
152
141
  "pytest-skill-engineering[dev,test,docs]",
142
+ "pytest-skill-engineering-dogfood",
153
143
  ]
144
+
145
+ [tool.uv.sources]
146
+ pytest-skill-engineering-dogfood = { path = "examples/skill-dogfood", editable = true }
@@ -1,4 +1,4 @@
1
- """pytest-skill-engineering: Pytest plugin for testing AI agents with MCP and CLI servers."""
1
+ """Copilot task execution and evidence for testing AI-facing tools and skills."""
2
2
 
3
3
  import logging
4
4
 
@@ -22,8 +22,6 @@ from pytest_skill_engineering.copilot import ( # noqa: E402
22
22
  )
23
23
  from pytest_skill_engineering.core import ( # noqa: E402
24
24
  AITestError,
25
- BenchmarkComparison,
26
- CaseBenchmark,
27
25
  EngineTimeoutError,
28
26
  EvalResult,
29
27
  HookDefinition,
@@ -33,25 +31,16 @@ from pytest_skill_engineering.core import ( # noqa: E402
33
31
  Plugin,
34
32
  PluginMetadata,
35
33
  Prompt,
36
- RefinementResult,
37
- RefinementSuggestion,
38
- ScoreResult,
39
- ScoringDimension,
40
34
  ServerStartError,
41
35
  Skill,
42
- SkillBenchmarkResult,
43
- SkillCaseResult,
44
36
  SkillError,
45
37
  SkillEvalCase,
46
- SkillGradingResult,
47
38
  SkillInfo,
48
39
  SkillMetadata,
49
40
  SubagentInvocation,
50
41
  ToolCall,
51
42
  ToolInfo,
52
43
  Turn,
53
- analyze_skill_failures,
54
- assert_score,
55
44
  export_grading,
56
45
  has_skill_evals,
57
46
  load_custom_agent,
@@ -74,27 +63,18 @@ from pytest_skill_engineering.execution import ( # noqa: E402
74
63
  WaitStrategy,
75
64
  )
76
65
 
77
- # Hooks (for plugin extensibility)
78
- from pytest_skill_engineering.hooks import AitestHookSpec # noqa: E402
79
- from pytest_skill_engineering.plugin import ( # noqa: E402
80
- get_analysis_prompt,
81
- get_analysis_prompt_details,
82
- )
83
-
84
66
  # Reporting
85
67
  from pytest_skill_engineering.reporting import ( # noqa: E402
86
68
  SuiteReport,
87
69
  TestReport,
88
70
  build_suite_report,
89
- generate_html,
90
71
  generate_json,
72
+ load_suite_report,
91
73
  )
92
74
 
93
75
  __all__ = [ # noqa: RUF022
94
76
  # Core
95
77
  "AITestError",
96
- "BenchmarkComparison",
97
- "CaseBenchmark",
98
78
  "EngineTimeoutError",
99
79
  "EvalResult",
100
80
  "HookDefinition",
@@ -104,22 +84,16 @@ __all__ = [ # noqa: RUF022
104
84
  "Plugin",
105
85
  "PluginMetadata",
106
86
  "Prompt",
107
- "RefinementResult",
108
- "RefinementSuggestion",
109
87
  "ServerStartError",
110
88
  "Skill",
111
- "SkillBenchmarkResult",
112
- "SkillCaseResult",
113
89
  "SkillError",
114
90
  "SkillEvalCase",
115
- "SkillGradingResult",
116
91
  "SkillInfo",
117
92
  "SkillMetadata",
118
93
  "SubagentInvocation",
119
94
  "ToolCall",
120
95
  "ToolInfo",
121
96
  "Turn",
122
- "analyze_skill_failures",
123
97
  "export_grading",
124
98
  "has_skill_evals",
125
99
  "load_custom_agent",
@@ -152,16 +126,8 @@ __all__ = [ # noqa: RUF022
152
126
  "SuiteReport",
153
127
  "TestReport",
154
128
  "build_suite_report",
155
- "generate_html",
156
129
  "generate_json",
157
- # Hooks
158
- "AitestHookSpec",
159
- "get_analysis_prompt",
160
- "get_analysis_prompt_details",
161
- # Scoring
162
- "ScoreResult",
163
- "ScoringDimension",
164
- "assert_score",
130
+ "load_suite_report",
165
131
  ]
166
132
 
167
133
  from importlib.metadata import version as _get_version # noqa: E402