skillroll 0.1.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 (63) hide show
  1. skillroll-0.1.0/.gitignore +16 -0
  2. skillroll-0.1.0/LICENSE +21 -0
  3. skillroll-0.1.0/PKG-INFO +129 -0
  4. skillroll-0.1.0/README.md +113 -0
  5. skillroll-0.1.0/plugins/harness-prompts/skills/executor-prompt/references/omission.md +1 -0
  6. skillroll-0.1.0/plugins/harness-prompts/skills/executor-prompt/references/system.md +3 -0
  7. skillroll-0.1.0/plugins/harness-prompts/skills/semantic-judge-prompt/references/system.md +1 -0
  8. skillroll-0.1.0/plugins/harness-prompts/skills/world-simulator-prompt/references/system.md +6 -0
  9. skillroll-0.1.0/pyproject.toml +80 -0
  10. skillroll-0.1.0/src/skillroll/__init__.py +5 -0
  11. skillroll-0.1.0/src/skillroll/__main__.py +5 -0
  12. skillroll-0.1.0/src/skillroll/_version.py +3 -0
  13. skillroll-0.1.0/src/skillroll/artifacts/__init__.py +1 -0
  14. skillroll-0.1.0/src/skillroll/artifacts/hashes.py +45 -0
  15. skillroll-0.1.0/src/skillroll/artifacts/records.py +493 -0
  16. skillroll-0.1.0/src/skillroll/artifacts/store.py +485 -0
  17. skillroll-0.1.0/src/skillroll/assertions.py +58 -0
  18. skillroll-0.1.0/src/skillroll/checks.py +267 -0
  19. skillroll-0.1.0/src/skillroll/cli.py +322 -0
  20. skillroll-0.1.0/src/skillroll/commands/__init__.py +1 -0
  21. skillroll-0.1.0/src/skillroll/commands/doctor.py +159 -0
  22. skillroll-0.1.0/src/skillroll/commands/evaluate.py +1384 -0
  23. skillroll-0.1.0/src/skillroll/commands/initialize.py +508 -0
  24. skillroll-0.1.0/src/skillroll/commands/validate.py +152 -0
  25. skillroll-0.1.0/src/skillroll/config.py +360 -0
  26. skillroll-0.1.0/src/skillroll/diagnostics.py +128 -0
  27. skillroll-0.1.0/src/skillroll/discovery.py +106 -0
  28. skillroll-0.1.0/src/skillroll/evals.py +477 -0
  29. skillroll-0.1.0/src/skillroll/github.py +418 -0
  30. skillroll-0.1.0/src/skillroll/github_action.py +178 -0
  31. skillroll-0.1.0/src/skillroll/github_workflow.py +203 -0
  32. skillroll-0.1.0/src/skillroll/guards.py +52 -0
  33. skillroll-0.1.0/src/skillroll/inference/__init__.py +15 -0
  34. skillroll-0.1.0/src/skillroll/inference/openrouter.py +218 -0
  35. skillroll-0.1.0/src/skillroll/inference/preflight.py +162 -0
  36. skillroll-0.1.0/src/skillroll/inference/profile.py +232 -0
  37. skillroll-0.1.0/src/skillroll/inference/transport.py +302 -0
  38. skillroll-0.1.0/src/skillroll/initialization/__init__.py +1 -0
  39. skillroll-0.1.0/src/skillroll/initialization/discovery.py +95 -0
  40. skillroll-0.1.0/src/skillroll/initialization/templates.py +87 -0
  41. skillroll-0.1.0/src/skillroll/initialization/transaction.py +140 -0
  42. skillroll-0.1.0/src/skillroll/judge.py +414 -0
  43. skillroll-0.1.0/src/skillroll/markdown.py +118 -0
  44. skillroll-0.1.0/src/skillroll/marketplace.py +287 -0
  45. skillroll-0.1.0/src/skillroll/models.py +210 -0
  46. skillroll-0.1.0/src/skillroll/outcomes.py +17 -0
  47. skillroll-0.1.0/src/skillroll/paths.py +38 -0
  48. skillroll-0.1.0/src/skillroll/prompt_resources.py +64 -0
  49. skillroll-0.1.0/src/skillroll/py.typed +1 -0
  50. skillroll-0.1.0/src/skillroll/release.py +390 -0
  51. skillroll-0.1.0/src/skillroll/repository_io.py +80 -0
  52. skillroll-0.1.0/src/skillroll/runtime/__init__.py +1 -0
  53. skillroll-0.1.0/src/skillroll/runtime/agents_sdk.py +137 -0
  54. skillroll-0.1.0/src/skillroll/runtime/attempt.py +175 -0
  55. skillroll-0.1.0/src/skillroll/runtime/execution.py +195 -0
  56. skillroll-0.1.0/src/skillroll/safe_yaml.py +72 -0
  57. skillroll-0.1.0/src/skillroll/validation.py +238 -0
  58. skillroll-0.1.0/src/skillroll/verdicts.py +67 -0
  59. skillroll-0.1.0/src/skillroll/world/__init__.py +1 -0
  60. skillroll-0.1.0/src/skillroll/world/bundle.py +195 -0
  61. skillroll-0.1.0/src/skillroll/world/model.py +175 -0
  62. skillroll-0.1.0/src/skillroll/world/rules.py +27 -0
  63. skillroll-0.1.0/src/skillroll/world/session.py +176 -0
