Skip to main content

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") or Path(__file__).parent, including .parent chains;
  • 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-run reports the ordered plan and a reason for each task without writing the manifest or outputs.
  • --force always reruns the target in addition to stale dependencies.
  • --force-all reruns the target's entire upstream closure.
  • --debug executes 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=path is repeatable. Relative paths resolve against the project root. Unknown names fail with the list of available variables.
  • --local-file points at a python file following the same static contract as local.py. Variables matching names in local.py become overrides; other variables are helpers and are ignored. --set wins on conflicts.
  • Derived variables are recomputed: overriding output_path also 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 run behaves 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. kind is one of parse_error, task_not_found, run_error, init_error, or error, so callers can branch without parsing the message.
  • When run fails partway through a plan, the failure envelope also includes executed: the task IDs that completed (and were recorded in the manifest) before the failure.
  • run --dry-run never fails on a missing raw input; the plan reports it as a missing_input reason so a build can always be previewed.
  • When --set/--local-file overrides are active, run envelopes 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)

Source distribution for stooge 0.1.2
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)

Table of built distributions (wheels) for stooge 0.1.2
File Interpreter ABI Platform Actions
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 log

Release 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 log

Security 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.

Select from 2 files

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 log

A 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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page