Docs and Commit Messages With AI That Are Still Useful in Six Months
AI is great at describing what code does and terrible at explaining why. Here's how to get documentation and commits that answer the question that matters.
The default AI commit message is a paraphrase of the diff. git diff already tells you the code changed from A to B; a message that says “changed A to B” adds nothing you couldn't read yourself. The same disease afflicts AI docstrings: Returns the user by ID above a function called get_user_by_id. Technically accurate, completely redundant, and it rots the moment the behavior drifts because nobody updates a comment that was never worth reading.
Documentation and commit history exist to answer one question the code cannot: why. AI can help with this, but only if you stop it from restating the what.
Commit messages: the diff is the input, not the output
A generated commit message improves dramatically when you feed the model the reasoning and forbid it from summarizing the diff. The subject line describes the change; the body must justify it.
Write a commit message for this staged diff. Rules:
- subject: imperative, under 60 chars, says WHAT changed
- body: explain WHY this change, not what the diff shows.
I can read the diff. Tell me the reason, the alternative
I rejected, and any consequence for callers.
- if you cannot infer the WHY from the diff, ask me instead
of guessing.That last rule matters more than it looks. The why is usually not in the diff — it's in your head. A good AarrCLI workflow prompts you for it rather than fabricating a plausible-sounding rationale. Compare the two outputs:
Bad (paraphrase of diff):
Add retry logic to fetchConfig
Adds a loop that retries fetchConfig 3 times with backoff.
Good (reasoning):
Add bounded retry to fetchConfig
The config service returns 503 during its own deploys, which
took down every pod that happened to boot in that window.
Retry 3x with jitter so a rolling config deploy no longer
cascades. Chose retry over a longer startup timeout because
the timeout would delay healthy boots too. Callers still see
a hard failure after 3 attempts; startup fails closed.Six months later, when someone wonders why fetchConfig retries exactly three times, the second message answers them. The first sends them to a git blame archaeology dig that ends in a Slack thread that no longer exists.
Let the model draft, you supply the why
The efficient division of labor: the model handles structure, tense, and the mechanical summary of scope; you inject the one or two sentences of intent it can't know. In practice I stage my changes, run an AI commit helper, and treat its first draft as a fill-in-the-blank form. It gets the subject line and the scope right; I overwrite its guessed rationale with the real one. This is faster than writing from scratch and produces better history than either the model or a rushed human alone.
One caution for squashed or multi-concern commits: models will average across unrelated changes into a vague summary. If the diff does three things, the message will say “various improvements.” The fix is upstream — make atomic commits — but you can also ask the model to refuse: “if this diff contains unrelated changes, list them and tell me to split the commit instead of writing one message.”
Docstrings: document the contract and the surprises
A useful docstring covers what the signature can't express: the invariants, the failure modes, the units, the surprising edge behavior. The redundant parts — parameter names, obvious return types — are exactly what AI defaults to and exactly what you should strip.
Write a docstring for this function. Do NOT restate the
parameter names or types; the signature already shows those.
Document only what a caller cannot infer:
- preconditions and what happens if violated
- units and ranges
- side effects
- which exceptions it raises and when
- any non-obvious edge case
If the function has none of these, write a one-line summary
and stop. Do not pad.“Do not pad” is load-bearing. Left alone, models generate a full Args:/Returns: block for a two-line pure function because the format template demands it. A one-line docstring on a trivial function is correct engineering; a six-line one is decoration that will drift out of sync.
The drift problem, and using AI to fight it
Every doc lies eventually because code changes and prose doesn't. AI can invert this failure into a strength: point it at the diff and ask what documentation the change invalidated.
Here is the diff. Which existing docstrings, README sections,
or code comments does this change make wrong or misleading?
Search the repo. List file and line, quote the now-false
statement, and propose the correction. Don't touch anything
else.Run this in Claude Code or Cursor's agent mode and it will actually grep for references to the changed function and flag the README example that still shows the old signature. This is the single most valuable doc task to hand an AI, because staleness detection is tedious, mechanical, and the thing humans reliably skip. It's the inverse of writing docs: instead of generating prose nobody asked for, it finds the prose that's now actively lying.
Where AI docs go wrong
Two failure modes to watch. First, confident fabrication in conceptual docs. Ask for an architecture overview and the model will state that the cache invalidates on write when it actually invalidates on a TTL, because that's the more common pattern and it pattern-matched. Anything describing system behavior at a level above the code it can read must be verified against reality, not vibes. Second, the tutorial that never runs. Generated README quickstarts routinely contain a command that was plausible in 2023 but wrong for your current CLI. Every command in generated docs gets executed once before it ships, no exceptions.
The rule that keeps it useful
Whether it's a commit body, a docstring, or a design note, apply one filter: does this say something the reader couldn't get from the code in front of them? If yes, keep it and verify it. If no, delete it — a redundant doc isn't neutral, it's a maintenance liability that will contradict the code the first time either one changes. AI is a fast, tireless drafter of the mechanical parts and a genuinely good detector of stale docs. It is not a source of the why. That still comes from you, and the whole value of the artifact depends on you putting it there.
A note on shelf life. AI products change fast. This guide deliberately focuses on the parts that stay true — how to judge a tool, what the trade-offs are — rather than ranking products that will have changed by the time you read it. Prices and feature claims should always be checked against the provider before you rely on them.