Development guidelines, architectural patterns, and best practices for trobz_local.
Five-layer modular design with clear separation of concerns:
| Layer | Module(s) | Responsibility |
|---|---|---|
| CLI Layer | main.py |
Command routing, user interaction, newcomer mode |
| Diagnostics | doctor.py |
Environment health checks, status enums, check result dataclasses |
| Implementation | installers.py, postgres.py |
Installation strategies (script, system, npm, uv); PostgreSQL user management |
| Utility Layer | utils.py |
Config validation, platform detection, helpers |
| Infrastructure | concurrency.py, exceptions.py |
Parallel execution, custom exceptions |
- Standard: PEP 8 compliance
- Formatter: ruff (fast, deterministic)
- Line Length: Max 120 characters (ruff.toml config)
- Import Order: stdlib → third-party → local (ruff-managed)
- Active Rules: YTT, S (security), B, A, C4, T10, SIM, I, C90, E, W, F, PGH, UP, RUF, TRY
- UI Library: Rich (progress bars, colored output, trees)
- All function signatures must have type hints
- Complex variables must be annotated
- Static analysis via mypy (ty wrapper)
- Pydantic for external data validation (config.toml)
| Element | Pattern | Example |
|---|---|---|
| Modules | snake_case | installers.py |
| Classes | PascalCase | ConfigModel |
| Functions | snake_case | pull_repos |
| Constants | SCREAMING_SNAKE_CASE | ARCH_PACKAGES |
| Private | _snake_case | _run_installers |
System state defined in TOML. Tool reconciles local environment with definition. Pydantic validates before any side effects.
installers.py: Multiple strategies per tool source (script, system packages, npm, uv) with OS-aware selection.
main.py: Each CLI command is discrete but shares context (newcomer mode, dry-run). Easy to add new commands.
GitProgress and run_tasks(): Real-time progress callbacks to Rich UI. Decoupled from execution logic.
doctor.py: Grouped health checks returning CheckResult objects with CheckStatus enum. Enables modular diagnostics that can be combined or reused independently.
Config validated at startup. Early detection prevents side effects on invalid input.
- Never use shell=True - Always pass arguments as list
- Full paths only - Use shutil.which() instead of relying on PATH
- No user input in commands - Build commands from validated config only
- SQL injection prevention - Use psql variable binding (
:\"identifier\"for names,:'string'for values) instead of string interpolation
- HTTPS enforcement - Pydantic validator rejects non-HTTPS URLs
- Trusted sources only - Script URLs must be whitelisted or reviewed
- Regex patterns - All config fields validated with specific patterns:
- Versions:
^(?:\d+\.\d+|master)$(supports semver and "master" branch) - UV tools:
^[a-zA-Z0-9][a-zA-Z0-9._\-\[\]@=<>!,]*$ - Repo names:
^[a-zA-Z0-9._-]+$ - PostgreSQL usernames:
^[a-zA-Z_][a-zA-Z0-9_]{0,62}$(max 63 chars, alphanumeric + underscore)
- Versions:
- Pydantic models - No ad-hoc parsing of config
- Ruff S rules* - Security linting enabled in make check
- No credentials stored in code
- No sensitive data logged
- Environment variables used for user-specific paths only
Use specialized exceptions from exceptions.py with context:
raise DownloadError(url=script_url, reason=str(e))
raise ExecutableNotFoundError(executable="wget")- Config errors: Print message + example, exit 1
- Task failures: Catch exception, record in TaskResult, continue
- Validation errors: Pydantic prints field-level details, exit 1
- Use context managers for temporary files
- Temporary directories auto-deleted on function exit
- No partial state on failure
- Tool: pytest
- Mocking: unittest.mock for filesystem, network, subprocesses
- Coverage: All new features must include tests
- No real I/O: Tests must not actually download, install, or git-clone
- Test file naming:
test_{module}.py - Test function naming:
test_{function}_case_description - Fixtures for common setup
- Parametrized tests for multiple scenarios
make test # Full suite
pytest -xvs file.py # Single file with verbose output
pytest --cov # Coverage reportuv sync # Install dependencies
uv run pre-commit install # Setup git hooks
make check # Verify setup (lint + type check)- Code follows naming conventions and style guidelines
- Type hints on all function signatures
- Tests written and passing (make test)
- Linting passes (make check)
- No security issues (ruff S rules)
- Error handling implemented
- Documentation updated
make check # Linters + type checkers
make test # Full test suiteFollow Conventional Commits:
feat: description- New featurefix: description- Bug fixdocs: description- Documentationrefactor: description- Code restructuringtest: description- Test additionschore: description- Maintenance
Target file size: 500 LOC; main.py at 592 LOC is exception due to command density (6 command implementations + orchestration).
main.py: CLI commands and orchestration (592 LOC - 6 commands: init, pull-repos, create-venvs, install-tools, ensure-db-user, doctor)doctor.py: Environment health checks (~200 LOC - CheckStatus enum, CheckResult dataclass, check_* functions, run_doctor orchestrator)installers.py: Installation strategies (391 LOC - 5 installation strategies: PostgreSQL repo, scripts, system packages, NPM, UV)postgres.py: PostgreSQL user management (173 LOC - user validation, creation, testing)utils.py: Config, platform detection, helpers (246 LOC - Pydantic models, OS detection, utilities)concurrency.py: Task runner with progress (60 LOC - ThreadPoolExecutor wrapper, TaskResult dataclass)exceptions.py: Custom exception classes (38 LOC - installer exceptions)tests/: pytest unit tests for all modules (1006 LOC total - 6 test files)
Imports in each module:
- No circular imports
- Public functions documented
- Private functions start with underscore
def function(param: Type) -> ReturnType:
"""Brief one-line description.
Longer description if needed.
Args:
param: Description
Returns:
Description of return value
Raises:
CustomError: When this happens
"""- Explain "why", not "what"
- Comment complex logic only
- Keep comments synchronized with code
- Update docs/ files when changing features
- Keep code examples in docs/ current
- Reference specific line numbers when helpful