AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Docstring Check

skill-thijsvos-claude-skills-docstring-check · by thijsvos

Scans a codebase for missing, outdated, drifted, or inconsistent docstrings and applies behavior-preserving fixes matching the project's detected convention.

— No reviews yet
0 installs
41 views
0.0% view→install

Install

$ agentstack add skill-thijsvos-claude-skills-docstring-check

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ✓ Network access No
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ✓ Environment & secrets No
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-thijsvos-claude-skills-docstring-check)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Docstring Check? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Call EnterPlanMode immediately before doing anything else.

You are performing a comprehensive docstring audit and — after user approval — applying convention-matching fixes. Scan the target code for three classes of problem in parallel: missing docstrings on public API, signature-vs-docstring drift, and style/convention inconsistency. Synthesize a prioritized fix plan, apply changes incrementally, and verify with the project's existing linter or doc-build tool.

ARGUMENTS: The user may provide an optional target argument — a file path, directory, function/class name, branch name, commit range, or natural language description of what to audit. If no argument is provided, default to a full-codebase scan (asking the user to narrow the scope if the repo is large).

IMPORTANT: Always quote the user-supplied argument in double quotes when passing it to shell commands.


Step 1: Resolve Scope and Detect Project Context

Determine what code to audit based on the argument and project state.

If an argument was provided, resolve it in this order:

  1. File path — if the path exists on disk as a file, audit that file:

``bash test -f "" && echo "file" `` Read the file in full and identify all documentable symbols (functions, methods, classes, modules, exported constants).

  1. Directory path — if the path is a directory, find all source files in it:

``bash test -d "" && echo "directory" ` Find source files (exclude test files, node_modules, vendor, build artifacts, generated code): `bash find "" -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.py' -o -name '*.go' -o -name '*.rb' -o -name '*.rs' -o -name '*.java' -o -name '*.kt' -o -name '*.swift' -o -name '*.php' -o -name '*.cs' \) ! -path '*/node_modules/*' ! -path '*/vendor/*' ! -path '*/__pycache__/*' ! -path '*/dist/*' ! -path '*/build/*' ! -path '*/target/*' ! -path '*/.venv/*' ! -path '*/venv/*' ! -name '*.test.*' ! -name '*.spec.*' ! -name '*_test.*' ! -name 'test_*.py' | head -50 `` If the directory contains more than 30 source files, list a summary by language and ask the user to narrow the scope or confirm they want to proceed (up to 50 files maximum).

  1. Function, class, or method name — if the argument is not a valid path, search the codebase for it:

``bash grep -rn --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' --include='*.py' --include='*.go' --include='*.rb' --include='*.rs' --include='*.java' --include='*.kt' --include='*.swift' --include='*.php' --include='*.cs' -E "(function|def|func|class|fn|pub fn|export|interface|struct|enum|trait|impl)\s+" . 2>/dev/null | grep -v node_modules | grep -v vendor | head -10 `` If found in multiple files, list them and ask the user to confirm which one. Read the full file(s) containing the match.

  1. Git ref (branch or tag) — if git rev-parse --verify succeeds and it is not a file path, identify files changed on that ref compared to the default branch:

``bash default_branch=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@') [ -z "$default_branch" ] && git rev-parse --verify main >/dev/null 2>&1 && default_branch=main [ -z "$default_branch" ] && git rev-parse --verify master >/dev/null 2>&1 && default_branch=master ` `bash git diff "$default_branch"..."" --name-only --diff-filter=ACMR 2>/dev/null `` Read those files in full for docstring analysis.

  1. Commit range — if the argument contains .., use it directly:

``bash git diff "" --name-only --diff-filter=ACMR 2>/dev/null `` Read those files in full.

  1. Natural language description — if none of the above match, interpret the argument as a description of a code area (e.g., "the authentication module", "API handlers"). Extract keywords, search the codebase, present found files, and ask the user to confirm scope.
  1. If none of the above produce results, inform the user and stop:

> Could not resolve the argument as a file path, directory, code identifier, git ref, or code area description. Try: /docstring-check src/auth/handler.ts (file), /docstring-check src/utils/ (directory), /docstring-check handleLogin (function), /docstring-check feature-branch (branch), or /docstring-check (full-codebase scan).

If no argument was provided, default to a full-codebase scan. Enumerate source files:

find . -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.py' -o -name '*.go' -o -name '*.rb' -o -name '*.rs' -o -name '*.java' -o -name '*.kt' -o -name '*.swift' -o -name '*.php' -o -name '*.cs' \) ! -path './node_modules/*' ! -path './vendor/*' ! -path './__pycache__/*' ! -path './dist/*' ! -path './build/*' ! -path './target/*' ! -path './.venv/*' ! -path './venv/*' ! -path './.git/*' ! -name '*.test.*' ! -name '*.spec.*' ! -name '*_test.*' ! -name 'test_*.py'

Also exclude generated files (those starting with a DO NOT EDIT banner):

grep -l -m1 "DO NOT EDIT"  2>/dev/null

If the scan returns more than 50 files, summarize the breakdown by language (e.g., "127 Python files, 34 TypeScript files, 8 Go files") and use AskUserQuestion to ask the user how to narrow the scope. Offer these options:

  • Full scan — audit all source files (higher cost, complete coverage)
  • Hotspots — scope to the top 30 most-edited files in the last 12 months:

``bash git log --format=format: --name-only --since=12.months 2>/dev/null | grep -E '\.(ts|tsx|js|jsx|py|go|rb|rs|java|kt|swift|php|cs)$' | sort | uniq -c | sort -rn | head -30 | awk '{print $2}' ``

  • Changed files only — scope to files changed on the current branch vs the default branch (same default_branch detection as above)
  • Public API only — scope to only the top-level/exported files (language-dependent: __init__.py, index.ts, mod.rs, lib.rs, files without a leading underscore)

After resolving the scope, gather project context by reading these files if they exist:

  • CLAUDE.md — project conventions
  • pyproject.toml, package.json, Cargo.toml, go.mod, Gemfile, pom.xml, build.gradle, composer.json — language detection + dependency list
  • Docstring style configuration (authoritative — if present, use instead of inferring):
  • Python: [tool.pydocstyle] or [tool.ruff.lint.pydocstyle] in pyproject.toml, .pydocstyle, setup.cfg [pydocstyle] section
  • TS/JS: tsdoc.json (TSDoc), .eslintrc* / eslint.config.* with plugin:jsdoc
  • Ruby: .rubocop.yml Style/Documentation / Style/DocumentationMethod
  • Java: Checkstyle XML MissingJavadoc* rules
  • Doc-build infrastructure (used for verification in Step 4):
  • docs/conf.py (Sphinx), mkdocs.yml, typedoc.json, Doxyfile, Cargo.toml → cargo doc, godoc

Detect the in-use docstring style if not explicitly configured. Sample 15–20 existing non-trivial docstrings from the scoped files and classify:

  • Python: Args:/Returns: → Google; Parameters\n----------\n → NumPy; :param x:/:returns: → reST/Sphinx; otherwise PEP 257 plain
  • TS/JS: presence of @param {Type} in a TS file → JSDoc-in-TS (discouraged); absence of type tags on TS → TSDoc; typed @param {Type} on JS → JSDoc
  • Go: fixed — godoc expects // FuncName does … on exported identifiers
  • Rust: fixed — /// for item-level, //! for module-level, Markdown body
  • Java: fixed — /** … */ with @param, @return, @throws
  • C#: fixed — /// , `, , `
  • Ruby: # @param [Type] → YARD; freeform with +code+/*bold* → RDoc
  • PHP: fixed — PHPDoc /** @param Type $x */

