yuj
yuj scatters work across idle lab desktops over SSH and pulls the results back. A self-healing watchdog on each host keeps the batch running through crashes and reboots, so you don't need root on the machines or a scheduler watching over them.
If you have a 'batch of jobs' that can be split into independent items, you can use yuj to achieve effective and fast parallelisation. Each item runs on one host on its own, with no communication between items and no shared memory.
yuj will not work if your job needs nodes to talk to each other mid-run (MPI, a shared address space).
Quickstart
# Python job
pipx install yuj
mkdir my-job && cd my-job
yuj init --template python # scaffold worker.py + config
$EDITOR fleet.csv # add hosts (username, IP, password or key)
yuj bootstrap # install Python (uv) on each host, no root
yuj deploy && yuj submit # push code, start watchdog + cron
yuj status --watch 30 # live dashboard
yuj pull --loop 60
yuj decommission lab-desk-1 --at "9am tomorrow"
# R job
pipx install yuj
mkdir my-r-job && cd my-r-job
yuj init --template r # scaffold worker.R + environment.yaml
$EDITOR fleet.csv
yuj bootstrap # install R via micromamba, no root or compiler
yuj deploy && yuj submit
yuj status --watch 30
yuj pull --loop 60
See the full quickstart and R users guide in the docs.
How it works
- provision (optional): if you only have an admin/sudo login,
yuj provisioncreates a dedicated worker user with key-only auth and writes aprovisioned-fleet.csvyou can hand to the rest of the commands. This is the one step that needs privilege. - deploy: rsync your code + data to
$HOMEon each host. Aborts up front if a configured path is missing locally. - submit: dry-run the work command on one host first (a canary), so a broken job aborts before it installs a watchdog everywhere. Then install a watchdog and a cron entry that restarts it every 15 min. The watchdog runs your work loop, detects stalls (no new output in N min), and relaunches.
- resume: the work loop skips any item whose output file already exists. This is the only reliable checkpoint when a worker crashes mid-write.
- pull: parallel rsync of outputs back to a central directory, tolerant of hosts being down.
- survive: supervision lives in cron on each host, so a rebooted host resumes within 15 min with no controller involved.
Caveats
- Passwords work but trigger fail2ban on repeated auth failures. Pass
key_pathinfleet.csvto avoid this. - A few failed auths can get your IP banned for hours.
yuj diagnoseclassifies what's wrong (net down / sshd down / banner drop / auth refused); it won't hammer a banned host. - Passwords are stored as plain text in fleet.csv. The
.gitignoreexcludes it by default, but double-check before pushing. yuj statusshows a warning when someone is at the console. Useyuj decommission --at "9am tomorrow"to hand machines back at a civilised time.
Development
uv sync --locked # create the venv and install dev deps
uv run pytest # tests
uv run ruff check . # lint
uv run ruff format . # format
uv run mypy src # strict type-check
License
Metadata
Release files for yuj 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 | Provenance | Actions |
|---|---|---|---|---|
| yuj-0.1.0.tar.gz | 205.7 kB | With provenance | Details for yuj-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| yuj-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for yuj-0.1.0-py3-none-any.whl |
Total release size: 300.9 kB
Release files / yuj-0.1.0.tar.gz
| Download URL | yuj-0.1.0.tar.gz |
|---|---|
| Size | 205.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
baa2dcd500c0d24f4e8a2903a3121380f8c8d5a7f627703474dacab58f7899be
|
|
BLAKE2b-256 checksum How to use checksums |
17d7a35989e50fd0775b7648ea5dc7301433bfcc30fcea602afa70aa7f112371
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
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 Jul 17, 2026.
Transparency logRelease files / yuj-0.1.0-py3-none-any.whl
| Download URL | yuj-0.1.0-py3-none-any.whl |
|---|---|
| Size | 95.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
90a45e977ac67f969634d7d1b124fbaf4486af41cc7ca7d98f8f8acac20dea42
|
|
BLAKE2b-256 checksum How to use checksums |
351b5ef91ebcab41aa88e9f946f074247bf90f5be9273509c37f7a0ccbbbb962
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
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 Jul 17, 2026.
Transparency logSecurity for yuj 0.1.0
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 yuj-0.1.0.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 Jul 17, 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.