From comment-discipline
Rules for writing source-code comments that serve future readers, not the conversation that produced the code. Apply whenever about to write or edit any source-code comment, docstring, or inline note — verify each proposed comment against these rules before producing the diff. Prevents the very common AI-coding failure mode where an agent adds comments documenting the chat (what the user asked, what alternative was rejected, what the agent changed) instead of comments that document the code.
How this skill is triggered — by the user, by Claude, or both
Slash command
/comment-discipline:comment-disciplineThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A comment belongs in source code only if a future reader who has **only this file** — no chat transcript, no PR description, no linked issue — finds it useful. Comments that document the path the author took through a conversation are noise to that reader; they age into nonsense within weeks.
A comment belongs in source code only if a future reader who has only this file — no chat transcript, no PR description, no linked issue — finds it useful. Comments that document the path the author took through a conversation are noise to that reader; they age into nonsense within weeks.
The audience for a comment is not the person who wrote the code and not the agent that helped write it. The audience is someone six months later, possibly someone else, opening this file cold.
If a proposed comment fails any of these, do not produce it.
The cleanest fix for most comment-worthy code isn't a better comment — it's better code. Before writing a comment, ask whether one of these would remove the need:
const d = u.filter(x => x.a > 0) becomes self-documenting as const activeUsers = users.filter(u => u.accountAgeDays > 0). No comment needed.applyDiscountToCart(cart, code). The function name is the documentation.// must be positive becomes a PositiveInt branded type or a runtime assertion that throws on bad input. The constraint is enforced, not described.Reach for the comment only after these moves don't fit.
Write a comment only if it explains one of:
If the comment doesn't fit one of those four, delete it.
Mentally replace the comment with // ???. Does the file communicate as much to a cold reader? If yes, the comment was adding nothing — remove it. If no, the comment is doing real work and stays.
A second test: would the comment still make sense if read by someone who has never seen the conversation that produced this code? If "as requested", "per your suggestion", "switched to library X", or any reference to the conversation has to be removed for the comment to make sense, the whole comment is conversation residue and should be deleted, not edited.
Every one of these is a deletion candidate, not an edit candidate.
The comment narrates the chat instead of the code.
// ❌ Switched to map() per your suggestion
const ids = users.map(u => u.id);
// ✓ delete — the map() call is right there
const ids = users.map(u => u.id);
The comment restates what the code obviously does.
# ❌ Loop through users
for user in users:
notify(user)
# ✓ delete — the loop is self-evident. If something non-obvious is true,
# state the constraint instead:
# users is guaranteed sorted by signup date — notification order matters
for user in users:
notify(user)
The comment describes the previous version that no longer exists.
// ❌ Refactored from earlier nested-map approach
const grouped = groupBy(items, 'category');
// ✓ delete — belongs in the commit message, not the file
const grouped = groupBy(items, 'category');
The comment editorializes about a library call that's already visible.
// ❌ Use lodash here to make this simpler
const grouped = _.groupBy(items, 'category');
// ✓ delete — the lodash call is the code
const grouped = _.groupBy(items, 'category');
The comment states a preference, not a constraint.
// ❌ We chose async here because it's more modern
async function loadConfig() { ... }
// ✓ either delete, or convert the preference into the real constraint:
// Must be async — caller holds the UI thread and disk I/O can block for tens of ms
async function loadConfig() { ... }
The comment links to a moving target without encoding why.
// ❌ See issue #42
element.addEventListener('touchstart', handler, { once: true });
// ✓ encode the constraint so the link isn't load-bearing:
// Workaround: Safari < 17 fires touchstart twice on this element (issue #42).
// Remove when Safari 17 is the minimum supported version.
element.addEventListener('touchstart', handler, { once: true });
A bare TODO ages into noise.
# ❌ TODO: fix this
return data[0] if data else None
# ✓ either fix it now, OR encode the deferred work concretely:
# TODO(mh, 2026-06): replace with native AbortSignal once Node 22 LTS is min target — issue #142
return data[0] if data else None
// ========= USERS =========. Well-organized files don't need them; poorly-organized files need to be reorganized, not banner-decorated.// returns a string above a function whose return type is already string. The type system is the documentation.// Added by Mikita 2026-04-12. Git blame already knows.This is not a ban on documentation. Function-level documentation that explains intent, parameters, return semantics, and side effects in a docstring/JSDoc/Rust-doc-comment is valuable when the function is part of a public API or a non-trivial internal contract. The rules above are primarily for inline comments inside function bodies — the place where conversation residue accumulates most aggressively. Doc-comments follow the same "audience = future reader with only this file" model, but the bar for inclusion is different: a public API function should have a docstring even when an inline comment in the same spot would be redundant.
When in doubt, write fewer comments. The bar should be high. A file with three sharp comments that each capture a real WHY is better than a file with thirty comments that narrate the implementation.
Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub mikitahimpel/ai-toolkit --plugin comment-discipline