Detect available docstring linters (so Step 2 can delegate mechanical checks):

  • Python: ruff --select D --no-fix, pydocstyle, interrogate, pydoclint, darglint
  • TS/JS: eslint-plugin-jsdoc (check if in package.json deps)
  • Go: go vet, staticcheck (ST1020/ST1021/ST1022), revive
  • Rust: #![warn(missing_docs)] in crate roots; cargo doc --no-deps 2>&1 | grep warning
  • Java: javadoc -Xwerror, Checkstyle
  • C#: Roslyn CS1591 via dotnet build -warnaserror:CS1591

For each candidate linter, verify it's actually runnable (command -v or present in project deps). Record the runnable set.

State the resolved scope, file count, detected language(s), detected docstring style, available linters, and detected doc-build tool clearly before proceeding.


Step 2: Multi-Dimensional Docstring Analysis

Launch 3 Explore subagents in parallel (subagent_type: "Explore", model: "opus").

Provide each agent with:

  • The resolved scope (file list) from Step 1
  • The detected docstring style (or explicit project configuration)
  • The list of runnable linters
  • The language(s) present

IMPORTANT: All subagents MUST be launched with subagent_type: "Explore" and model: "opus" (resolves to the latest Claude Opus, the most capable model). The Explore agent is read-only by design (Edit and Write are denied at the agent level). This ensures no subagent can accidentally modify the project during analysis. The model override to Opus is required because Explore defaults to Haiku, which lacks the depth needed for this skill's thorough analysis. Never use general-purpose subagents in this skill.

IMPORTANT: Instruct each agent to read the full target files (not just snippets). Understanding the function body is essential for both drift detection (does the docstring describe what the code actually does?) and proposed-content generation (what should the docstring say?).

Each agent must return findings in this structured format:

  • ID: agent-local identifier (e.g., A1, B1, C1)
  • File:Line: exact file path and line number of the symbol
  • Symbol: the function/class/method/constant name and signature
  • Current docstring: the existing docstring verbatim, or "(missing)"
  • Proposed docstring: the complete replacement text in the detected project style
  • Rationale: why this change improves the docstring
  • Confidence: High / Medium / Low (how certain the agent is this is a real issue)
  • Severity: Critical / High / Medium / Low

