Overview
pyrig is built around three interconnected systems that enable powerful extensibility and automation:Config System
Declarative file management with automatic discovery and merging
CLI System
Automatic command registration across package dependencies
Inheritance System
Multi-package inheritance with automatic discovery (
.I and .L patterns)Config File System
The ConfigFile Architecture
Every generated file in pyrig is backed by aConfigFile subclass. This provides:
- Automatic discovery: All ConfigFile subclasses are found across dependent packages
- Subset validation: User files only need required keys, not all keys
- Intelligent merging: pyrig adds missing keys while preserving user additions
- Priority-based validation: Files validate in order (e.g., pyproject.toml before dependent configs)
- Parallel execution: File validation runs concurrently for performance
How ConfigFile Works
Here’s the complete lifecycle:Run validation
When
pyrig mkroot runs, for each ConfigFile:- Load existing file (if it exists)
- Merge configurations:
user_config | expected_config - Validate subset: Ensure
expected_config ⊆ merged_config - Write back: Save merged config (user additions preserved)
ConfigFile Hierarchy
The system has four layers:- Core Layer
- Type-Specific Layer
- Format-Specific Layer
- Specialized Layer
ConfigFile (
base.py)Abstract base defining the config lifecycle:Subset Validation
The key innovation is subset validation rather than exact matching:- User additions: Extra keys beyond expected config
- Required structure: Expected keys must exist with correct values
- Validation: Final file must contain all expected configuration
Example: pyproject.toml
pyrig/rig/configs/pyproject.py
pyrig mkroot:
- Loads existing
pyproject.toml - Merges with expected structure
- Preserves your custom dependencies, scripts, etc.
- Ensures required fields exist
- Writes back merged result
CLI System
Automatic Command Discovery
The CLI system automatically discovers and registers commands from three sources:Main entry point
main() from <package>.mainmy_project/main.py
Project-specific commands
Functions from
<package>.rig.cli.subcommandsmy_project/rig/cli/subcommands.py
CLI Registration Flow
Here’s how the CLI discovers and registers commands:pyrig/rig/cli/cli.py (simplified)
Logging Configuration
The CLI includes flexible verbosity control:- Default
- Quiet (-q)
- Verbose (-v)
- Very Verbose (-vv)
- Maximum (-vvv)
Multi-Package Inheritance System
The .I and .L Patterns
The most powerful feature of pyrig is automatic discovery of implementations across package boundaries.
DependencySubclass Base
All extensible classes inherit fromDependencySubclass:
pyrig/src/subclass.py
How It Works
Discovery Process
The discovery searches:- Base dependency (typically
pyrig) - All dependent packages in the dependency chain
- Scoped to definition package (e.g.,
rig.tools) - Returns leaf (most specific implementation)
Practical Example: Tool Wrappers
pyrig/rig/tools/base/base.py
Creating Organization Standards
The real power emerges when creating organization-wide standards:company-pyrig/rig/tools/linter.py
company-pyrig automatically uses company rules:
any-project/pyproject.toml
Benefits of This Architecture
Declarative
Define what should exist, not how to create it. pyrig handles the implementation.
Idempotent
Safe to run repeatedly. Changes are preserved, missing structure is added.
Extensible
Override any behavior by subclassing. Changes propagate automatically.
Discoverable
All implementations found automatically. No manual registration needed.
Composable
Build on existing standards. Company package extends pyrig, project extends company package.
Type-Safe
Full type checking support. IDE autocomplete works throughout.
Design Principles
1. Separation of Concerns
- ConfigFile: Declares what files should exist
- Tool: Constructs command arguments
- Builder: Creates build artifacts
- CLI: Routes commands to implementations
2. Discovery Over Registration
No manual registration required. Define a subclass and it’s automatically discovered:3. Priority-Based Ordering
Configs validate in priority order (high to low):4. Caching and Performance
- ConfigFile.configs(): Cached (validated once)
- ConfigFile.load(): Cached (file read once)
- DependencySubclass.L: Cached (discovery runs once)
- Parallel validation: All ConfigFiles validated concurrently
Next Steps
Config Reference
Detailed documentation on creating custom config files
Tool Reference
Learn about available tools and how to customize them
CLI Guide
Advanced CLI patterns and custom commands
Testing
Understanding autouse fixtures and test infrastructure