Skip to content

rhiza-task

The rhiza developer tasks, as a pinned CLI β€” not a synced make layer.

PyPI Downloads Python CI License: MIT uv Ruff


Quick links: πŸ“¦ PyPI β€’ πŸ“š Repository β€’ πŸ› Issues β€’ 🌱 rhiza β€’ πŸ§ͺ pytest-rhiza


πŸ“‹ Overview

uvx rhiza-task@1.4.0 test

There is nothing to install and nothing to sync. One command runs a project's gates, and which gates those are is decided by the manifest in the repository β€” pyproject.toml, Cargo.toml or go.mod.

rhiza-task is the sibling of pytest-rhiza, which did the same thing for .rhiza/tests.

🎯 The problem it deletes

The pain was never make's syntax β€” it was distribution by copying, which make structurally cannot fix, because include cannot reach a remote file. Every consumer got a full copy of the task layer at a template tag, and everything downstream was damage control.

Version pinning becomes a dependency pin, which is a real mechanism instead of "copy files at tag v1.3.3 and hope nobody edited them."

before, per consumer repo after
.rhiza/rhiza.mk β€” 200 lines, synced gone
.rhiza/make.d/*.mk β€” 1023 lines in 15 files, synced gone
exclude: entries in template.yml, because a deletion alone is undone by the next sync not needed
targets shadowed in the repo Makefile [tool.rhiza-task]
~40 lines of GNU-make guard and Windows POSIX-shell probe gone β€” no make, no shell
install-uv β€” 30 lines of bootstrap.mk shell gone β€” uvx provisions the runtime
Makefile repo-owned, if a repo wants one

πŸš€ Three commands

  • See what is available


    Tasks, grouped by section, with prerequisites and a one-line description.

    uvx rhiza-task@1.4.0 list
    

    β†’ The task catalogue

  • Run every gate


    The aggregate CI runs: format, deps, test, docs, security, licence, types.

    uvx rhiza-task@1.4.0 all
    

    β†’ Getting started

  • Read a resolved setting


    Six configuration layers, collapsed to the one value a task will actually see.

    uvx rhiza-task@1.4.0 print coverage_fail_under
    

    β†’ Configuration

🧩 One set of names, three languages

test is pytest in a Python project, cargo nextest in a crate and go test in a module. That gate-parity contract is what lets a reusable workflow call typecheck without knowing the language.

flowchart LR
    M{which manifest?}
    M -- "pyproject.toml" --> P[python layer]
    M -- "Cargo.toml" --> R[rust layer]
    M -- "go.mod" --> G[go layer]
    P --> T["test Β· typecheck Β· coverage<br/>security Β· deps Β· license"]
    R --> T
    G --> T

The make layer answered "which one?" at sync time, by copying exactly one of python.mk, rust.mk and go.mk into a repository. A pinned CLI carries all three, so the answer is the manifest that is present β€” and the layers you do not have stay addressable as rhiza-task rust:test.

β†’ How the layers resolve

πŸ“ Why it is small

Reading all ten make fragments back to back, every recipe has the same three parts: a guard on a folder existing, a provision via uv run --with or uvx, and a long, mostly static argument list. So the model is declarative, with an escape hatch for the three recipes that genuinely are not.

β†’ The design Β· β†’ Adding your own task

πŸ“– Where to go next

If you want to… Read
run this against your project for the first time Getting Started
know what every task does, and when it skips Tasks
change a threshold, a folder or a typechecker Configuration
understand polyglot repositories and rust:test Language Layers
add a project-specific gate Adding a Task
retire a synced make layer Migrating from make
know why it is not a Taskfile FAQ