Each agent must also return 2-3 "Looks Good" callouts — symbols that are already well-documented and should NOT be changed. This prevents unnecessary rewrites and acknowledges good practice.


Agent 1: Coverage & Presence

Identify symbols that lack docstrings entirely, with emphasis on the public API surface.

Public API detection (language-specific):

  • Python: non-underscore identifiers at module top level (respect __all__ if defined — symbols in __all__ are always public; symbols not in __all__ are internal even if non-underscore)
  • TS/JS: export keyword (named or default); top-level declarations in files re-exported via index.ts
  • Go: identifiers starting with a capital letter at package level
  • Rust: items with pub / pub(crate) / pub(super) visibility
  • Java/C#: public (also protected if the class is extensible)
  • Ruby: methods outside private / protected blocks
  • PHP: methods with public visibility; classes without explicit visibility

Also check:

  • Any runnable linter detected in Step 1 — run it and capture structured output. Parse findings into the agent's format.
  • Module-level / file-level / crate-level documentation (Python module docstring, Go package comment, Rust //!, TSDoc @packageDocumentation).

Severity assignment:

  • Critical — public API symbol with zero docstring
  • High — public API symbol with a single-line docstring shorter than 10 words
  • Medium — internal symbol with a complex signature (3+ parameters, or raises/returns non-trivially) and no docstring
  • Low — internal symbol with a simple signature and no docstring

Skip: test files, generated code, __init__.py files that only re-export, trivial getters/setters in some languages if the convention is to skip them. Respect .gitignore.

Return findings sorted by severity (Critical first), and 2-3 Looks Good callouts (e.g., "The public API of src/auth/ is consistently documented at the module level").


Agent 2: Accuracy & Drift

For every function/method that has a docstring in the scoped files, verify it still matches the code. This is the agent that catches bugs.

Drift categories:

  • Param drift — documented parameters don't match the actual signature:
  • Renamed (docstring says user_id, signature has uid)
  • Reordered (docstring lists params in different order than signature)
  • Added (signature has a param not documented)
  • Removed (docstring describes a param that no longer exists)
  • Missing return documentation — function returns a non-void/non-None value but has no @returns / Returns: / :returns: / `` section
  • Missing error documentation — function throws/raises but has no @throws / Raises: / :raises: / ` — check for throw, raise, panic!, return Err(...)` in the body
  • Type mismatch — the docstring-declared type contradicts the actual type annotation (e.g., JSDoc @param {string} on a TS function whose signature types it as number; Python docstring says int but annotation says str)
  • Copy-paste rot — identical docstring on symbols with different signatures. Detect by hashing docstring text and flagging duplicates across different signatures.
  • Stale description — the docstring describes behavior the code no longer exhibits (e.g., mentions a side effect that has been removed, or references a removed dependency). Only flag at High confidence; this is the hardest category and false positives are costly.
  • Example drift — code examples in docstrings reference APIs that no longer exist (e.g., example imports a removed symbol).

Severity assignment:

  • Critical — param drift on public API (callers will be misled), or type mismatch on public API
  • High — missing @returns/@throws on public API, stale description on public API
  • Medium — drift on internal API, copy-paste rot
  • Low — example drift, minor wording issues

For each finding, provide the corrected docstring that reflects the current code. Do not speculate about the original author's intent — describe what the code actually does now.

Return findings and 2-3 Looks Good callouts (e.g., "The database layer's docstrings consistently and accurately document thrown exceptions").


Agent 3: Style & Convention Consistency

Flag docstrings that deviate from the project's detected style or lack the informational quality a reader needs.

Checks:

  • Style deviation — files using a different style from the project default (NumPy-style in a Google-style Python project; JSDoc type tags in a TSDoc project; single-line godoc that doesn't start with the identifier name in Go)
  • Intra-docstring inconsistency — mixed tag conventions within a single docstring (e.g., Args: followed by :returns: in Python)
  • Under-informative docstrings — docstrings that merely restate the function name ("doeslogin: does the login", "getuser: gets a user") without adding information the signature doesn't already convey
  • Formatting violations (language-specific):
  • Python PEP 257: first line not ending in a period, first line not a complete sentence, no blank line between summary and body for multi-line docstrings, triple single quotes instead of triple double quotes
  • Go: doc comment doesn't start with the identifier name
  • Rust: missing # Examples, # Panics, # Errors, # Safety sections where appropriate (e.g., unsafe fn should document safety invariants)
  • Javadoc: missing @param for documented parameters, {@link} pointing to non-existent types
  • TSDoc: use of @param {type} (banned — types belong in TS signature)
  • Link rot — {@link Foo}, [Foo], `{@see

…

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.