From warden
Use when writing a comment that paraphrases the line of code immediately below it; adding a docstring to a function whose name and signature already say everything; reviewing a diff that adds explanatory comments to make obvious code "easier to read"; deciding whether a non-obvious decision (workaround, constraint, invariant) needs a comment.
How this skill is triggered — by the user, by Claude, or both
Slash command
/warden:et-0005-writing-comments-that-explain-whyThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
<!-- generated from tenets/ET-0005-writing-comments-that-explain-why.md by `uv run poe build` — do not edit by hand. -->
Type: best-practice · Tier: 1
Comments capture the why that the code itself cannot express: hidden constraints, surprising invariants, references to upstream bugs, deliberate workarounds, performance trade-offs, "we tried the obvious way and it failed because…". Comments do not restate what the code does — that is the code's job, and a clear identifier or a short helper function does it better than prose. If you find yourself describing the next line in English, rename the line; if a function needs a paragraph to explain its purpose, the function is doing too much. Default to no comment; add one only when removing it would leave a future reader genuinely uncertain.
What-comments rot. The code changes, the comment doesn't, and the
next reader is left to guess which is right — usually losing minutes
diffing them, sometimes shipping a bug because they trusted the wrong
one. Why-comments survive: they record a fact the code cannot
encode (an external constraint, a past incident, a performance
measurement) and that fact stays true even when the implementation
changes. Comments that name the current PR, ticket, or caller (// for the new checkout flow) rot the fastest — the moment "the new
checkout flow" is two years old, the comment is misleading.
// BAD: every comment paraphrases the next line.
public decimal CalculateTotal(IEnumerable<LineItem> items)
{
// sum up all the line items
decimal total = 0;
foreach (var item in items)
{
// multiply price by quantity
total += item.Price * item.Quantity;
}
// return the total
return total;
}
# BAD: docstring restates the signature; "added for X" comment will rot.
def send_invoice(customer_id: str, amount: Decimal) -> None:
"""Send an invoice to the customer with the given amount.
Added for the new billing flow (PR #1842).
"""
# loop through the line items and sum them
...
// BAD: comment narrates the obvious; the variable name already says it.
function priceOrder(order: Order): number {
// initialize the total to zero
let total = 0;
// iterate over each item in the order
for (const item of order.items) {
// add the item's subtotal to the total
total += item.subtotal;
}
return total;
}
// GOOD: no narration of the loop. Comments only where the WHY is non-obvious.
public decimal CalculateTotal(IEnumerable<LineItem> items)
{
return items.Sum(i => i.Price * i.Quantity);
}
// Elsewhere, where it matters:
// Stripe rejects amounts < 0.50 with a generic error; we round up at the API
// boundary so retries don't loop forever. See incident #2024-08-14.
private decimal NormalizeForStripe(decimal amount) =>
amount < 0.50m ? 0.50m : amount;
# GOOD: signature speaks for itself; comment captures a non-obvious constraint.
def send_invoice(customer_id: str, amount: Decimal) -> None:
# SAP only accepts invoices in EUR; upstream code must convert before calling.
# We do not convert here because the caller owns FX rate selection.
...
// GOOD: no narration. Comment names the workaround, not the loop.
function priceOrder(order: Order): number {
// Round per-item, not on the sum: the legacy POS terminal computes the
// same way and we must reconcile to its receipts to the cent.
return order.items.reduce(
(total, item) => total + Math.round(item.subtotal * 100) / 100,
0,
);
}
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 c-hoeller/agent-plugins --plugin warden