stapel-taskspecs
Versioned schemas and models for the artifacts that flow through the Stapel Studio pipeline: a TaskSpec goes to an architect, a TaskReport comes back from a runner, a SpecPatch amends the project spec, a QAReport records per-criterion acceptance, an EscalationQuestion asks a human, and a ReviewFinding captures a falsifiable review claim.
This is a small, Django-free, pure-Python library. It carries the shape of the artifacts — fields, types, states — and nothing of the pipeline's brains. It sits on the OSS side of the OSS/moat boundary: boundaries are schemas (studio-design §6). Prompts, anti-cheat detectors, routing config and escalation thresholds are not here and never will be.
Install
pip install stapel-taskspecs
Runtime dependencies are just two: jsonschema (validation) and PyYAML (the YAML front-matter header). See "Why these dependencies" below.
What's in the box
| Artifact | Schema | Model | Purpose |
|---|---|---|---|
| TaskSpec | schemas/task_spec.v1.json |
TaskSpec |
unit of work: id, type, goal, criteria, budget, risk, deps |
| TaskReport | schemas/task_report.v1.json |
TaskReport |
attempt outcome: status, controls, files, commits, usage |
| SpecPatch | schemas/spec_patch.v1.json |
SpecPatch |
operations over the project spec + confirmation text |
| QAReport | schemas/qa_report.v1.json |
QAReport |
per-criterion pass/fail with screenshot/repro refs |
| EscalationQuestion | schemas/escalation_question.v1.json |
EscalationQuestion |
business-language question + options |
| ReviewFinding | schemas/review_finding.v1.json |
ReviewFinding |
fingerprint + falsifiable claim + severity |
| UsageSplit | schemas/usage_split.v1.json |
UsageSplit |
the strict five-component token split |
Every artifact carries schema_version: 1.
Quickstart
from stapel_taskspecs import TaskSpec, TaskReport, validate, taskspec_from_markdown
# Parse + validate a JSON payload into a typed model
spec = TaskSpec.parse({
"schema_version": 1,
"id": "T-001",
"type": "feature",
"goal": "CRUD entity: list, create, view and edit",
"risk": ["validation"],
"criteria": [{"id": "C1", "text": "Given: empty db; When: POST; Then: 201"}],
"budget": {"iterations": 3, "wall_min": 20},
})
# Validate a raw dict without building a model
validate(spec.to_dict(), "task_spec")
# Read the repository projection (markdown + YAML front matter)
spec = taskspec_from_markdown(open("TASKS/T-001.md").read())
print(spec.id, spec.criteria)
The five-component usage split is mandatory and closed
TaskReport.usage is a UsageSplit of exactly five non-negative integers —
cache_read, cache_write, fresh_input, output, thinking — and nothing
else. Every report carries it (report zeros, never omit it). This is a protocol
condition, not a convenience: without a dedicated thinking column the
economics of reasoning-class models (thinking tokens billed as output) are
understated.
report = TaskReport.parse({
"schema_version": 1,
"task_id": "T-001",
"status": "done",
"usage": {"cache_read": 18000, "cache_write": 0,
"fresh_input": 320, "output": 640, "thinking": 0},
})
report.usage.prompt_tokens # cache_read + cache_write + fresh_input
A missing, extra, negative or non-integer component fails validation.
Markdown <-> JSON
Tasks live in a project repo as human-readable markdown with a YAML front-matter header (machine fields up top, prose below); inside the pipeline everything is JSON validated by schema (system-design §7.17). This library is the bridge:
from stapel_taskspecs import taskspec_from_markdown, taskspec_to_markdown
spec = taskspec_from_markdown(md_text) # -> TaskSpec (body kept in .body)
md_text = taskspec_to_markdown(spec) # -> markdown projection
Forward compatibility
The artifact envelopes are forward-compatible: a v1 reader accepts (and
preserves, in model.extra) unknown top-level fields a newer producer added,
rather than rejecting the document. The one deliberate exception is
UsageSplit, which is closed by design.
Open by design (OSS/moat boundary)
Risk classes, model names, FSM statuses, severities and failure taxonomies are open strings/enums with documented examples — not hardcoded closed sets. A consuming host owns those value sets. Gate semantics (red-before-coder, path-ownership, finding falsifiability) are documented methodology; their implementations and detectors are private. This library is only the wire shape.
Why these dependencies
- jsonschema — the schemas are the product; a spec-compliant validator is
the honest way to enforce them, and it resolves the cross-file
usage_split$ref. - PyYAML — the front-matter header is YAML, so a YAML parser is
unavoidable. We parse the header with PyYAML and split the
---fence with the stdlib; we deliberately do not addpython-frontmatter(a whole dependency for a ten-line split, with its own metadata conventions we don't want).
Import is lazy (PEP 562): import stapel_taskspecs pulls in neither jsonschema
nor PyYAML until you touch a validation or front-matter symbol.
License
MIT.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file stapel_taskspecs-0.1.0.tar.gz.
File metadata
- Download URL: stapel_taskspecs-0.1.0.tar.gz
- Upload date:
- Size: 21.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84dc0007387b76cfec9722a4eda30624d1e7c28b4946c93bcb4a4c33c8e884c0
|
|
| MD5 |
1d2ce0f25f6cfa511c6510ff1da68a77
|
|
| BLAKE2b-256 |
368afff378d839c5412fd90514d0dd4bcfceb0c3d7a2edc58c5d511bf5e31b4a
|
Provenance
The following attestation bundles were made for stapel_taskspecs-0.1.0.tar.gz:
Publisher:
publish.yml on usestapel/stapel-taskspecs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stapel_taskspecs-0.1.0.tar.gz -
Subject digest:
84dc0007387b76cfec9722a4eda30624d1e7c28b4946c93bcb4a4c33c8e884c0 - Sigstore transparency entry: 2568412349
- Sigstore integration time:
-
Permalink:
usestapel/stapel-taskspecs@2444a69df091573cb4c4e2e3736bc692e82073ee -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/usestapel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2444a69df091573cb4c4e2e3736bc692e82073ee -
Trigger Event:
push
-
Statement type:
File details
Details for the file stapel_taskspecs-0.1.0-py3-none-any.whl.
File metadata
- Download URL: stapel_taskspecs-0.1.0-py3-none-any.whl
- Upload date:
- Size: 21.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63de874fd76d2585374c0bbe3b5c08931d37d652adc7f511a1fe8c2cb4551791
|
|
| MD5 |
ba941e11f5a7b957355d38c0dd515c59
|
|
| BLAKE2b-256 |
3832f8919488e5928c500c22677b0d039908fe2b63d6579472237708e4490329
|
Provenance
The following attestation bundles were made for stapel_taskspecs-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on usestapel/stapel-taskspecs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stapel_taskspecs-0.1.0-py3-none-any.whl -
Subject digest:
63de874fd76d2585374c0bbe3b5c08931d37d652adc7f511a1fe8c2cb4551791 - Sigstore transparency entry: 2568412361
- Sigstore integration time:
-
Permalink:
usestapel/stapel-taskspecs@2444a69df091573cb4c4e2e3736bc692e82073ee -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/usestapel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2444a69df091573cb4c4e2e3736bc692e82073ee -
Trigger Event:
push
-
Statement type: