agentleFS
rhvdberghrhvdbergh/claude-skills/prune-comments/SKILL.md

prune-comments

Skill0 starsChanged 27 days agoMITView on GitHub

Delete comments that narrate what the code does or record conversation history, keeping only those that explain a non-obvious why. Operates on the working diff by default; accepts explicit paths. Pass --strict to delete every comment on an added line except a short hard-keep list.

4 other projects use a version of this.

Adopted by

Most recently taken up by

The file

Show its rules and text

We split this skill into the rules it gives an agent

21 rules. 0 are common, 17 are distinctive, and 4 are very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 17

    Distinctive

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Default scope is the working diff — comments in code this branch touched.

    line 30
  2. Distinctive:

    If the working directory is not a git repo, require explicit paths.

    line 65
  3. Distinctive:

    Only four things survive. The first three break the build or the license if you remove them.

    line 78
  4. Distinctive:

    Delete first. Apply the edits, then ask.

    line 94
  5. Very specific:

    Ask all candidates in one AskUserQuestion call, after the edits are applied.

    line 99
  6. Distinctive:

    If more than 3 comments qualify, ask about the 3 strongest and delete the rest without a question.

    line 101
  7. Distinctive:

    If none qualify, ask nothing.

    line 102
  8. Distinctive:

    Never delete an XML doc comment.

    line 109
  9. Very specific:

    Delete a <param> or <returns> line that only repeats the name and the type already in the signature.

    line 113
  10. Very specific:

    Keep a <param> or <returns> line that states a unit, a range, a null rule, an ordering guarantee, or a thrown exception.

    line 115
  11. Distinctive:

    Do not collapse when the result goes over about 120 characters.

    line 117
  12. Distinctive:

    When a comment is genuinely ambiguous — it might encode a why you cannot verify — keep it and list it under *Kept, uncertain* in the report.

    line 162
  13. Distinctive:

    When a comment exists only because a name is poor, the fix is the rename, not just the deletion.

    line 167
  14. Distinctive:

    If the symbol is exported, public, part of an interface, a serialized field, or referenced from other files: do not rename.

    line 172
  15. Distinctive:

    Read each in-scope file. Do not rely on the diff alone — a comment's fate depends on the code around it.

    line 182
  16. Distinctive:

    Verify — conditionally. Verification exists to catch the only two edits that can actually break a build: an incomplete rename, and a …

    line 190
  17. Distinctive:

    no renames were applied in this run, and

    line 193
  18. Very specific:

    no removed line matched a tool-directive pattern — eslint-disable, ts-expect-error, ts-ignore, noqa, type: ignore, pragma, region, nolint, …

    line 194
  19. Distinctive:

    When either condition fails, run the project's type check or build, and the test suite for the touched area:

    line 198
  20. Distinctive:

    If verification fails, a tool directive was removed or a rename was incomplete.

    line 204
  21. Distinctive:

    Keep the report to what changed and why.

    line 233

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Purpose

Enforce the comment rules from CLAUDE.md on real code: a comment survives only if it explains a non-obvious why. Comments that restate what a line does, or narrate what was changed and for whom, are deleted. Where a comment exists because a name is bad, the name is fixed instead.

This skill edits code directly, then reports what it removed. It does not hunt for bugs.

When this runs

Three entry points:

  • /prune-comments — the user invokes it directly. Scope is resolved below.
  • /prune-comments --strict, or /remove-comments — the same skill in strict mode. Read Strict mode below; it replaces the Delete these / Keep these rules.
  • The final step of session-review-loop — that skill reads this file and follows these steps once its review rounds have terminated, scoped to the diff the loop produced, using the merge-base it already established. In that mode there is no separate scoping pass and no round of its own: prune, verify, hand the report back for the loop's write-up.

Scope

Default scope is the working diff — comments in code this branch touched.

git rev-parse --show-toplevel
git rev-parse --abbrev-ref HEAD
git merge-base HEAD origin/main 2>/dev/null \
  || git merge-base HEAD origin/master 2>/dev/null \
  || git merge-base HEAD origin/develop 2>/dev/null
git diff <merge-base>...HEAD --name-only
git diff --name-only          # uncommitted
git diff --name-only --cached  # staged

Review the union of those file lists. Within each file, only added lines are in scope. Get them with a zero-context diff and keep the + lines:

