Nuke Comments
Deletes every comment in the target file(s) or directory, unconditionally.
There's no distinction here between a tutorial comment and a required
SAFETY: note, a license header, or a public API doc comment — they're all
comments, so they all go. This only exists because the user has explicitly
chosen blind, no-review removal over a judgment-based cleanup — don't use it
when the actual ask is "clean up bad comments" or "improve comment quality."
Before running this on a real codebase, say once, plainly, what it will
also remove: license/copyright headers, SAFETY:/# Safety doc comments on
unsafe code, and public API docs (rustdoc/Javadoc/godoc/docstrings). State
it and proceed — the user has already decided this tradeoff is what they
want; don't turn it into a confirmation gate or ask again.
How it works
A bundled Python state machine (scripts/strip_comments.py) tracks whether
the parser is inside a string, a raw/triple-quoted string, a line comment, or
a block comment (with nesting for Rust's /* /* */ */), so it only deletes
actual comments and never touches // or # sitting inside a string literal
or a URL in a string. It needs nothing beyond Python 3's standard library.
Supported by extension:
- Rust (
.rs) — //, /* */ (nested), and r"..." / r#"..."# raw strings
- C-family (
.c .h .cpp .hpp .cc .cxx .java .scala .kt .kts .js .jsx .mjs .cjs .ts .tsx .proto .go .cs .swift .php .dart .zig .jsonc) — //, /* */
- Hash-family (
.py .pyw .sh .bash .zsh .rb .yaml .yml .toml .r .pl .pm, Dockerfile) — #
- Dash-family (
.sql .lua .hs) — --, plus /* */ for SQL
Anything else (e.g. plain YAML edge cases, exotic languages) is skipped
silently — the tool never guesses at a syntax it wasn't given.
Known limitation: cgo preambles
In Go files that import "C", the /* ... */ block immediately above that
import isn't documentation — cgo compiles its contents as literal C, so
#includes, #cgo directives, and any C declarations placed in there are
real code wearing a Go comment as a syntax requirement. This tool can't
distinguish that from an ordinary comment and will delete C code along with
it, breaking the build (symptom: could not determine kind of name for C.foo). If a repo has .go files using cgo, check go build ./...
afterward and be ready to manually restore anything load-bearing that lived
inside a cgo preamble.
Scope
Resolve $ARGUMENTS to a target in this order — stop at the first match:
- No argument → run
git status --porcelain (staged and unstaged,
tracked files). If there are uncommitted changes, target those changed
files' paths directly. If there are none, say so and stop — don't
fall back to stripping the whole repo, that must be requested explicitly
(case 5).
- A filesystem path that exists relative to the repo root (a file or
directory) → target it directly, same as before.
- A PR reference (
#123, 123, PR 123, or a GitHub PR URL) →
gh pr diff <number> --name-only for the file list; target those paths
as they exist in the current working tree (gh pr checkout <number>
first only if the files aren't present locally, and confirm with the
user first since it switches branches).
- A branch name that resolves via
git show-ref --verify or appears
in git branch --list/git branch -r → diff it against its merge base
with the repo's default branch (git merge-base <branch> origin/HEAD)
and target the files that diff touches.
- An explicit whole-repo request ("full repo", "whole repo", "repo",
"everything", "all") → target the repo root, same as passing it as a
directory.
- Anything that matches none of the above (typo'd path, unknown branch,
PR number that doesn't exist) → say so and ask, rather than guessing or
silently widening scope.
Running it
python3 ~/.claude/skills/nuke-comments/scripts/strip_comments.py -i <path> [<path> ...]
<path> can be a single file, a directory (recursed automatically), or
several of either — pass one argument per file/directory the scope
resolution above landed on (e.g. every changed file for the no-argument
or PR/branch cases, or the repo root for the whole-repo case).
-i / --in-place writes the stripped result back to each file. Without
it, the tool writes to stdout instead — useful for a quick look, but for
the "just remove them" workflow this skill exists for, use -i.
.git, target, node_modules, .build, build, dist, .idea,
.vscode, .venv, venv, __pycache__, and any other dot-directory are
skipped automatically.
Reporting back
The script prints one Stripped: <path> line per file it actually modified,
plus Warning:/Error: lines for anything it couldn't read. After running,
just relay that file list back to the user — that's the whole report. Don't
open the diff, don't walk through what got removed, don't add anything back.
That's the point of this skill over the judgment-based cleanup workflow.
1---2name: nuke-comments3description: Mechanically strip every comment from source files in one pass, with zero per-comment review or judgment — a fast syntax-driven deletion, not a quality/cleanup pass. Use whenever the user says to "nuke", "strip", "wipe", "delete all", or "remove all" comments, wants comments gone with "no checking" or "don't review them", or explicitly rejects a judgment-based comment cleanup in favor of blind removal. Do NOT use this for requests like "clean up bad comments", "remove redundant/tutorial comments", or "improve comment quality" — those need per-comment judgment (SAFETY docs, license headers, and public API docs must survive that kind of pass); this skill removes literally all of them, no exceptions, and is for when the user explicitly wants that. Takes an optional argument scoping the pass: a file or directory path, a PR number/URL, a branch name, or "full repo"/"repo". With no argument, scopes to uncommitted changes if there are any, and otherwise reports that there's nothing to strip rather than defaulting to4---56# Nuke Comments78Deletes every comment in the target file(s) or directory, unconditionally.9There's no distinction here between a tutorial comment and a required10`SAFETY:` note, a license header, or a public API doc comment — they're all11comments, so they all go. This only exists because the user has explicitly12chosen blind, no-review removal over a judgment-based cleanup — don't use it13when the actual ask is "clean up bad comments" or "improve comment quality."1415**Before running this on a real codebase, say once, plainly, what it will16also remove: license/copyright headers, `SAFETY:`/`# Safety` doc comments on17`unsafe` code, and public API docs (rustdoc/Javadoc/godoc/docstrings).** State18it and proceed — the user has already decided this tradeoff is what they19want; don't turn it into a confirmation gate or ask again.2021## How it works2223A bundled Python state machine (`scripts/strip_comments.py`) tracks whether24the parser is inside a string, a raw/triple-quoted string, a line comment, or25a block comment (with nesting for Rust's `/* /* */ */`), so it only deletes26actual comments and never touches `//` or `#` sitting inside a string literal27or a URL in a string. It needs nothing beyond Python 3's standard library.2829Supported by extension:30- **Rust** (`.rs`) — `//`, `/* */` (nested), and `r"..."` / `r#"..."#` raw strings31- **C-family** (`.c .h .cpp .hpp .cc .cxx .java .scala .kt .kts .js .jsx .mjs .cjs .ts .tsx .proto .go .cs .swift .php .dart .zig .jsonc`) — `//`, `/* */`32- **Hash-family** (`.py .pyw .sh .bash .zsh .rb .yaml .yml .toml .r .pl .pm`, `Dockerfile`) — `#`33- **Dash-family** (`.sql .lua .hs`) — `--`, plus `/* */` for SQL3435Anything else (e.g. plain YAML edge cases, exotic languages) is skipped36silently — the tool never guesses at a syntax it wasn't given.3738## Known limitation: cgo preambles3940In Go files that `import "C"`, the `/* ... */` block immediately above that41import isn't documentation — cgo compiles its contents as literal C, so42`#include`s, `#cgo` directives, and any C declarations placed in there are43real code wearing a Go comment as a syntax requirement. This tool can't44distinguish that from an ordinary comment and will delete C code along with45it, breaking the build (symptom: `could not determine kind of name for46C.foo`). If a repo has `.go` files using cgo, check `go build ./...`47afterward and be ready to manually restore anything load-bearing that lived48inside a cgo preamble.4950## Scope5152Resolve `$ARGUMENTS` to a target in this order — stop at the first match:53541. **No argument** → run `git status --porcelain` (staged and unstaged,55 tracked files). If there are uncommitted changes, target those changed56 files' paths directly. If there are **none**, say so and stop — don't57 fall back to stripping the whole repo, that must be requested explicitly58 (case 5).592. **A filesystem path** that exists relative to the repo root (a file or60 directory) → target it directly, same as before.613. **A PR reference** (`#123`, `123`, `PR 123`, or a GitHub PR URL) →62 `gh pr diff <number> --name-only` for the file list; target those paths63 as they exist in the current working tree (`gh pr checkout <number>`64 first only if the files aren't present locally, and confirm with the65 user first since it switches branches).664. **A branch name** that resolves via `git show-ref --verify` or appears67 in `git branch --list`/`git branch -r` → diff it against its merge base68 with the repo's default branch (`git merge-base <branch> origin/HEAD`)69 and target the files that diff touches.705. **An explicit whole-repo request** ("full repo", "whole repo", "repo",71 "everything", "all") → target the repo root, same as passing it as a72 directory.736. Anything that matches none of the above (typo'd path, unknown branch,74 PR number that doesn't exist) → say so and ask, rather than guessing or75 silently widening scope.7677## Running it7879```bash80python3 ~/.claude/skills/nuke-comments/scripts/strip_comments.py -i <path> [<path> ...]81```8283- `<path>` can be a single file, a directory (recursed automatically), or84 several of either — pass one argument per file/directory the scope85 resolution above landed on (e.g. every changed file for the no-argument86 or PR/branch cases, or the repo root for the whole-repo case).87- `-i` / `--in-place` writes the stripped result back to each file. Without88 it, the tool writes to stdout instead — useful for a quick look, but for89 the "just remove them" workflow this skill exists for, use `-i`.90- `.git`, `target`, `node_modules`, `.build`, `build`, `dist`, `.idea`,91 `.vscode`, `.venv`, `venv`, `__pycache__`, and any other dot-directory are92 skipped automatically.9394## Reporting back9596The script prints one `Stripped: <path>` line per file it actually modified,97plus `Warning:`/`Error:` lines for anything it couldn't read. After running,98just relay that file list back to the user — that's the whole report. Don't99open the diff, don't walk through what got removed, don't add anything back.100That's the point of this skill over the judgment-based cleanup workflow.