Quick Start¶
This walks you from a fresh build to the warm inner loop in a few minutes. tiderace is a pure-Rust test engine — it runs your Python tests directly, with no pytest at runtime.
1. Build the engine¶
tiderace builds from source from the engine/ Cargo workspace. You need a Rust toolchain and a Python 3.12+ interpreter (the engine uses CPython's sys.monitoring for coverage).
This produces two binaries under engine/target/release/:
tiderace— one-shot CLI (collect,run).tiderace-daemon— the warm server (run,run --all,serve,watch,bench,probe).
Platforms
Linux, macOS, and Windows are all supported. Windows has no fork(), so isolation there is no-fork + snapshot/restore, and the opt-in sub-interpreter tier (CPython 3.14+) adds parallel no-fork execution. run / run --all / watch work everywhere; only the serve RPC socket is Unix-only.
2. Point the engine at Python¶
The engine is env-driven. Two variables matter to start:
# Required: the Python shim the engine runs inside CPython (it imports your code & invokes bodies).
export TIDERACE_SHIM="$PWD/py-shim/shim.py"
# Optional: the interpreter (defaults to python3). Use your project's venv if it has deps.
export TIDERACE_PYTHON="$(which python3)"
TIDERACE_SHIM is mandatory — without it the binaries exit with an error. See Configuration for the full set of variables.
3. First run — everything executes¶
Point the daemon at your tests. The impact-aware run does a full pass the first time (there's no prior state to compare against), recording each test's coverage footprint:
Behind that line, tiderace:
- Collected your tests via fast regex scanning (Rust).
- Built the fixture closure per test (Rust).
- Launched a warm wellspring per core and ran every test through the isolation ladder — pure tests in-process, the rest snapshot/restored, only opaque modules forked.
- Captured per-test coverage via
sys.monitoringand persisted it to.tiderace-state.json(per-test deps + file content hashes).
4. Second run — nothing changes, nothing runs¶
Run the exact same command again without touching any files:
Zero tests execute — tiderace hashes the files, sees nothing changed, and serves the prior outcomes. With no changes the warm interpreter isn't even launched. This is the impact-skip path.
5. After an edit — only impacted tests re-run¶
Edit a test file or a source file it depends on, then run again:
Only the tests whose recorded dependencies include the changed file re-execute. Impact analysis is conservative: a test is re-run when its own file changed, when a recorded dependency changed, or when it has no recorded footprint yet (e.g. the very first run).
6. Force a full run¶
When you want every test to execute regardless of state — a clean baseline, or a CI gate — use run --all:
This runs the whole suite across the parallel pool. (--all opts out of the impact-skip and its coverage recording; use plain run to keep the dependency graph fresh.)
7. The inner loop — watch¶
For an editor loop, keep the interpreter warm and re-run only what each save impacts:
watching /path/to/tests (Ctrl-C to stop)…
src/auth.py: Ran(2)
test_auth.py: Recollected(5)
conftest.py: Recycled(12)
Each save classifies the change (source edit → re-run impacted; test file → re-collect; conftest → recycle the warm interpreter) and does the minimum work — millisecond feedback. watch keeps a long-lived warm process, so it's a local-dev tool; CI should use fresh run / run --all. See Watch Mode.
Next steps¶
- Configuration — every environment variable and the
--allflag - Watch Mode — the warm inner loop in detail
- CI — safe vs fast modes, caching
.tiderace-state.json - How impact analysis works
- Benchmarks — run the comparison yourself