Skip to content

Architecture

pyrig is organized into two layers:

src/pyrig/
├── core/          # Generic, reusable Python utilities
│   └── introspection/
└── rig/           # pyrig domain logic
    ├── cli/       # CLI commands
    ├── configs/   # Config file generators
    ├── tools/     # External tool wrappers
    ├── tests/     # Mirror test framework
    └── resources/ # Bundled static files

Extensibility — DependencySubclass

All major pyrig classes (ConfigFile, Tool, etc.) inherit from DependencySubclass, which is defined and documented in pyrig-runtime.

In short: any installed package that depends on pyrig can override any of its classes simply by subclassing them in the right place — no registration needed. Run pyrig mk subcls to generate a correctly placed subclass skeleton for any pyrig class.


Config Files — ConfigFile

ConfigFile is the abstraction for declarative, idempotent file management. A subclass declares what a file should contain; validate() enforces it:

file missing?      → create with required content
file incorrect?    → merge in missing content, preserve user additions
file correct?      → no-op

Format-specific bases handle serialization:

ConfigFile
 ├── DictConfigFile → TOMLConfigFile (pyproject.toml, prek.toml …)
 ├── YAMLConfigFile → YMLConfigFile → YMLDictConfigFile (GitHub Actions workflows)
 └── ListConfigFile → StringConfigFile → MarkdownConfigFile (README.md …)

Tools — Tool and Args

Every external tool (uv, git, pytest, ruff, …) is wrapped in a Tool subclass. Methods return Args — an immutable tuple[str, ...] that can execute itself:

PackageManager.I.install_dependencies_args().run()  # → uv sync

Because every tool interaction goes through a Tool subclass, any command or behaviour can be overridden downstream without touching pyrig itself.


Mirror Tests — MirrorTestConfigFile

MirrorTestConfigFile is a ConfigFile that treats test files as managed configuration. It inspects every source module and ensures a corresponding test stub exists for every function and method. validate() only appends missing stubs — existing test code is never touched.

Conformance is enforced by the pyrig sync pre-commit hook, which runs before every commit and fails if any test stubs are missing or out of date.


Usage Recommendation

The recommended way to use pyrig is to create your own personal package that extends it once with all the customizations you want, and then use that package as the base for all your projects:

uv init my-new-project --python 3.12
cd my-new-project
uv add my-pyrig-package --dev
uv run pyrig init

All your projects that depend on your package automatically inherit your customizations without any per-project configuration.