git diff -U0 <merge-base>...HEAD -- <file>
git diff -U0 -- <file>
git diff -U0 --cached -- <file>

A comment is in scope only when its own line carries a + prefix in one of those three diffs. For a block comment, every line of the block must be added. Context lines and removed lines are out of scope. Comments in untouched regions are out of scope — leave them.

Overrides:

  • /prune-comments <paths> — review exactly those files or directories in full, ignoring the diff.
  • /prune-comments --all — every source file in the repo. Confirm with the user before starting, and warn that this produces a large diff across code they did not touch.

--strict --all is refused. Say so and stop. Strict mode deletes knowledge that other people wrote, so it must stay inside added lines. --strict <paths> narrows to those paths but still applies the added-line filter inside them.

If the working directory is not a git repo, require explicit paths.

Strict mode (--strict)

Strict mode inverts the default. In normal mode a comment survives unless it narrates. In strict mode every comment on an added line is deleted, unless it is on the hard-keep list below.

The sections Delete these, Keep these, and the Kept, uncertain report category do not apply in strict mode. There is no "keep because I am unsure" — doubt is resolved by a question, or by deletion.

Hard keep — never delete, in any mode

Only four things survive. The first three break the build or the license if you remove them. The fourth has its own rule.

  1. Tool directives — eslint-disable, ts-expect-error, ts-ignore, # noqa, # type: ignore, #pragma, #region, nolint, prettier-ignore, istanbul ignore, coverage:, any @ts- directive, codegen markers, <auto-generated> headers.
  2. License and copyright headers.
  3. Text inside a string literal or a regex that only looks like a comment. Check the match is a real comment before you edit it.
  4. XML doc comments — see the next section. These are compressed, never deleted.

Everything else on an added line goes. This includes TODO, FIXME, HACK, and XXX markers, and comments that state a real why. A why comment survives only if you keep it through a question.

The question budget

  • Delete first. Apply the edits, then ask.
  • Collect at most 3 candidates for a question across the whole run.
  • A comment qualifies as a candidate only when it states a constraint that lives outside this repo and no test covers: a vendor bug, a rate limit, a hardware limit, a legal or compliance rule, an ordering guarantee of an external system.
  • Ask all candidates in one AskUserQuestion call, after the edits are applied. Restore the ones the user keeps.
  • If more than 3 comments qualify, ask about the 3 strongest and delete the rest without a question.
  • If none qualify, ask nothing.

XML doc comments

An XML doc comment means /// lines in C#, and a /** … */ block that carries tags in TypeScript or JavaScript. An HTML-style <!-- … --> comment is not one of these; strict mode deletes it.

Never delete an XML doc comment. Compress it instead, in both modes:

  • Collapse a multi-line <summary> to one line. /// <summary>Returns the unpaid balance.</summary> is valid and the compiler accepts it.
  • Delete a <param> or <returns> line that only repeats the name and the type already in the signature.
  • Keep a <param> or <returns> line that states a unit, a range, a null rule, an ordering guarantee, or a thrown exception.
  • Do not collapse when the result goes over about 120 characters. A wrapped one-liner reads worse than three short lines.
  • Aim for one line per doc comment. Accept more when the tags above carry contract information.

Delete these

  • What-narration — the comment restates the line or block below it. // increment the counter, # loop over users, // set loading to true
  • Conversation history — the comment refers to a prompt, ticket, request, or change event. // added for the onboarding flow, // fixed per review, // changed to handle the new shape, // NEW:, // updated 2026-04-01
  • Section banners with no information — // ---- helpers ----, // imports, // constructor
  • Restated signatures — a docblock whose every line repeats the parameter names and types already in the signature, adding no constraint, unit, or contract.
  • Forward references to tickets — a comment pointing at work that has not happened yet, in any tracker format: // FW-3838 will handle this, // deferred to PROJ-123, // see CU-8a2f1x, // blocked on #412, // follow-up ticket coming. The code cannot be read against a ticket that does not exist yet, and these outlive their tickets. Delete the whole comment when the reference is all it says; strip only the reference when the rest of the line states a real constraint. This takes precedence over the TODO/FIXME keep-rule below: a // TODO: FW-3838 with no substance goes, while // TODO: unbounded if the feed exceeds 10k rows stays — reworded without its ticket id if it carried one.
  • Commented-out code — dead code kept "just in case". Delete it; git has it.
  • Redundant type notes in typed languages — // string above a : string.

