PyTaskWireCheck
Local-first, dependency-aware task orchestration for Python.
Describe your tasks and how they depend on each other. PyTaskWireCheck works out the order, runs independent work in parallel, retries the flaky parts, skips work that hasn't changed, and tells you exactly why — without a server, a daemon, or a single byte leaving your machine.
Why PyTaskWireCheck
Most build tools want to own your project. PyTaskWireCheck does one job: it orchestrates other programs. You already have the scripts, the compilers, the test runners, the data jobs — PyTaskWireCheck just knows which ones can run at once, which must wait, and which can be skipped because nothing they depend on has changed.
- Local-first. No server, no account, no telemetry. State lives in
.pytaskwirecheck/inside your project. - Dependency-aware. Tasks declare
depends_on; PyTaskWireCheck topologically sorts them and runs every independent branch concurrently. - Content-addressed cache. Tasks declare
inputsandoutputs. If the fingerprint is unchanged, the task is skipped and its outputs restored. - Deterministic failure handling.
fail_fastor continue-and-block, with a documented state machine — never a half-observed status. - Scriptable and embeddable. A first-class CLI and a small Python API.
- Zero runtime dependencies on Python 3.11+, one tiny backport otherwise.
Install
pip install PyTaskWireCheck
# or, for the bleeding edge:
pip install "PyTaskWireCheck @ git+https://github.com/Mullassery/PyTaskWireCheck"
PyTaskWireCheck targets Python 3.9 – 3.13. The import name and the command are both
pytaskwirecheck.
pytaskwirecheck --version
Quick start
pytaskwirecheck init # write a starter pytaskwirecheck.toml
pytaskwirecheck validate # check the config and the graph
pytaskwirecheck graph # print the DAG (text, dot, or json)
pytaskwirecheck plan # show levels, order, and max parallelism
pytaskwirecheck run # run everything, in dependency order
A minimal pytaskwirecheck.toml:
[project]
name = "example-workflow"
version = 1
[execution]
max_workers = 4
fail_fast = false
[tasks.fetch]
command = ["python", "scripts/fetch.py"]
outputs = ["data/raw.json"]
[tasks.transform]
command = ["python", "scripts/transform.py"]
depends_on = ["fetch"]
inputs = ["data/raw.json"]
outputs = ["data/clean.parquet"]
[tasks.test]
command = ["pytest", "-q"]
depends_on = ["transform"]
Run it:
$ pytaskwirecheck run
run 3f9c1a2b4d5e
fetch running
transform pending
test pending
fetch succeeded 0.84s
transform running
transform succeeded 1.20s
test running
test succeeded 3.05s
ok: 3 succeeded in 5.11s
Features at a glance
| Area | What you get |
|---|---|
| Graph | depends_on, cycle detection, missing-dependency detection, topological levels |
| Scheduling | bounded concurrency, deterministic ordering, fail_fast or continue-and-block |
| Processes | streaming output, process groups, timeouts, cooperative cancellation, output budget |
| Retries | bounded attempts, fixed or exponential backoff, retry-on-exit-code |
| Cache | content-addressed, sha256-verified, atomic commits, corrupt-entry recovery |
| CLI | init validate graph plan run cache explain history, each with --json |
| TUI | optional live dashboard when attached to a TTY (run --tui) |
| Persistence | local run history (SQLite, WAL) and optional webhook notifications |
| Library | Workflow.from_file(...).run() and functional helpers |
Command-line reference
pytaskwirecheck [-C ROOT] [--config PATH] [--no-color] COMMAND ...
init [--path DIR] [--force] create a starter configuration
validate [--json] validate configuration and graph
graph [--format text|dot|json] display the task DAG
plan [TASKS...] [--json] show the execution plan
run [TASKS...] [--no-cache] [--max-workers N] [--fail-fast|--no-fail-fast]
[--json] [-q] [--no-output] [--tui]
cache status [--json] show cache statistics
cache clean [--force] [--json] remove cached data
explain TASK [--json] explain scheduling and cache status for a task
history [--limit N] [--json] show recent execution summaries
run accepts task names and runs only those tasks plus their dependencies. Add
--json for a machine-readable summary, and -q to silence progress.
Exit codes
| Code | Meaning |
|---|---|
0 |
success |
1 |
one or more tasks failed |
2 |
usage or configuration error |
3 |
graph error (cycle, missing dependency, unknown target) |
130 |
interrupted (Ctrl-C) |
Python API
from pytaskwirecheck import Workflow
workflow = Workflow.from_file("pytaskwirecheck.toml")
# Inspect before running.
plan = workflow.plan(["test"])
print(plan.order, plan.max_parallelism)
# Run and react to events.
def on_event(event):
print(type(event).__name__, event)
result = workflow.run(["test"], on_event=on_event)
if not result.succeeded:
for task_id, record in result.records.items():
if not record.status.is_success:
print(task_id, record.status.value, record.exit_code)
raise SystemExit(0 if result.succeeded else 1)
Functional helpers are available for one-liners:
import pytaskwirecheck
plan = pytaskwirecheck.validate(root=".") # -> ExecutionPlan
result = pytaskwirecheck.run(["build"], path="ci.toml")
Workflow.run supports use_cache, max_workers, fail_fast, on_event,
cancel_token, record_history, and notify. See
docs/python-api.md.
Caching model
The cache is content-addressed and conservative by design:
- A task is cache-eligible only if it declares
inputsoroutputs(otherwise its side effects are unknown, so PyTaskWireCheck never guesses). - The fingerprint covers the command, resolved inputs (hashing file contents), declared outputs' expectations, relevant environment variables, the config schema version, and the cache keys of upstream dependencies.
- A hit restores declared outputs, but only after verifying every stored file's sha256 and size; anything corrupt is discarded rather than trusted.
- Commits are atomic (staged, then
os.replace), and protected by a cross-process lock. Restores are confined to the workspace root. - Environment values are hashed, never stored in plaintext.
Disable it globally ([cache] enabled = false), per task (cache = false), or
per run (pytaskwirecheck run --no-cache). Inspect decisions with
pytaskwirecheck explain TASK.
Execution semantics
Every task moves through an explicit state machine:
PENDING → READY → RUNNING → SUCCEEDED | FAILED | TIMED_OUT | CACHED
↘ CANCELLED
dependents of a failure → BLOCKED
fail_fast = truestops launching new tasks and cancels in-flight work as soon as a task fails.fail_fast = falselets unrelated branches finish; only the transitive dependents of the failed task becomeBLOCKED.- A cancelled, timed-out, or failed task is never cached.
- Persistence (history, notifications) is best-effort and never changes a run's outcome or exit code.
Architecture
pytaskwirecheck.toml
│
▼
config ──▶ graph ──▶ planner ──▶ scheduler ──▶ executor ──▶ processes
(schema, (DAG, (levels, (bounded (retries, (streaming,
validation) builder) order) concurrency) cache hooks) process groups)
│
▼
events ──▶ CLI / TUI / logs / history
Each layer depends only on the one below it. The scheduler owns state transitions; the executor owns retries and cache interaction; the process runner owns the subprocess. Rendering and persistence are observers, never participants. Read the full design in docs/architecture.md.
Documentation
| Document | Contents |
|---|---|
| docs/architecture.md | Layers, data flow, state machine, design rules |
| docs/configuration.md | Every pytaskwirecheck.toml field |
| docs/execution.md | Scheduling, retries, timeouts, cancellation |
| docs/caching.md | Fingerprints, storage, integrity, eviction |
| docs/cli.md | Commands, flags, exit codes |
| docs/python-api.md | Embedding PyTaskWireCheck as a library |
| docs/security.md | Trust model and hardening |
| docs/development.md | Contributing, tests, tooling |
| docs/roadmap.md | Where PyTaskWireCheck is going |
| docs/implementation-status.md | What is done and verified |
Status
PyTaskWireCheck is 0.1.0 — a complete, tested horizontal slice: config → graph →
scheduler → runner → cache → CLI → TUI → history → notifications. See
docs/implementation-status.md for the verified
breakdown. It is pre-1.0, so the configuration schema is versioned (version = 1)
and unsupported versions are rejected rather than guessed at.
Contributing
Issues and pull requests are welcome. Start with CONTRIBUTING.md and docs/development.md. Please follow the Code of Conduct and report vulnerabilities via SECURITY.md.
License
MIT — see LICENSE.
Metadata
Release files for PyTaskWireCheck 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pytaskwirecheck-0.1.0.tar.gz | 60.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pytaskwirecheck-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 122.7 kB
Release files / pytaskwirecheck-0.1.0.tar.gz
| Download URL | pytaskwirecheck-0.1.0.tar.gz |
|---|---|
| Size | 60.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cceba3a0942f22f8745fe19185e7cdb4bbd24cfb193e97918515172f0706f230
|
|
BLAKE2b-256 checksum How to use checksums |
6ee29a70ee716e440bcd919a2bcf3d72f5307f147ce9c7f09b3d01aa42409df7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Release files / pytaskwirecheck-0.1.0-py3-none-any.whl
| Download URL | pytaskwirecheck-0.1.0-py3-none-any.whl |
|---|---|
| Size | 62.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e19f72093b8e01baed1d4c3600c4cee2d314b5e9f5332c6b6f0fe369cf8c3fb3
|
|
BLAKE2b-256 checksum How to use checksums |
89d49d35183ff1c34d835f568a30a7803ac8404376f6a4d95086a2596d05a53f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|