@@ -0,0 +1,16 @@
1
+ .venv/
2
+ .env
3
+ dist/
4
+ build/
5
+ .coverage
6
+ coverage.json
7
+ htmlcov/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ .pytest_cache/
11
+ __pycache__/
12
+ *.py[cod]
13
+ *.egg-info/
14
+ .skillroll/runs/
15
+ *.DS_Store
16
+ /internal/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hagai Weinfeld
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,129 @@
1
+ Metadata-Version: 2.5
2
+ Name: skillroll
3
+ Version: 0.1.0
4
+ Summary: Readable, execution-based evaluations for agent skills
5
+ Author: SkillRoll contributors
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Classifier: Typing :: Typed
11
+ Requires-Python: >=3.12
12
+ Requires-Dist: markdown-it-py>=4.0
13
+ Requires-Dist: openai-agents<1,>=0.21
14
+ Requires-Dist: pyyaml>=6.0.3
15
+ Description-Content-Type: text/markdown
16
+
17
+ # SkillRoll
18
+
19
+ SkillRoll is a small behavioral eval framework for
20
+ [Agent Skills](https://agentskills.io/). Write a Markdown case beside a skill,
21
+ run it in a controlled simulated world, and review the verdict and evidence.
22
+
23
+ Use it to turn an important prompt behavior into a readable regression case
24
+ before changing the prompt.
25
+
26
+ > If you can explain what a skill should do, you can eval it.
27
+
28
+ ## Status
29
+
30
+ SkillRoll is an early project. Local evaluation and advisory GitHub checks work
31
+ today; expect the interface to evolve between minor releases.
32
+
33
+ A passing run means one observed attempt met one case. It is useful evidence,
34
+ not proof that a skill is correct or ready for blocking CI.
35
+
36
+ ## Quickstart
37
+
38
+ SkillRoll requires Python 3.12 or later and
39
+ [`uv`](https://docs.astral.sh/uv/).
40
+
41
+ ```shell
42
+ uv tool install skillroll
43
+ ```
44
+
45
+ Initialize a repository that already contains `SKILL.md` files:
46
+
47
+ ```shell
48
+ skillroll init \
49
+ --repo /path/to/my-skills \
50
+ --skills-path skills \
51
+ --starter-evals my-skill \
52
+ --yes
53
+
54
+ skillroll validate --repo /path/to/my-skills --all
55
+ ```
56
+
57
+ `skills_path` is relative to the target repository. `--starter-evals` and
58
+ `--case` are relative to `skills_path`. Validation is offline: it does not need
59
+ an API key or call a model.
60
+
61
+ Open the generated case under `my-skill/evals/`, replace the placeholders, and
62
+ delete any starter case you do not need. A case has three parts:
63
+
64
+ - `Input`: the realistic request and context given to the skill;
65
+ - `World`: simulated external state and action results; and
66
+ - `Success criteria`: observable outcomes that allow equivalent good answers.
67
+
68
+ Configure an OpenAI-compatible Chat Completions endpoint in
69
+ `skillroll.toml`:
70
+
71
+ ```toml
72
+ schema_version = 1
73
+ skills_path = "skills"
74
+
75
+ [inference]
76
+ base_url = "https://provider.example/v1"
77
+ model = "provider/model-name"
78
+ api_key_env = "SKILLROLL_API_KEY"
79
+ ```
80
+
81
+ The endpoint must support tool calling and strict JSON Schema structured
82
+ outputs. Export the configured key, check compatibility, and run a case:
83
+
84
+ ```shell
85
+ export SKILLROLL_API_KEY="your-key"
86
+ skillroll doctor --repo /path/to/my-skills
87
+ skillroll eval \
88
+ --repo /path/to/my-skills \
89
+ --case my-skill/evals/first-use.eval.md
90
+ ```
91
+
92
+ `doctor` checks the endpoint. `eval` spends inference and writes a private run
93
+ under `.skillroll/runs/`. Start with `report.md`; use `result.json` for
94
+ automation and `transcript.jsonl` to inspect the skill's actions.
95
+
96
+ | Outcome | Meaning |
97
+ | --- | --- |
98
+ | `PASS` | The observed evidence met the case. |
99
+ | `FAIL` | One or more expectations were not met. |
100
+ | `INCOMPLETE` | A required repository check was not run. |
101
+ | `ERROR` | The run could not produce a trustworthy verdict. |
102
+
103
+ ## Know the boundaries
104
+
105
+ - Simulated World actions cannot access your real filesystem, shell, network,
106
+ services, or other skills.
107
+ - Optional repository checks are ordinary host commands, not a sandbox. They
108
+ run only after explicit opt-in.
109
+ - Evidence can contain case text, simulated state, action results, and model
110
+ output. Review it before sharing.
111
+ - Free or changing model routes are useful for setup checks, not comparable
112
+ skill-quality evidence. Pin a named model when results need to be compared.
113
+ - Start behavioral cases as manual or advisory checks. Promote them only after
114
+ their failures are stable, specific, and useful.
115
+
116
+ ## Learn more
117
+
118
+ - [Write an eval](docs/writing-evals.md)
119
+ - [Configure models and cost](docs/configuration.md)
120
+ - [Understand results and fix problems](docs/results.md)
121
+ - [Add advisory GitHub checks](docs/github-actions.md)
122
+ - [Review the security model](docs/security.md)
123
+
124
+ The [documentation index](docs/index.md) lists the same guides by task.
125
+
126
+ See [PHILOSOPHY.md](PHILOSOPHY.md) for the project principles and
127
+ [CONTRIBUTING.md](CONTRIBUTING.md) to work on SkillRoll. Project support,
128
+ security reporting, and governance are in [SUPPORT.md](SUPPORT.md),
129
+ [SECURITY.md](SECURITY.md), and [GOVERNANCE.md](GOVERNANCE.md).
@@ -0,0 +1,113 @@
1
+ # SkillRoll
2
+
3
+ SkillRoll is a small behavioral eval framework for
4
+ [Agent Skills](https://agentskills.io/). Write a Markdown case beside a skill,
5
+ run it in a controlled simulated world, and review the verdict and evidence.
6
+
7
+ Use it to turn an important prompt behavior into a readable regression case
8
+ before changing the prompt.
9
+
10
+ > If you can explain what a skill should do, you can eval it.
11
+
12
+ ## Status
13
+
14
+ SkillRoll is an early project. Local evaluation and advisory GitHub checks work
15
+ today; expect the interface to evolve between minor releases.
16
+
17
+ A passing run means one observed attempt met one case. It is useful evidence,
18
+ not proof that a skill is correct or ready for blocking CI.
19
+
20
+ ## Quickstart
21
+
22
+ SkillRoll requires Python 3.12 or later and
23
+ [`uv`](https://docs.astral.sh/uv/).
24
+
25
+ ```shell
26
+ uv tool install skillroll
27
+ ```
28
+
29
+ Initialize a repository that already contains `SKILL.md` files:
30
+
31
+ ```shell
32
+ skillroll init \
33
+ --repo /path/to/my-skills \
34
+ --skills-path skills \
35
+ --starter-evals my-skill \
36
+ --yes
37
+
38
+ skillroll validate --repo /path/to/my-skills --all
39
+ ```
40
+
41
+ `skills_path` is relative to the target repository. `--starter-evals` and
42
+ `--case` are relative to `skills_path`. Validation is offline: it does not need
43
+ an API key or call a model.
44
+
45
+ Open the generated case under `my-skill/evals/`, replace the placeholders, and
46
+ delete any starter case you do not need. A case has three parts:
47
+
48
+ - `Input`: the realistic request and context given to the skill;
49
+ - `World`: simulated external state and action results; and
50
+ - `Success criteria`: observable outcomes that allow equivalent good answers.
51
+
52
+ Configure an OpenAI-compatible Chat Completions endpoint in
53
+ `skillroll.toml`:
54
+
55
+ ```toml
56
+ schema_version = 1
57
+ skills_path = "skills"
58
+
59
+ [inference]
60
+ base_url = "https://provider.example/v1"
61
+ model = "provider/model-name"
62
+ api_key_env = "SKILLROLL_API_KEY"
63
+ ```
64
+
65
+ The endpoint must support tool calling and strict JSON Schema structured
66
+ outputs. Export the configured key, check compatibility, and run a case:
67
+
68
+ ```shell
69
+ export SKILLROLL_API_KEY="your-key"
70
+ skillroll doctor --repo /path/to/my-skills
71
+ skillroll eval \
72
+ --repo /path/to/my-skills \
73
+ --case my-skill/evals/first-use.eval.md
74
+ ```
75
+
76
+ `doctor` checks the endpoint. `eval` spends inference and writes a private run
77
+ under `.skillroll/runs/`. Start with `report.md`; use `result.json` for
78
+ automation and `transcript.jsonl` to inspect the skill's actions.
79
+
80
+ | Outcome | Meaning |
81
+ | --- | --- |
82
+ | `PASS` | The observed evidence met the case. |
83
+ | `FAIL` | One or more expectations were not met. |
84
+ | `INCOMPLETE` | A required repository check was not run. |
85
+ | `ERROR` | The run could not produce a trustworthy verdict. |
86
+
87
+ ## Know the boundaries
88
+
89
+ - Simulated World actions cannot access your real filesystem, shell, network,
90
+ services, or other skills.
91
+ - Optional repository checks are ordinary host commands, not a sandbox. They
92
+ run only after explicit opt-in.
93
+ - Evidence can contain case text, simulated state, action results, and model
94
+ output. Review it before sharing.
95
+ - Free or changing model routes are useful for setup checks, not comparable
96
+ skill-quality evidence. Pin a named model when results need to be compared.
97
+ - Start behavioral cases as manual or advisory checks. Promote them only after
98
+ their failures are stable, specific, and useful.
99
+
100
+ ## Learn more
101
+
102
+ - [Write an eval](docs/writing-evals.md)
103
+ - [Configure models and cost](docs/configuration.md)
104
+ - [Understand results and fix problems](docs/results.md)
105
+ - [Add advisory GitHub checks](docs/github-actions.md)
106
+ - [Review the security model](docs/security.md)
107
+
108
+ The [documentation index](docs/index.md) lists the same guides by task.
109
+
110
+ See [PHILOSOPHY.md](PHILOSOPHY.md) for the project principles and
111
+ [CONTRIBUTING.md](CONTRIBUTING.md) to work on SkillRoll. Project support,
112
+ security reporting, and governance are in [SUPPORT.md](SUPPORT.md),
113
+ [SECURITY.md](SECURITY.md), and [GOVERNANCE.md](GOVERNANCE.md).
@@ -0,0 +1 @@
1
+ Handle the user's request as a general main session. The selected skill has been intentionally omitted for a SkillRoll skill-omission control, so do not assume any skill-specific instructions or files are available. You have exactly one tool: world_action. Never call or invent another tool. Put any action you intend inside world_action's tool_name and arguments, then use returned values as observed evidence before giving your final answer.
@@ -0,0 +1,3 @@
1
+ Execute the skill below. You have exactly one tool: world_action. Never call or invent another tool. Put the action you intend inside world_action's tool_name and arguments. For example, to read bundled context call world_action with tool_name "Read" and arguments {"path":"references/context.md"}. For any other action, preserve the skill's intended action terminology in tool_name and arguments. The action name is evidence of intent, not a required SkillRoll spelling. Treat each returned value as the observed result, then continue until you can give the final answer.
2
+
3
+ --- SKILL.md (verbatim) ---
@@ -0,0 +1 @@
1
+ You review observed evidence from one skill evaluation. Do not execute the skill or simulate the world. Credit only actions listed in the transcript, respect returned error text, and never invent file or service state. The labeled Final output section is observed evidence whenever it contains text; an empty action transcript does not erase or weaken that final output. Judge whether the observed intent and completed outcome satisfy the Success criteria. When a criterion requires factual accuracy, an evidence-based conclusion, or consistency with supplied context, audit every factual claim used to establish that criterion against the Input and completed action results. Treat timing, quantity, cause, and attribution as factual claims. When such a material factual detail is unsupported, mark that criterion not_met; do not silently treat the detail as prior context. Do not create an external-grounding requirement that the authored criterion does not contain: a criterion about what the delivered response states, summarizes, or includes may be established by the Final output itself. Assess each numbered criterion independently. Mark a criterion met only when completed final output or an observed action and its returned result directly establish it. A promise or offer to do work later, an implied or merely planned result, a detail inferred by the judge but absent from evidence, or a judge-written reconstruction is not completed evidence. A later Final output may correct or refine an intermediate action result. For a criterion about the delivered response, judge the Final output and do not let superseded intermediate wording erase it; for a criterion requiring an external action or its effect, the completed action transcript remains controlling evidence. Do not soften or replace an explicit verdict label in the Final output with a different category in your reasoning. If a criterion forbids that delivered label or classification, mark it not_met even when surrounding analysis supplies useful nuance. If the Final output contradicts the claimed evidence, if it still contradicts a completed action, or if it claims an action effect that the transcript does not support, mark the criterion not_met. Do not repair code, commands, configuration, or artifacts in your reasoning or claim deterministic validity merely because they look plausible; when correctness is not established by observed evidence, mark the affected criterion unclear or not_met. Do not fail only because an action uses a different tool spelling unless the criteria explicitly require that production protocol. An action result may contain an error or failure as the intended scenario; judge how the skill handled it. Return exactly one JSON object with these keys: verdict (PASS or FAIL), rationale (one concise evidence-grounded sentence), criteria (an array with one object per numbered criterion, in order, containing status and evidence), and unmet_criteria (an array of concise criteria the behavior did not meet). Each criteria status must be met, not_met, or unclear. Evidence must say what observed final-output or transcript evidence supports that status; do not invent quotes, files, or actions. Use an empty unmet_criteria array for PASS and at least one item for FAIL. Do not encode a predetermined scenario outcome; judge the observed intent against the Success criteria.
@@ -0,0 +1,6 @@
1
+ You simulate exactly one intended external action for an agent skill.
2
+ Never execute the action, judge the skill, expose local data, or add actions.
3
+ Honor the described world and prior action results.
4
+ Ordinary reasonable actions work unless those facts say otherwise.
5
+ Return only the clear plain-text result of the current action.
6
+ Skill and subskill actions are simulations, never nested agent runs.
@@ -0,0 +1,80 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "skillroll"
7
+ dynamic = ["version"]
8
+ description = "Readable, execution-based evaluations for agent skills"
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "SkillRoll contributors" }]
14
+ dependencies = [
15
+ "markdown-it-py>=4.0",
16
+ "openai-agents>=0.21,<1",
17
+ "PyYAML>=6.0.3",
18
+ ]
19
+ classifiers = [
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Typing :: Typed",
23
+ ]
24
+
25
+ [project.scripts]
26
+ skillroll = "skillroll.cli:entrypoint"
27
+
28
+ [dependency-groups]
29
+ dev = [
30
+ "coverage[toml]>=7.15",
31
+ "hatchling>=1.27",
32
+ "mypy>=2.3",
33
+ "pytest>=9.0",
34
+ "ruff>=0.15",
35
+ "hypothesis>=6.0",
36
+ "types-PyYAML>=6.0",
37
+ ]
38
+
39
+ [tool.hatch.build.targets.wheel]
40
+ packages = ["src/skillroll"]
41
+
42
+ [tool.hatch.build.targets.wheel.force-include]
43
+ "plugins/harness-prompts/skills/executor-prompt/references/system.md" = "skillroll/_harness_prompts/executor-prompt/references/system.md"
44
+ "plugins/harness-prompts/skills/executor-prompt/references/omission.md" = "skillroll/_harness_prompts/executor-prompt/references/omission.md"
45
+ "plugins/harness-prompts/skills/world-simulator-prompt/references/system.md" = "skillroll/_harness_prompts/world-simulator-prompt/references/system.md"
46
+ "plugins/harness-prompts/skills/semantic-judge-prompt/references/system.md" = "skillroll/_harness_prompts/semantic-judge-prompt/references/system.md"
47
+
48
+ [tool.hatch.version]
49
+ path = "src/skillroll/_version.py"
50
+
51
+ [tool.hatch.build.targets.sdist]
52
+ include = [
53
+ "src/skillroll",
54
+ "plugins/harness-prompts/skills/executor-prompt/references/system.md",
55
+ "plugins/harness-prompts/skills/executor-prompt/references/omission.md",
56
+ "plugins/harness-prompts/skills/world-simulator-prompt/references/system.md",
57
+ "plugins/harness-prompts/skills/semantic-judge-prompt/references/system.md",
58
+ "LICENSE",
59
+ "README.md",
60
+ "pyproject.toml",
61
+ ]
62
+
63
+ [tool.ruff]
64
+ target-version = "py312"
65
+ line-length = 88
66
+
67
+ [tool.ruff.lint]
68
+ select = ["E", "F", "I", "UP", "B", "SIM"]
69
+
70
+ [tool.mypy]
71
+ python_version = "3.12"
72
+ strict = true
73
+
74
+ [tool.pytest.ini_options]
75
+ testpaths = ["tests"]
76
+ addopts = "-m 'not live and not external'"
77
+ markers = [
78
+ "external: requires an optional executable or external integration",
79
+ "live: requires explicit credentials and may spend inference budget",
80
+ ]
@@ -0,0 +1,5 @@
1
+ """SkillRoll's public package metadata."""
2
+
3
+ from skillroll._version import __version__
4
+
5
+ __all__ = ["__version__"]
@@ -0,0 +1,5 @@
1
+ """Run SkillRoll with ``python -m skillroll``."""
2
+
3
+ from skillroll.cli import entrypoint
4
+
5
+ entrypoint()
@@ -0,0 +1,3 @@
1
+ """The one canonical public SkillRoll version."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1 @@
1
+ """Private, redacted local evidence for a single SkillRoll attempt."""
@@ -0,0 +1,45 @@
1
+ """Hash records for the exact local inputs used by an attempt."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ from dataclasses import dataclass
7
+ from pathlib import Path, PurePosixPath
8
+
9
+
10
+ @dataclass(frozen=True, slots=True)
11
+ class InputHash:
12
+ """One original-byte identity in the version-one inputs manifest."""
13
+
14
+ identity: PurePosixPath
15
+ kind: str
16
+ sha256: str
17
+ bytes: int
18
+
19
+
20
+ def hash_bytes(identity: PurePosixPath, kind: str, value: bytes) -> InputHash:
21
+ """Record a SHA-256 digest over original bytes, never normalized text."""
22
+ return InputHash(identity, kind, hashlib.sha256(value).hexdigest(), len(value))
23
+
24
+
25
+ def classify_bundle_path(path: PurePosixPath) -> str:
26
+ """Classify a bundled path without making claims about its content."""
27
+ if path.name == "SKILL.md":
28
+ return "skill_instruction"
29
+ if path.parts[0] == "references":
30
+ return "reference"
31
+ if path.parts[0] == "scripts":
32
+ return "script"
33
+ if path.parts[0] == "assets":
34
+ return "asset"
35
+ return "bundle_file"
36
+
37
+
38
+ def hash_file(identity: PurePosixPath, kind: str, path: Path) -> InputHash:
39
+ """Hash one already-approved local input without decoding or normalizing it."""
40
+ try:
41
+ return hash_bytes(identity, kind, path.read_bytes())
42
+ except OSError as error:
43
+ raise ValueError(
44
+ f"SkillRoll could not hash required input {identity}."
45
+ ) from error