-
Notifications
You must be signed in to change notification settings - Fork 0
Description
project_lib — multi-layer config resolution and template rendering
Problem
Several ghtraf commands need to resolve project configuration from multiple sources with a defined precedence order:
CLI flags > .ghtraf.json (per-project) > ~/.ghtraf/config.json (global)
Currently, config.py handles some of this, but the logic is ad-hoc and will be duplicated across commands:
ghtraf statusneeds to know which repos are tracked (from config)ghtraf listneeds to enumerate all configured repos across global + local configsghtraf verifyneeds config to know expected gist IDsghtraf initneeds template paths from configghtraf createneeds defaults for gist descriptions, org names, etc.
Without a shared config resolution library, each command will re-implement the same "read .ghtraf.json, fall back to global, merge with CLI flags" logic — creating the same kind of divergence risk that plan-execute was designed to prevent.
Proposed solution
A project_lib library in src/ghtraf/lib/project_lib/ that provides:
@dataclass
class ProjectConfig:
"""Resolved configuration for a single tracked project."""
repo: str # "owner/repo"
badge_gist_id: str | None
archive_gist_id: str | None
dashboard_path: str | None
template_source: str # "bundled" | path to custom templates
# ... other per-project settings
@dataclass
class GlobalConfig:
"""User-wide ghtraf settings."""
default_org: str | None
github_token_source: str # "env" | "gh-cli" | "keyring"
tracked_repos: list[str]
# ... other global settings
def resolve_config(
cli_args: dict,
project_path: Path | None = None,
global_path: Path | None = None,
) -> ProjectConfig:
"""Three-layer merge: CLI > project > global."""
...
def discover_projects(
global_config: GlobalConfig,
) -> list[ProjectConfig]:
"""Enumerate all tracked repos for status/list commands."""
...Design considerations
- DazzleLib candidate: The three-layer config pattern (CLI > local > global) is universal across CLI tools. project_lib should be designed for extraction.
- Not blocking the immediate plan: Plan-Execute Phase 1: retrofit ghtraf create with plan-execute pattern #55 and Plan-Execute Phase 2: retrofit ghtraf init with plan-execute pattern #56 can proceed without project_lib by using the existing ad-hoc config in
config.py. But ghtraf status and ghtraf list — multi-repo visibility from config #37 (status/list) will be significantly cleaner with this library. - Template rendering:
ghtraf initcopies templates with variable substitution ({{REPO_NAME}},{{BADGE_GIST_ID}}). This rendering logic could live in project_lib or in a separate template module. - PEV integration: Config resolution happens in the scan stage of the PEV lifecycle — it feeds into plan building. project_lib provides the "what are we working with?" context that plan functions consume.
Acceptance criteria
-
src/ghtraf/lib/project_lib/exists with config resolution - Three-layer merge: CLI flags >
.ghtraf.json>~/.ghtraf/config.json -
discover_projects()enumerates tracked repos from global config - Unit tests for merge precedence (CLI wins over project wins over global)
- At least one command (
statusorlist) uses project_lib for config resolution - Config dataclasses are serializable (JSON round-trip for future
ghtraf configcommand)
Related issues
- Refs ghtraf status and ghtraf list — multi-repo visibility from config #37 — ghtraf status/list (primary consumer of project discovery)
- Refs ghtraf verify — state.json validation and consistency checks #38 — ghtraf verify (needs config to know expected gist IDs)
- Refs Plan-Execute architecture — trustworthy --dry-run across all subcommands #53 — Plan-Execute epic (config resolution feeds the scan stage)
- Refs Installer pattern extraction — plan-execute as DazzleLib candidate #61 — DazzleLib extraction (project_lib is a future extraction candidate)
Analysis
See 2026-03-02__21-48-45__dev-workflow-process_missing-issues-and-plan-gaps.md for gap analysis (Gap 5).
See 2026-02-27__16-02-55__dev-workflow-process_cli-architecture-ordering-and-init-command.md for the three-layer config design origin.