Library API
Saga is primarily a CLI, but the pipeline it drives — diff → generate → render, plus the in-HTML comment store — is importable as a library. The names re-exported from the top-level saga package (and listed in its __all__) are the supported, semver-stable surface. Everything else under saga.* is an internal detail that may change without notice; import only from saga itself.
import saga
diff = saga.compute_diff(repo_root, base="main", ref="my-branch")
saga_obj = saga.generate(diff, base="main", head="my-branch",
commit_sha=diff.head_sha, model="claude-cli")
html = saga.render(saga_obj, diff)
Diff
compute_diff(repo_root, base, ref) -> DiffResult— diff two refs purely from git (base...ref, no checkout).pr_diff(pr) -> PRDiff— fetch the same shape from a GitHub PR via theghCLI.DiffResult— the computed change set consumed bygenerate/render.
Generate
generate(diff, *, base, head, commit_sha, model, intent=None) -> Saga— one structured LLM call that partitions the diff into chapters.modelis aprovider/modelstring (e.g.anthropic/claude-...,local/..., orclaude-clito shell out to the logged-in Claude Code CLI).intentis optional markdown describing the change’s purpose for plan-aware narration. RaisesSagaErroron an empty diff, a provider error, or a coverage gap.
Render
render(saga, diff, file_links=None) -> str— build the single self-contained HTML page (diff2html + syntax highlighting +window.__sagaData- an empty comments block with a minted
sagaId).
- an empty comments block with a minted
build_payload(saga, diff, file_links=None) -> dict— the JSON payloadrenderinlines, exposed for callers that assemble their own page.
Model
The pure, stdlib-only core.
Saga,Chapter,Hunk— the persisted dataclasses.parse_hunks(diff_text) -> list[Hunk]— split a unified diff into stable-id (h0, h1, …) hunks.reconstruct_diff(hunks) -> str— rebuild a valid unified diff for any subset of hunks (same anchors as the full view).validate_coverage(chapters, hunks) -> None— enforce the hard invariant that every hunk belongs to at least one chapter; raisesSagaErroron a gap.SagaError— the exception raised for anything user-facing across the pipeline.
Comments
Review comments live as a JSON envelope spliced between sentinel comments inside the saga HTML.
comments_block— the module that reads/rewrites that block. Notable members:read_envelope(path),write_envelope(path, envelope)(atomic sentinel splice),validate_envelope(data),empty_envelope(saga_id),render_block(envelope),read_saga_meta(path), and the constantsSCHEMA,START,END.agent_view(envelope, meta=None) -> dict— the tombstone-filtered, normalized view of a comment envelope ({branch, base, overall, file, inline}) suitable for handing to a coding agent.