Keep these

Normal mode only. Under --strict, the hard-keep list replaces this section.

Never remove:

  • A non-obvious constraint, tradeoff, workaround, or gotcha not recoverable from the code (// retrying because the vendor API silently drops writes under load).
  • Anything load-bearing for a tool: eslint-disable, ts-expect-error, # noqa, # type: ignore, #pragma, #region, nolint, codegen markers, <auto-generated> headers.
  • License and copyright headers.
  • TODO, FIXME, HACK, XXX markers whose text states a real problem — these are trackable signals, not prose. A marker that only points at a future ticket is deleted; see above.
  • Public API documentation that carries contract information a caller cannot see from the signature: units, ranges, nullability, thrown exceptions, ordering guarantees, side effects. XML doc comments, JSDoc, and docstrings on public surfaces are kept when they do this. Trim only the lines inside them that merely restate the signature.
  • Anything inside a string literal, regex, or generated file — verify a match is a real comment before editing it.

When a comment is genuinely ambiguous — it might encode a why you cannot verify — keep it and list it under Kept, uncertain in the report. Silence is cheaper than deleting knowledge.

Rename instead of delete

When a comment exists only because a name is poor, the fix is the rename, not just the deletion. Apply the rename only when the symbol's scope is provably local — a local variable, a parameter, or a private member with all references inside the file you are already editing. Verify with a grep across the repo before renaming.

If the symbol is exported, public, part of an interface, a serialized field, or referenced from other files: do not rename. Delete the comment if it is pure what-narration, and note the bad name under Rename suggestions in the report for the user to decide.

Steps

  1. Detect the mode. --strict on the invocation, or an invocation through /remove-comments, turns on strict mode. State the mode in the first line of your output.
  2. Resolve scope as described above. State the repo path, branch, and how many files are in scope. Under --strict, also state how many added lines carry a comment.
  3. Read each in-scope file. Do not rely on the diff alone — a comment's fate depends on the code around it.
  4. For each comment in scope, decide: delete, keep, keep-uncertain, compress, or rename-and-delete. Under --strict the choices are delete, hard-keep, compress, or ask — and ask is capped at 3.
  5. Apply the edits file by file. After any multi-edit sequence in a file, re-read it before the next edit — never target line numbers from a pre-edit view.
  6. Under --strict, ask the question batch now, in one AskUserQuestion call, and restore the comments the user keeps.
  7. Verify — conditionally. Verification exists to catch the only two edits that can actually break a build: an incomplete rename, and a removed line that was load-bearing for a tool. Skip it entirely when both hold:

    • no renames were applied in this run, and
    • no removed line matched a tool-directive pattern — eslint-disable, ts-expect-error, ts-ignore, noqa, type: ignore, pragma, region, nolint, prettier-ignore, istanbul ignore, coverage:, @ts-, <auto-generated>, or any codegen marker.

    When either condition fails, run the project's type check or build, and the test suite for the touched area:

    • TypeScript: tsc --noEmit (or the project's typecheck script)
    • .NET: dotnet build
    • Python: the project's linter and pytest on affected paths

    If verification fails, a tool directive was removed or a rename was incomplete. Restore it and re-verify. When verification is skipped, say so in the report line rather than omitting it.

  8. Report. Never commit.

Report

Pruned N comments across M files.

<file:line>  deleted   what-narration      "// increment the counter"
<file:line>  deleted   history             "// added for the billing flow"
<file:line>  deleted   forward-ticket      "// FW-3838 will handle this"
<file:line>  trimmed   forward-ticket      ticket id stripped, constraint kept
<file:line>  renamed   d -> daysUntilDue   comment deleted, symbol was file-local
<file:line>  compressed  xml-doc           4 lines -> 1

Kept, uncertain (N)  — normal mode only, omit this block under --strict
<file:line>  "<comment>" — may encode a constraint I could not verify

Kept by your answer (N)  — --strict only
<file:line>  "<comment>"

Rename suggestions (N) — symbol is public, your call
<file:line>  `flag` -> `isEligibleForRefund`

Verification: <build/typecheck result>, <test pass count>
              — or: skipped (no renames, no tool directives removed)

Keep the report to what changed and why. If nothing qualified for removal, say so in one line.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.