Skip to content

History — API

The facade of the domain package goga.history — the single owner of the .goga/history/ tree. The git branch reader lives in the nested leaf cell goga.history.git, the status scale in goga.history.statuses; both are re-exported on this facade.

The signatures below are the CODEMANIFEST contract of the cell.

Identity and addressing

normalize_topic_slug(name: str) -> str
current_year() -> str

The slug grammar — lowercase, non-ASCII dropped, anything outside [a-z0-9] as -, repeat hyphens collapsed, edges trimmed (Feature/Foo_Barfeature-foo-bar) — and the current year as four digits.

resolve_history_root() -> Path
resolve_topic_dir(topic: str, year: str | None = None) -> Path
resolve_topic_file(topic: str, filename: str, year: str | None = None) -> Path
topic_exists(topic: str, year: str | None = None) -> bool
ensure_topic_dir(name: str, year: str | None = None) -> Path
remove_topic_dir(name: str, year: str | None = None) -> bool

Topic addressing: the tree root, the topic directory, and an artifact file path (the filename taken verbatim, extension required). ensure_topic_dir creates the directory idempotently (parents as needed); remove_topic_dir removes it idempotently (True — removed).

Statuses

resolve_topic_status(topic_dir: Path, scale: StatusScale) -> list[str]
collect_topic_statuses(year: str | None = None, scale: StatusScale | None = None) -> list[TopicRecord]
TopicRecord(topic: str, statuses: list[str])

The maximal present statuses of one topic and of one year's every topic — computed against the assembled scale, in scale order.

assemble_status_scale() -> StatusScale
StatusScale(stages: list[Stage])
Stage(name: str, filepath: str, before: str | None = None, after: str | None = None)
StatusRegistry(builtin_stages: list[Stage], tool_prefix: str)

The scale assembly — the built-in artifact axis plus the registrations of installed tool packages (see Hooks). assemble_status_scale is the single entry point; a broken goga_tool_* import raises ImportError, an invalid registration surfaces as ValueError.

Tree traversal and cleanup

collect_history_tree(year: str | None = None) -> list[HistoryYear]
HistoryYear(year: str, topics: list[str])
prune_topics(year: str | None = None, dry_run: bool = False) -> list[str]

collect_history_tree walks the tree (one year with year, every year with None). prune_topics deletes the orphan topics of the scoped year — the topics no branch of the repository inventory hosts — returning the removed slugs (dry_run=True lists without deleting).

Git embedding

resolve_current_branch_name() -> str | None
list_branch_refs() -> list[BranchRef]
BranchRef(name: str, ...)

The read-only branch surface: the current branch name (None-modes surface as ValueError reasons at the CLI layer) and the branch inventory used by the board, switching, and prune protection.

Example

from goga.history import collect_topic_statuses, resolve_topic_file

for record in collect_topic_statuses("2026"):
    print(record.topic, record.statuses)

plan = resolve_topic_file("feat-x", "plan.md")  # .goga/history/2026/feat-x/plan.md