βββββββ βββββββ ββββββββββββββββββββββ ββββββ βββββββββ ββββββββββ βββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ βββ
βββ ββββββ ββββββ ββββββββββββββββββββββββ βββ βββ ββββββββ
βββ ββββββ ββββββ βββββββββββββββ ββββββββ βββ βββ ββββββββ
ββββββββββββββββββββββββββββββββββββ βββ βββ βββ βββββββββββ βββ
βββββββ βββββββ ββββββββββββββββββ βββ βββ βββ ββββββββββ βββ
AI-powered documentation for Python projects. docspatch writes Google-style docstrings and directory-scoped README.md files, then edits them into your source without disturbing the surrounding code.
By grimmy_dev Β· Report an issue Β· Repository
Most doc generators re-process a file the moment a byte changes β a reformat, a renamed local, a stray comment β and pay the model for work that changed nothing. docspatch works against the meaning of your code, not its text:
- Each file is reduced to a structural hash that ignores blank lines, comments, and existing docstrings. A reformatted file is never re-sent to the model β only code whose logic actually changed is processed.
- Docstrings are inserted through
libcst, so your formatting, imports, and indentation are preserved exactly. Nothing else in the file moves. - Every generated item is reviewed before it is written β accept, reject, edit, or regenerate.
- Docstrings β Google-style docstrings for undocumented functions, methods, classes, and modules, inserted in place.
- READMEs β draft or refresh a
README.mdscoped to any directory, reviewed as a side-by-side diff before anything is written. - Semantic change tracking β a content-hash manifest skips files unchanged since the last run.
- Pre-commit ready β
dp checkreports stale docstrings and READMEs and exits non-zero, with no model calls and no configuration required. - Interactive review β accept, reject, edit, or rerun each generated item.
- Resumable β interrupted runs checkpoint to SQLite and continue with
--resume. - Three providers β Anthropic, OpenAI, and Google Gemini, each with
fast,balanced, andbestmodel tiers. - Cost-aware β every run reports token usage and the actual dollar cost.
- Python β₯ 3.14
- An API key for one provider: Anthropic, OpenAI, or Google Gemini
docspatch installs a single dp command.
Once published, install it as a standalone tool:
uv tool install docspatch # or: pipx install docspatchFrom source with uv:
git clone https://github.com/grimmy-dev/docspatch_v2.git
cd docspatch_v2
uv sync # create the environment and install dependencies
uv run dp --helpdp init # choose a provider, tier, and tone; store an API key
dp docs src/ # document everything undocumented under src/
dp readme # draft or refresh the root README
dp check # report stale docs/README; exit non-zero if any (no model calls)A typical first run:
dp init # one-time setup, writes .docspatch/config.toml
dp docs src/ --check # preview what needs docstrings and the estimated cost
dp docs src/ # generate and review themWalks you through provider, model tier, and tone, then writes configuration to the repo (.docspatch/config.toml) or your global path (~/.docspatch/). API keys are stored masked. It finishes by reporting whether your docs and README are already up to date.
Scans the given files or directories (the whole repo when omitted), generates docstrings for anything undocumented, and edits them into place after review.
| Flag | Description |
|---|---|
--check |
List undocumented functions and the estimated cost; write nothing. |
--update |
Regenerate every docstring in scope, including already-documented ones. |
--remarks TEXT |
Extra instruction added to every docstring prompt. |
--resume |
Continue the most recent interrupted run. |
--no-ignore |
Scan files normally excluded by .gitignore / .docsignore. |
dp docs src/ # document a subtree
dp docs src/ --check # preview only, exit non-zero if work remains
dp docs src/ --update --resume # full rewrite, resuming if interruptedCreates or updates a README.md for a directory. It compares the directory's source against the last run to decide whether the README is stale, maps the code with a fast analysis model, drafts the document, and shows a diff for approval.
| Flag | Description |
|---|---|
--update |
Re-draft from scratch instead of refreshing sections in place. |
--check |
Report whether the README is stale without calling the model. |
--remarks TEXT |
Extra layout or content instruction for the draft. |
dp readme # root README
dp readme src/docspatch/commands/ --check # is this package's README stale?Reports whether the root README.md or any docstrings are stale, then exits non-zero if so. It makes no model calls and needs no configuration, so it is safe to run on every commit or in CI.
dp check # exit 0 when everything is fresh, 1 when work remains$ dp check
README.md may be stale β 3 changed, 0 removed file(s). Run dp readme to refresh it.
5 function(s) across 2 file(s) need docstrings. Run dp docs to document them.
$ echo $?
1
Show the merged configuration, or set a key:
dp config # print resolved settings
dp config set provider anthropic
dp config set tone technical| Key | Purpose |
|---|---|
provider |
Active provider: anthropic, openai, or gemini. |
generator_model |
Model that drafts docstrings and README prose. |
analysis_model |
Fast, cheaper model that maps source files. |
tone |
Stylistic tone, e.g. professional or technical. |
batch_token_limit |
Maximum tokens per batched model request. |
concurrency_limit |
Maximum concurrent model requests. |
call_timeout |
Per-request timeout in seconds. |
Removes local cache files, run logs, and the SQLite checkpoint ledger.
Keep documentation from drifting by running dp check on every commit. It is fast, offline, and never calls a model. With the pre-commit framework, add a local hook:
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: docspatch-check
name: docspatch staleness check
entry: dp check
language: system
pass_filenames: false
always_run: trueThen enable it:
uv tool install pre-commit # or: pipx install pre-commit
pre-commit installA complete example, including Ruff, lives in .pre-commit-config.yaml at the repo root.
docspatch runs two LangGraph pipelines over a shared change manifest.
- Docs pipeline. Finds undocumented targets, packs them into token-bounded batches, and generates docstrings concurrently. Output is compiled to a concrete syntax tree with
libcstand inserted into the exact scope, so nothing else in the file moves. Anti-LLM-ese and transient-failure retries run automatically, and the model can be switched mid-run when a provider is exhausted. - README pipeline. Scopes a directory, resolves its structure and entry points into a context backbone, maps the code with a fast model, then weaves a draft with the generator model. The result is reviewed as a red/green diff before it is committed.
- Change manifest. Both pipelines key their state by pipeline name in one
ChangeManifest. Files are compared by a structural hash over a normalised syntax tree, with a size/mtime stamp as a fast-skip so unchanged files are not even re-hashed. - Checkpoints and ledger. Runs serialize to an async SQLite store, so
--resumepicks up outstanding work with its saved state and remarks. Token usage is recorded to a per-run ledger and reported as real cost at the end. - Run feedback. Every
docsandreadmerun shows one live elapsed timer that keeps ticking across steps while output scrolls above it, stepping aside only while an interactive prompt owns the terminal.
Settings resolve in layers: built-in defaults, then your global config (~/.docspatch/config.toml), then the repo config (.docspatch/config.toml). Later layers win. View or edit them with dp config.
To exclude files from documentation, add a .docsignore (same syntax as .gitignore) to your repo; .gitignore is honoured automatically.
uv sync # install runtime + dev dependencies
uv run pytest # unit, integration, and pipeline tests
uv run ruff check # lint
uv run mypy src # static type checkIssues and pull requests are welcome β see the issue tracker. Please run uv run pytest, uv run ruff check, and uv run mypy src before opening a PR.
MIT β see LICENSE.
Keep your docs as fresh as your code.