stooge
Stooge is a small CLI and Python framework for reproducible local research projects. It discovers dependencies between numbered scripts and runs only the tasks whose declared outputs are missing or stale.
Stooge requires Python 3.12 or newer. Supported execution backends are uv and the current Python interpreter.
Project structure
Task scripts use canonical IDs: one lowercase letter and three digits, such as
a010_clean.py, a020_calculate.py, or v010_plot.py. Uppercase letters are
not valid. The letter is free to group related tasks and has no other meaning:
tasks may depend on outputs from any series, in either direction. Dependencies
decide execution order, and remaining ties run in sorted task-ID order (a010,
a020, b010). Any other .py file whose name fits this pattern is treated as
a task and must declare an output.
Paths are declared in local.py. A path is an output when its variable name or
filename starts with the current script's task ID; other referenced paths are
inputs.
my_project/
├── inputs/raw.csv
├── local.py
├── a010_clean.py
└── a020_calculate.py
Stooge reads local.py statically and never executes it. Its deliberately
narrow contract supports top-level path assignments built from:
Path("literal")orPath(__file__).parent, including.parentchains;- an earlier path variable joined to string literals with
/; and - a simple alias of an earlier path variable.
Keep local.py free of side effects and project-module imports. Output parent
directories are created immediately before their producing task runs.
Parsing produces a deterministic .stooge.toml containing the backend, source
hashes, artifact paths, and direct task dependencies. Generated projects also
include a short AGENTS.md with these conventions.
Initialize, parse, and inspect
The uv backend is the default and includes a minimal pyproject.toml.
stooge init my_project --backend uv
stooge parse my_project
stooge parse my_project --dry-run
stooge info my_project
stooge info my_project --json
Use --backend python to run tasks with the interpreter that launched Stooge.
info is read-only and can inspect a project before its manifest exists.
Parsing rejects dynamic path expressions, duplicate task IDs, duplicate output producers, dependency cycles, tasks without outputs, and outputs outside the project root.
Plan and run
Commands accept an optional project path, so changing directories is not required:
stooge run a030 my_project --dry-run
stooge run a030 my_project
stooge run a030 my_project --json
A task is stale when an output is missing, its script content hash changed, or
its newest input is newer than its oldest output. Script mtimes alone do not
trigger work. A local.py edit only rebuilds tasks whose parsed definitions
change. When an upstream task runs, affected downstream tasks are rebuilt.
--dry-runreports the ordered plan and a reason for each task without writing the manifest or outputs.--forcealways reruns the target in addition to stale dependencies.--force-allreruns the target's entire upstream closure.--debugexecutes selected scripts under the standard-library debugger.
Override local paths for one run
For debugging, run can temporarily swap local.py path values without editing any project file:
stooge run a030 my_project --set output_path=/tmp/stooge_debug --dry-run --json
stooge run a030 my_project --set output_path=/tmp/stooge_debug --set input_path=alt_inputs
stooge run a030 my_project --local-file debug_local.py
--set name=pathis repeatable. Relative paths resolve against the project root. Unknown names fail with the list of available variables.--local-filepoints at a python file following the same static contract aslocal.py. Variables matching names inlocal.pybecome overrides; other variables are helpers and are ignored.--setwins on conflicts.- Derived variables are recomputed: overriding
output_pathalso moves every path defined from it (e.g.a030_result = output_path / "result.png"), both when planning and inside the executing script. - Overridden runs are ephemeral: the manifest is never written, no execution fingerprints are recorded, and fingerprint-based staleness is skipped (plans rest on missing outputs and mtimes at the overridden locations). A later plain
stooge runbehaves as if the overridden run never happened. - Overridden outputs may resolve outside the project root (e.g.
/tmp). - Works with
--dry-run,--json, and--debug.
Remove outputs
Remove or preview only the outputs declared by one task:
stooge remove a020 my_project --dry-run
stooge remove a020 my_project
stooge remove a020 my_project --json
Downstream results are retained and rebuilt when required by a later run. Files, symlinks, and output directories are supported. Stooge refuses to remove the project root or paths outside it.
JSON output
Every command except version accepts --json. The envelopes are a stable contract for scripts and agents:
- Success:
{"command": "<name>", "ok": true, ...}with command-specific fields. - Failure:
{"command": "<name>", "ok": false, "kind": "<kind>", "error": "<message>"}written to stdout with exit status 1.kindis one ofparse_error,task_not_found,run_error,init_error, orerror, so callers can branch without parsing the message. - When
runfails partway through a plan, the failure envelope also includesexecuted: the task IDs that completed (and were recorded in the manifest) before the failure. run --dry-runnever fails on a missing raw input; the plan reports it as amissing_inputreason so a build can always be previewed.- When
--set/--local-fileoverrides are active,runenvelopes include"overrides": {name: path}and"ephemeral": true.
Development
pip install -e '.[test]'
pytest
ruff check .
ruff format --check .
Stooge is optional by design: scripts remain directly executable in dependency
order. The supported Python API is listed in stooge.__all__.
Metadata
Release files for stooge 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| stooge-0.1.2.tar.gz | 61.2 kB | With provenance | Details for stooge-0.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| stooge-0.1.2-py3-none-any.whl | Python 3 | none | any | Details for stooge-0.1.2-py3-none-any.whl |
Total release size: 92.4 kB
Release files / stooge-0.1.2.tar.gz
| Download URL | stooge-0.1.2.tar.gz |
|---|---|
| Size | 61.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9369270cab42974483d5525d7f5998a549e680d4c553655e55f5ca9ab14ff1c1
|
|
BLAKE2b-256 checksum How to use checksums |
7bd870eef1b54712559a79354a9e65fdcea7f5363bf877fd5397836985221974
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / stooge-0.1.2-py3-none-any.whl
| Download URL | stooge-0.1.2-py3-none-any.whl |
|---|---|
| Size | 31.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
85edba9928818a3a1a537e14b8a71114bbae92dd6a10957f34cab412cd586058
|
|
BLAKE2b-256 checksum How to use checksums |
cabb46fc9b4f9f29325112518b5c47fffd7d7c8fba749d5ce593230a1968ac9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logSecurity for stooge 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for stooge-0.1.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.