skills/code-analysis/code-summarizer/SKILL.md
Produces natural-language summaries of what code does at the function, class, module, or subsystem level, with length and abstraction scaled to the scope. Explains purpose, side effects, and non-obvious behavior rather than restating syntax. Use when onboarding to unfamiliar code, when the user asks what something does, when generating docstrings or architecture notes, or when preparing a handoff document.
npx skillsauth add santosomar/general-secure-coding-agent-skills code-summarizerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Say what the code is for, not what it says. "Iterates over the list and appends items where status is active" is a translation, not a summary. "Returns only the invoices that are eligible for payment" is a summary.
The answer to "what does this do" changes with how much code "this" covers. Decide up front:
| Scope | Length | Abstraction level | Goal | | ------------- | ------------- | ---------------------------------------------- | ------------------------------------------- | | Single expr | 1 phrase | What value, in domain terms | Replace with a well-named variable | | Function | 1–3 sentences | Contract: inputs → outputs → effects | A reader can call it correctly without reading the body | | Class | 1 paragraph | Responsibility + lifecycle + main collaborators| A reader knows when to use it and when not to | | Module / file | 2–4 paragraphs| Subsystem role + what enters/leaves | A reader can decide whether to open it | | Package / dir | Bullets | Architectural role + public surface | A reader can navigate to the right file |
If the user doesn't specify scope, infer from what they pasted: 10 lines → function-level; 500 lines → module-level; a directory path → package-level.
You don't read a 300-line function top-to-bottom to summarize it. You scan for high-information locations:
process or handle, skip to step 2.test_rejects_expired_token tells you more about the function's purpose than its body does.Before writing anything else, complete: "This exists so that ___." If you can't, you don't understand it yet — go back to Step 2.
Good patterns:
Bad patterns (translation, not summary):
After the purpose sentence, add only things that are true, not obvious from the signature, and would change how a caller uses it:
audit_log table on every call." Always worth stating — they're invisible from the signature.QuotaExceededError rather than returning null" — if there's a choice a reasonable person might get wrong.items is already sorted by timestamp."Leave out what the types already say, what any function in this language does (e.g., "returns a value"), and any uncertainty you'd be guessing at.
<One-sentence purpose, active voice.>
<Side effects, if any. Be specific.>
<Error behavior, if non-obvious.>
<Preconditions or cost warnings, if any.>
Example. For:
def reconcile(ledger, bank_txns):
matched, unmatched = [], []
for txn in bank_txns:
entry = ledger.find(amount=txn.amount, date_within=timedelta(days=3))
if entry and not entry.reconciled:
entry.reconciled = True
matched.append((entry, txn))
else:
unmatched.append(txn)
ledger.save()
return matched, unmatched
Bad (translates): "Iterates over bank transactions, calls ledger.find for each, checks if reconciled, appends to matched or unmatched lists, then saves the ledger."
Good (summarizes): "Matches bank transactions against ledger entries by amount within a 3-day window, marking each matched entry as reconciled. Persists the ledger. Returns (matched pairs, unmatched transactions). A transaction with no same-amount entry in the window, or whose entry is already reconciled, lands in unmatched."
The good version lets a caller predict behavior without reading the body. The bad version just makes them read the body slower.
Don't list every method. Answer: what is this class responsible for, and what does it deliberately leave to others?
RateLimiter
Tracks request counts per client and decides whether to admit or reject
the next request. Uses a sliding window — a client at the limit is
rejected until its oldest counted request ages out, not until a fixed
interval elapses.
State is in-memory only. Does not persist across restarts; does not
coordinate across instances. For distributed limiting, wrap a shared
store.
Thread-safe (internal lock). Not async-safe — do not `await` while
holding a reference to a window.
Note: "what it doesn't do" (persist, coordinate) is as valuable as what it does.
At module scope, the reader is deciding whether to open this file. Tell them what crosses the boundary:
payments/stripe_adapter.py
Isolates all Stripe SDK usage behind four operations: charge, refund,
subscribe, cancel. The rest of the codebase speaks in our `Payment` and
`Subscription` types and never imports `stripe` directly.
Incoming: our domain types + tenant config (API key per tenant).
Outgoing: Stripe HTTP; audit log; `payment.completed` event on the bus.
Stripe errors are caught here and re-raised as our `PaymentError`
hierarchy — callers never see raw Stripe exceptions. Retries transient
failures (5xx, rate limits) internally with backoff.
config.VALIDATION_MODE at call time."foo() — behavior depends on that."invoice, say invoice — don't genericize to "the object" or "the record."development
Extracts human-readable pseudocode from a verified formal artifact (Dafny, Lean, TLA+) while preserving the verified properties as annotations, so the proof-carrying logic can be reimplemented in a production language. Use when porting verified code to an unverified target, when documenting what a formal spec actually does, or when handing a verified algorithm to an implementer.
development
Translates natural-language or pseudocode descriptions of concurrent and distributed systems into TLA+ specifications ready for the TLC model checker. Identifies state variables, actions, type invariants, safety properties, and liveness properties from the description. Use when formalizing a protocol, when the user describes a distributed algorithm to verify, when designing a consensus or locking scheme, or when starting formal verification of a concurrent system.
testing
Reduces a TLA+ model so TLC can actually check it — shrinks constants, adds state constraints, abstracts data, or applies symmetry — when the state space is too large to enumerate. Use when TLC runs out of memory, when checking takes hours, or when a spec works at N=2 and you need confidence at larger scale.
development
TLA+-specific instance of model-guided repair — reads a TLC error trace, identifies the enabling condition that should have been false, strengthens the corresponding action, and maps the fix to source code. Use when TLC reports an invariant violation or deadlock and you have the code-to-TLA+ mapping from extraction.