Reusable configuration templates for modern Python projects
Project description
rhiza-cli
Command-line interface for managing reusable configuration templates for modern Python projects.
📖 New to Rhiza? Check out the Getting Started Guide for a beginner-friendly introduction!
Overview
Rhiza is a CLI tool that helps you maintain consistent configuration across multiple Python projects by using templates stored in a central repository. It allows you to:
- Initialize projects with standard configuration templates
- Materialize (inject) templates into target repositories
- Validate template configurations
- Keep project configurations synchronized with template repositories
Table of Contents
- Overview
- Installation
- Quick Start
- Commands
- init
- sync
- materialize (deprecated)
- migrate
- validate
- Configuration
- Examples
- Development
- Additional Documentation
Additional Documentation
For more detailed information, see:
- Getting Started Guide - Beginner-friendly introduction and walkthrough
- CLI Quick Reference - Command syntax and quick examples
- Usage Guide - Practical tutorials and workflows
- Authentication Guide - Configuring credentials for private template repositories (GitHub PATs, SSH keys, GitLab tokens)
- Contributing Guidelines - How to contribute to the project
- Code of Conduct - Community guidelines
Installation
Using pip
pip install rhiza
To update to the latest version:
pip install --upgrade rhiza
Using uvx (run without installation)
uvx is part of the uv package manager and allows you to run CLI tools directly without installing them:
uvx rhiza --help
With uvx, you don't need to install rhiza globally. Each time you run uvx rhiza, it will automatically use the latest version available on PyPI. To ensure you're using the latest version, simply run your command - uvx will fetch updates as needed:
# Always uses the latest version
uvx rhiza init
uvx rhiza sync
uvx rhiza validate
If you want to use a specific version:
uvx rhiza@0.5.6 --help
From source
git clone https://github.com/jebel-quant/rhiza-cli.git
cd rhiza-cli
pip install -e .
Using uv (recommended for development)
git clone https://github.com/jebel-quant/rhiza-cli.git
cd rhiza-cli
make install
Verify installation
rhiza --help
Quick Start
-
Initialize a project with Rhiza templates:
cd your-project rhiza init
This creates a
.rhiza/template.ymlfile with default configuration. -
Customize the template configuration:
Edit
.rhiza/template.ymlto specify which files/directories to include from your template repository. -
Sync templates into your project:
rhiza syncThis fetches and copies template files into your project (first run) or applies updates via 3-way merge (subsequent runs).
-
Validate your configuration:
rhiza validateThis checks that your
.rhiza/template.ymlis correctly formatted and valid.
Commands
rhiza init
Initialize or validate .rhiza/template.yml in a target directory.
Usage:
rhiza init [OPTIONS] [TARGET]
Arguments:
TARGET- Target directory (defaults to current directory)
Options:
--project-name <name>- Custom project name (defaults to directory name)--package-name <name>- Custom package name (defaults to normalized project name)--with-dev-dependencies- Include development dependencies in pyproject.toml--git-host <host>- Target Git hosting platform (github or gitlab). Determines which CI/CD files to include. If not provided, will prompt interactively.--template-repository <owner/repo>- Custom template repository (format: owner/repo). Defaults to 'jebel-quant/rhiza'.--template-branch <branch>- Custom template branch. Defaults to 'main'.--path-to-template <directory>- Directory wheretemplate.ymlwill be created (defaults to<TARGET>/.rhiza). Use.to keep the file in the project root.
Description:
Creates a default .rhiza/template.yml file if it doesn't exist, or validates an existing one. The default configuration includes common Python project files like .github, .editorconfig, .gitignore, .pre-commit-config.yaml, Makefile, and pytest.ini.
You can customize the template source by specifying your own template repository and branch using the --template-repository and --template-branch options.
Examples:
# Initialize in current directory
rhiza init
# Initialize in a specific directory
rhiza init /path/to/project
# Initialize with GitLab CI configuration
rhiza init --git-host gitlab
# Use a custom template repository
rhiza init --template-repository myorg/my-templates
# Use a custom template repository and branch
rhiza init --template-repository myorg/my-templates --template-branch develop
# Initialize in parent directory
rhiza init ..
# Create template.yml in a custom directory
rhiza init --path-to-template /custom/rhiza
# Create template.yml in the project root
rhiza init --path-to-template .
Output:
When creating a new template file:
[INFO] Initializing Rhiza configuration in: /path/to/project
[INFO] Creating default .rhiza/template.yml
✓ Created .rhiza/template.yml
Next steps:
1. Review and customize .rhiza/template.yml to match your project needs
2. Run 'rhiza sync' to inject templates into your repository
When validating an existing file:
[INFO] Validating template configuration in: /path/to/project
✓ Found template file: /path/to/project/.rhiza/template.yml
✓ YAML syntax is valid
✓ Field 'template-repository' is present and valid
✓ Field 'include' is present and valid
✓ template-repository format is valid: jebel-quant/rhiza
✓ include list has 6 path(s)
✓ Validation passed: template.yml is valid
rhiza sync
Sync Rhiza configuration templates into a target repository using diff/merge, preserving local customisations.
Usage:
rhiza sync [OPTIONS] [TARGET]
Arguments:
TARGET- Target git repository directory (defaults to current directory)
Options:
--branch, -b TEXT- Rhiza branch to use [default: main]--strategy, -s TEXT- Sync strategy:merge(default) ordiff--target-branch TEXT- Create/checkout a branch in the target repo for changes--help- Show help message and exit
Description:
Keeps your project in sync with the template repository:
- First run (no lock file): copies all template files and writes
.rhiza/template.lock - Subsequent runs: computes diff (base → upstream) and applies it via
git apply -3— local edits are preserved
.rhiza/template.lock is a YAML file that records the full state of the last sync:
sha: abc123def456789abcdef0123456789abcdef0123
repo: jebel-quant/rhiza
host: github
ref: main
include:
- .github/
- .rhiza/
exclude: []
templates: []
files:
- .github/workflows/ci.yml
- .rhiza/template.yml
- Makefile
Commit
.rhiza/template.lockto version control — it is the anchor for incremental 3-way merges.
Examples:
# Sync templates (first time or update with 3-way merge)
rhiza sync
# Preview what would change (dry-run)
rhiza sync --strategy diff
# Sync from a specific branch
rhiza sync --branch develop
# Sync to a dedicated branch
rhiza sync --target-branch update-templates
Output:
[INFO] Target repository: /path/to/project
[INFO] Rhiza branch: main
[INFO] Sync strategy: merge
[INFO] Cloning jebel-quant/rhiza@main (upstream)
[INFO] Upstream HEAD: abc123def456
[INFO] First sync — copying all template files
[COPY] .github/workflows/ci.yml
[COPY] .editorconfig
[COPY] .gitignore
[COPY] Makefile
✓ Sync complete — 4 file(s) processed
rhiza materialize (Deprecated)
Deprecated. Use
rhiza syncinstead.
| Old command | Equivalent new command |
|---|---|
rhiza materialize |
rhiza sync |
rhiza materialize --force |
rhiza sync |
rhiza migrate
Migrate project to the new .rhiza folder structure.
Usage:
rhiza migrate [OPTIONS] [TARGET]
Arguments:
TARGET- Target git repository directory (defaults to current directory)
Arguments:
TARGET- Target git repository directory (defaults to current directory)
Description:
Migrates your project to use the new .rhiza/ folder structure for storing Rhiza state and configuration files. This command helps transition from the old structure where configuration was stored in .github/rhiza/ and .rhiza.history in the project root.
The migration performs the following actions:
- Creates the
.rhiza/directory in the project root - Moves
template.ymlfrom.github/rhiza/or.github/to.rhiza/template.yml - Moves
.rhiza.historyto.rhiza/history - Provides instructions for next steps
The new .rhiza/ folder structure provides better organization by separating Rhiza's state and configuration from the .github/ directory.
Examples:
# Migrate current directory
rhiza migrate
# Migrate a specific directory
rhiza migrate /path/to/project
Output:
[INFO] Migrating Rhiza structure in: /path/to/project
[INFO] This will create the .rhiza folder and migrate configuration files
[INFO] Creating .rhiza directory at: .rhiza
✓ Created .rhiza
[INFO] Found template.yml at: .rhiza/template.yml
[INFO] Moving to new location: .rhiza/template.yml
✓ Moved template.yml to .rhiza/template.yml
✓ Migration completed successfully
Migration Summary:
- Created .rhiza/ folder
- Moved template.yml to .rhiza/template.yml
- Moved history tracking to .rhiza/history
Next steps:
1. Review changes:
git status
git diff
2. Update other commands to use new .rhiza/ location
(Future rhiza versions will automatically use .rhiza/)
3. Commit the migration:
git add .
git commit -m "chore: migrate to .rhiza folder structure"
Notes:
- If files already exist in
.rhiza/, the migration will skip them and leave the old files in place - You can manually remove old files after verifying the migration was successful
- The old
.rhiza.historyfile is removed after successful migration to.rhiza/history - The original template file in
.github/is moved (removed from old location)
rhiza validate
Validate Rhiza template configuration.
Usage:
rhiza validate [TARGET] [OPTIONS]
Arguments:
TARGET- Target git repository directory (defaults to current directory)
Options:
--path-to-template DIRECTORY- Directory containingtemplate.yml(defaults to<TARGET>/.rhiza). Use.to keep the file in the project root.
Description:
Validates the .rhiza/template.yml file to ensure it is syntactically correct and semantically valid. This performs authoritative validation including:
- Checking if the file exists
- Validating YAML syntax
- Verifying required fields are present
- Checking field types and formats
- Validating repository name format
- Ensuring include paths are not empty
Examples:
# Validate configuration in current directory
rhiza validate
# Validate configuration in a specific directory
rhiza validate /path/to/project
# Validate parent directory
rhiza validate ..
# Validate using a custom template directory
rhiza validate --path-to-template /custom/rhiza
# Validate with template.yml in the project root
rhiza validate --path-to-template .
Exit codes:
0- Validation passed1- Validation failed
Output (success):
[INFO] Validating template configuration in: /path/to/project
✓ Found template file: /path/to/project/.rhiza/template.yml
✓ YAML syntax is valid
✓ Field 'template-repository' is present and valid
✓ Field 'include' is present and valid
✓ template-repository format is valid: jebel-quant/rhiza
✓ include list has 6 path(s)
- .github
- .editorconfig
- .gitignore
- .pre-commit-config.yaml
- Makefile
- pytest.ini
✓ Validation passed: template.yml is valid
Output (failure):
[ERROR] Target directory is not a git repository: /path/to/project
or
[ERROR] Template file not found: /path/to/project/.rhiza/template.yml
[INFO] Run 'rhiza sync' or 'rhiza init' to create a default template.yml
Configuration
Rhiza uses a .rhiza/template.yml file to define template sources and what to include in your project.
Configuration File Format
The template.yml file uses YAML format with the following structure:
# Required: GitHub or GitLab repository containing templates (format: owner/repo)
template-repository: jebel-quant/rhiza
# Optional: Git hosting platform (default: github)
template-host: github
# Optional: Branch to use from template repository (default: main)
template-branch: main
# Required: List of paths to include from template repository
include:
- .github
- .editorconfig
- .gitignore
- .pre-commit-config.yaml
- Makefile
- pytest.ini
- ruff.toml
# Optional: List of paths to exclude (filters out from included paths)
exclude:
- .github/workflows/specific-workflow.yml
- .github/CODEOWNERS
Configuration Fields
template-repository (required)
- Type: String
- Format:
owner/repository - Description: GitHub or GitLab repository containing your configuration templates
- Example:
jebel-quant/rhiza,myorg/python-templates,mygroup/gitlab-templates
template-host (optional)
- Type: String
- Default:
github - Options:
github,gitlab - Description: Git hosting platform where the template repository is hosted
- Example:
github,gitlab
template-branch (optional)
- Type: String
- Default:
main - Description: Git branch to use when fetching templates
- Example:
main,develop,v2.0
include (required)
- Type: List of strings
- Description: Paths (files or directories) to copy from the template repository
- Notes:
- Paths are relative to the repository root
- Can include both files and directories
- Directories are recursively copied
- Must contain at least one path
Example:
include:
- .github # Entire directory
- .editorconfig # Single file
- src/config # Subdirectory
exclude (optional)
- Type: List of strings
- Description: Paths to exclude from the included set
- Notes:
- Useful for excluding specific files from broader directory includes
- Paths are relative to the repository root
Example:
exclude:
- .github/workflows/deploy.yml # Exclude specific workflow
- .github/CODEOWNERS # Exclude specific file
Complete Configuration Example
GitHub Example
template-repository: jebel-quant/rhiza
template-branch: main
include:
- .github
- .editorconfig
- .gitignore
- .pre-commit-config.yaml
- CODE_OF_CONDUCT.md
- CONTRIBUTING.md
- Makefile
- pytest.ini
- ruff.toml
exclude:
- .github/workflows/release.yml
- .github/CODEOWNERS
GitLab Example
template-repository: mygroup/python-templates
template-host: gitlab
template-branch: main
include:
- .gitlab-ci.yml
- .editorconfig
- .gitignore
- Makefile
- pytest.ini
exclude:
- .gitlab-ci.yml
Examples
Example 1: Setting up a new Python project
# Create a new project directory
mkdir my-python-project
cd my-python-project
# Initialize git
git init
# Initialize Rhiza
rhiza init
# Review the generated template.yml
cat .rhiza/template.yml
# Sync templates
rhiza sync
# Review the imported files
git status
# Commit the changes
git add .
git commit -m "chore: initialize project with rhiza templates"
Example 2: Updating existing project templates
# Navigate to your project
cd existing-project
# Validate current configuration
rhiza validate
# Update templates
rhiza sync
# Review changes
git diff
# Commit if satisfied
git add .
git commit -m "chore: update rhiza templates"
Example 3: Using a custom template repository
Edit .rhiza/template.yml:
template-repository: myorg/my-templates
template-branch: production
include:
- .github/workflows
- pyproject.toml
- Makefile
- docker-compose.yml
exclude:
- .github/workflows/experimental.yml
Then sync:
rhiza sync
Example 4: Using a GitLab template repository
Edit .rhiza/template.yml:
template-repository: mygroup/python-templates
template-host: gitlab
template-branch: main
include:
- .gitlab-ci.yml
- .editorconfig
- .gitignore
- Makefile
- pytest.ini
Then sync:
rhiza sync
Example 5: Validating before CI/CD
Add to your CI pipeline:
# .github/workflows/validate-rhiza.yml
name: Validate Rhiza Configuration
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install rhiza
run: pip install rhiza
- name: Validate configuration
run: rhiza validate
Development
Prerequisites
- Python 3.11 or higher
uvpackage manager (recommended) orpip- Git
Setup Development Environment
# Clone the repository
git clone https://github.com/jebel-quant/rhiza-cli.git
cd rhiza-cli
# Install dependencies
make install
# Run tests
make test
# Run linters and formatters
make fmt
# Generate documentation
make docs
Running Tests
# Run all tests with coverage
make test
# Run specific test file
pytest tests/test_cli.py
# Run with verbose output
pytest -v
Code Quality
The project uses:
- Ruff for linting and formatting
- pytest for testing
- pre-commit hooks for automated checks
# Run all quality checks
make fmt
# Run dependency checks
make deptry
Building Documentation
# Generate API documentation
make docs
# Build complete documentation book
make book
Makefile Targets
The project includes a comprehensive Makefile for common development tasks:
Bootstrap
install-uv ensure uv/uvx is installed
install-extras run custom build script (if exists)
install install
clean clean
Development and Testing
test run all tests
marimo fire up Marimo server
marimushka export Marimo notebooks to HTML
deptry run deptry if pyproject.toml exists
Documentation
docs create documentation with pdoc
book compile the companion book
fmt check the pre-commit hooks and the linting
all Run everything
Releasing and Versioning
bump bump version
release create tag and push to remote with prompts
post-release perform post-release tasks
Meta
sync sync with template repository as defined in .rhiza/template.yml
help Display this help message
customisations list available customisation scripts
update-readme update README.md with current Makefile help output
Run make help to see this list in your terminal.
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
Reporting Issues
If you find a bug or have a feature request, please open an issue on GitHub.
Code of Conduct
This project follows a Code of Conduct. By participating, you are expected to uphold this code.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Links
- PyPI: https://pypi.org/project/rhiza/
- Repository: https://github.com/jebel-quant/rhiza-cli
- Issues: https://github.com/jebel-quant/rhiza-cli/issues
- Documentation: Generated with
make docs - Companion Book: https://jebel-quant.github.io/rhiza-cli/ (includes coverage report, API docs, and notebooks)
Architecture
Rhiza follows a modular architecture:
src/rhiza/
├── __init__.py # Package initialization
├── __main__.py # Entry point for python -m rhiza
├── cli.py # Typer app and CLI command definitions
├── models.py # Data models (RhizaTemplate)
└── commands/ # Command implementations
├── __init__.py
├── init.py # Initialize template.yml
├── materialize.py # Shared helpers (used by sync.py)
├── sync.py # Sync templates (primary command)
└── validate.py # Validate configuration
Design Principles
- Thin CLI Layer: Commands in
cli.pyare thin wrappers that delegate to implementations incommands/ - Separation of Concerns: Each command has its own module with focused functionality
- Type Safety: Uses
pathlib.Pathfor file operations and Typer for type-checked CLI arguments - Clear Logging: Uses
logurufor structured, colored logging output - Validation First: Always validates configuration before performing operations
Troubleshooting
Command not found: rhiza
Ensure the package is installed and your Python scripts directory is in your PATH:
pip install --user rhiza
# Add ~/.local/bin to PATH if needed
export PATH="$HOME/.local/bin:$PATH"
Template validation fails
Check that:
- Your
.rhiza/template.ymlfile exists - The YAML syntax is valid
- Required fields (
template-repositoryandinclude) are present - The repository format is
owner/repo
Run rhiza validate for detailed error messages.
Git clone fails during sync
Ensure:
- The template repository exists and is accessible
- The specified branch exists
- You have network connectivity to GitHub or GitLab
- The repository is public (or you have appropriate credentials configured — see the Authentication Guide)
- The
template-hostfield matches your repository's hosting platform (defaults to "github")
Files not being copied
Check:
- The paths in
includeare correct relative to the template repository root - The paths exist in the specified branch
- Any
excludepatterns are not filtering out wanted files
FAQ
Q: Can I use Rhiza with private template repositories?
A: Yes. Rhiza fetches templates by running git clone, so any credentials that allow Git to access the repository will work. See the Authentication Guide for step-by-step instructions on configuring GitHub Personal Access Tokens (PATs), SSH keys, and GitLab tokens — for both local development and CI/CD environments.
Q: Does Rhiza support template repositories hosted outside GitHub?
A: Yes! Rhiza supports both GitHub and GitLab repositories. Use the template-host field in your .rhiza/template.yml to specify "github" (default) or "gitlab".
Q: How do I use a GitLab repository as a template source?
A: Add template-host: gitlab to your .rhiza/template.yml file. For example:
template-repository: mygroup/myproject
template-host: gitlab
include:
- .gitlab-ci.yml
- Makefile
Q: Can I sync templates from multiple repositories?
A: Not directly. However, you can run rhiza sync multiple times with different configurations, or combine templates manually.
Q: What's the difference between rhiza init and rhiza sync?
A: init creates or validates the .rhiza/template.yml configuration file. sync reads that configuration and actually copies the template files into your project (and performs 3-way merges on subsequent runs).
Q: How do I update my project's templates?
A: Run rhiza sync — it applies a 3-way merge so your local changes are preserved.
Q: How do I update rhiza-cli itself?
A: The update method depends on how you installed rhiza:
- Using pip: Run
pip install --upgrade rhiza - Using uvx: No action needed!
uvxautomatically uses the latest version each time you run it. Just run your command:uvx rhiza <command> - From source: Run
git pullin the repository directory and thenpip install -e .again
Q: Can I customize which files are included?
A: Yes, edit the include and exclude lists in .rhiza/template.yml to control exactly which files are copied.
Acknowledgments
Rhiza is developed and maintained by the Jebel Quant team as part of their effort to standardize Python project configurations across their portfolio.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rhiza-0.13.4.tar.gz.
File metadata
- Download URL: rhiza-0.13.4.tar.gz
- Upload date:
- Size: 300.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0b282337ee82bb7498086058f3f61a1ee1843e71535e44320ab5b9264ad12ef
|
|
| MD5 |
17fac5f5fffe00b93e3974fb39714daf
|
|
| BLAKE2b-256 |
cca34f423f290a14e4820131a7d21632e3d562e849c645bd10f1587ba584e84d
|
Provenance
The following attestation bundles were made for rhiza-0.13.4.tar.gz:
Publisher:
rhiza_release.yml on Jebel-Quant/rhiza-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rhiza-0.13.4.tar.gz -
Subject digest:
e0b282337ee82bb7498086058f3f61a1ee1843e71535e44320ab5b9264ad12ef - Sigstore transparency entry: 1213483748
- Sigstore integration time:
-
Permalink:
Jebel-Quant/rhiza-cli@ef5b10124d896f6f09c7c7791e0b317f354e6e40 -
Branch / Tag:
refs/tags/v0.13.4 - Owner: https://github.com/Jebel-Quant
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
rhiza_release.yml@ef5b10124d896f6f09c7c7791e0b317f354e6e40 -
Trigger Event:
push
-
Statement type:
File details
Details for the file rhiza-0.13.4-py3-none-any.whl.
File metadata
- Download URL: rhiza-0.13.4-py3-none-any.whl
- Upload date:
- Size: 61.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
64748010c27b77c5e1345a79cc75b7a33b0063543b2f5fcde5baf1d521255770
|
|
| MD5 |
b7e4c60badce7ff7ac303a670cc1538c
|
|
| BLAKE2b-256 |
1a707422ba684f5b83db09322f585e7a1b8c40ae103f5b011e8e307a27737eac
|
Provenance
The following attestation bundles were made for rhiza-0.13.4-py3-none-any.whl:
Publisher:
rhiza_release.yml on Jebel-Quant/rhiza-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rhiza-0.13.4-py3-none-any.whl -
Subject digest:
64748010c27b77c5e1345a79cc75b7a33b0063543b2f5fcde5baf1d521255770 - Sigstore transparency entry: 1213483781
- Sigstore integration time:
-
Permalink:
Jebel-Quant/rhiza-cli@ef5b10124d896f6f09c7c7791e0b317f354e6e40 -
Branch / Tag:
refs/tags/v0.13.4 - Owner: https://github.com/Jebel-Quant
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
rhiza_release.yml@ef5b10124d896f6f09c7c7791e0b317f354e6e40 -
Trigger Event:
push
-
Statement type: