src/documate/cli.py
Module

cli.py

cli.py — one command. Bare documate does the whole job; flags pick a mode.

src/documate/cli.py8 documented symbols

Overview

cli.py — one command. Bare documate does the whole job; flags pick a mode.

  documate            index → write/refresh the docs → gate the result
  documate --check    gate only, writes nothing: generated docs fresh, anchors
                      real, no authored page lying about changed code (CI/hooks)
  documate --watch    keep running: regenerate whenever a tracked file changes
  documate --ai       the opt-in model layer: draft every missing docstring and
                      repair drifted pages via the claude CLI, then re-verify
                      through the gate (default model haiku; `--ai sonnet` upgrades)
  documate --stats    the dashboard: coverage bars, doc lines +/−, and the
                      all-time --ai bill (ledgers live next to the graph)
  documate --init     scaffold a documate.config.json (defaults, ready to edit),
                      then run the normal job — first-time setup in one command

Everything else is an override: documate PATH (or --root) points the same binary at any repo or monorepo sub-tree, --base picks the drift ref, --full re-indexes from scratch, --html adds the static site, --briefs emits work orders whenever the gate runs. --only/--dry-run/--budget aim, preview, and cap an --ai run; --undo reverts the last one from its recorded manifest; --rewrap-docs reflows over-long doc comments to doc_width with no model at all; --list-undocumented prints the missing-docs map as JSON. One Context per invocation, no import-time globals. --watch --ai is refused: a model call on every save is a token faucet — run --ai as a deliberate one-shot.

depends on src/documate/briefs.py, src/documate/check.py, src/documate/config.py, src/documate/core.py, src/documate/docs.py, src/documate/prose.py, src/documate/rewrap.py, src/documate/site.py, src/documate/stats.py, src/documate/ui.py, src/documate/undo.py

API

F_index(ctx: Context, full: bool) -> None

src/documate/cli.py:43

Refresh the graph before anything reads it. Default is incremental-when-a- graph-exists: re-parse only what changed since the last build (fast on big repos, the whole point). --full forces a from-scratch rebuild; a first index (no db yet) is always full regardless. index() decides the safe path. A spinner covers the wait (this is the one silent-slow step), then one line says what it did.

called by _dispatch, _watch

F_snapshot(ctx: Context) -> dict[str, float]

src/documate/cli.py:60

{tracked file: mtime} — everything that can change the generated docs.

Tracked files only (git ls-files), matching what the indexer sees, minus the docs and site trees: regeneration writes there, so watching them would retrigger forever. A vanished file drops out of the dict, which is itself a change.

called by _watch

F_watch(ctx: Context, html: bool) -> int

src/documate/cli.py:86

documate --watch — poll for source changes, regenerate on each one.

A dumb 1s mtime poll, no watcher dependency: an idle cycle is one git ls-files + stats, and a regeneration is incremental, so the loop stays sub-second even on large repos. A brand-new file starts triggering once it's git-tracked (git add) — untracked files are invisible to the poll and the indexer alike. Ctrl-C stops.

Each cycle prints which source files triggered it, then a colored unified diff of every doc page that changed in response — the live terminal view of the docs.

called by _dispatch  ·  calls _index, _snapshot

F_repo_here() -> bool

src/documate/cli.py:121

Is the cwd inside a git work tree? Decides whether a bare documate can act (there's a repo to document) or should explain itself (the help screen).

called by main

Fbuild_parser() -> argparse.ArgumentParser

src/documate/cli.py:130

Build the one flat parser: no subcommands, so documate -h is the whole surface on one screen (rendered through rich-argparse, the one cosmetic dependency). The three modes come first, overrides after.

called by main

F_scaffold(ctx: Context) -> None

src/documate/cli.py:276

--init: write the starter config, then teach the ignore defaults so the user knows what's already skipped before they add to it. Never clobbers an existing config — that path just says the file is already there. Behaviourally a no-op on this run (the scaffold is defaults only), so the docs + gate that follow see exactly what they would have without it.

called by _dispatch

F_dispatch(args) -> int

src/documate/cli.py:293

Route one parsed invocation: index first (every mode reads the graph), then the mode — gate only (--check), the model layer (--ai), or the default job: docs, site if asked, then either the watch loop or the gate. --watch skips the gate on purpose: it's a dev loop, and gating every save would be noise.

called by main  ·  calls _index, _scaffold, _watch

Fmain(argv=None) -> int

src/documate/cli.py:371

Console entry point: parse argv, dispatch, return the exit code.

Bare documate inside a repo does the whole job; outside any repo (nothing to act on) it lands on the help screen instead of an error. -h/--help and argparse errors are converted from SystemExit to plain return codes so embedders (and the tests) get a value, not an exit.

calls _dispatch, _repo_here, build_parser