Documentation

Docstring Writer

Write docstrings for the non-obvious parts -- preconditions, units, error behavior -- and skip functions whose names and types already say everything.

When to use this

  • A public function/class in a library has no docstring and its behavior isn't self-evident from its signature.
  • An existing docstring is wrong or stale relative to what the function now does.
  • Not for every function uniformly -- a well-named, obviously-typed helper doesn't need one; forcing docstrings everywhere produces noise that hides the ones that matter.

The skill file

Copy this verbatim. It's written in the SKILL.md format (YAML frontmatter + markdown instructions) that Claude Code, and increasingly other agent tools, read directly.

SKILL.md
---
name: docstring-writer
description: Write docstrings for functions/classes whose behavior isn't fully captured by their name and type signature -- covering preconditions, units, side effects, and error/exception behavior. Skip documenting what's already obvious from the signature.
---

# Docstring Writer

Skip anything a well-named, well-typed signature already communicates.
Spend the effort on what the signature *can't* say.

## What actually needs documenting

- **Units and ranges** a type can't express: is this timeout in ms or
  seconds? Is this a 0-1 fraction or a 0-100 percentage?
- **Preconditions** the caller must satisfy that aren't enforced by the
  type system: "the list must be sorted," "the file must already exist."
- **Side effects**: does this mutate an argument, write to disk, make a
  network call -- anything not obvious from the name.
- **Error/exception behavior**: what does this raise or return on
  failure, and under what conditions specifically.
- **Non-obvious algorithmic behavior**: complexity if it matters for how
  the function should be used, or a surprising edge case (empty input
  behavior, what happens at a boundary value).

## What NOT to write

- A restatement of the function name in sentence form (`get_user_by_id`:
  "Gets a user by ID." -- adds nothing).
- Parameter descriptions that just repeat the parameter's name and type
  with no added information.
- Docstrings on obviously-named private helpers with clear types and no
  surprising behavior.

## Format

Match the language/project's existing docstring convention (JSDoc,
Google-style Python docstrings, rustdoc, etc.) -- don't introduce a new
style.

Installing it elsewhere

The frontmatter/body split above is Claude Code's convention. Here's how to carry the same instructions into other tools:

Claude Code
.claude/skills/docstring-writer/SKILL.md

Save the file below verbatim (frontmatter included) at that path, project-local or in ~/.claude/skills/ for a user-level skill. Claude Code loads the name/description pair to decide when to pull it in, or you invoke it directly as /docstring-writer.

Cursor
.cursor/rules/docstring-writer.mdc

Convert the YAML frontmatter to Cursor's rule format (description, globs, alwaysApply: false) and keep the markdown body as the rule content. Cursor surfaces it by description match, same idea as Claude Code's auto-load.

Codex CLI / Copilot
AGENTS.md

Codex CLI (and increasingly other agentic CLIs) read AGENTS.md at the repo root as always-on instructions. Paste the markdown body under a heading like ## {title}; for GitHub Copilot's coding agent, the equivalent file is .github/copilot-instructions.md.

Windsurf
.windsurfrules

Append the markdown body to .windsurfrules at the repo root. Windsurf treats the whole file as always-on context, so keep only the instructions you want applied on every request.

Where this goes wrong
  • Writing a docstring on every function regardless of whether it adds information -- this trains readers to skip docstrings entirely.
  • Documenting units/behavior without actually reading the implementation to confirm them.
  • Using a docstring format inconsistent with the rest of the file/project.