Identifies code smells — structural patterns that correlate with maintainability problems — and explains why each matters in context. Use when reviewing a PR for structural quality, when the user asks what's wrong with a piece of code that isn't buggy, or when prioritizing refactoring targets.
Install with Tessl CLI
npx tessl i github:santosomar/general-secure-coding-agent-skills --skill code-smell-detector100
Quality
100%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
A smell is not a bug. It's a structural property that makes bugs more likely later. The code works today; the smell is about tomorrow.
| Smell | Detection heuristic | Why it matters | Fix |
|---|---|---|---|
| Long method | > 40 lines, > 3 levels of nesting | Can't hold it in your head; every change risks the whole thing | Extract method |
| God class | > 15 methods, > 10 fields, or depends on > 8 other classes | Every change touches this file; merge conflicts; nobody understands it all | Split by responsibility |
| Feature envy | Method reads 3+ fields of another object, 0 of its own | The method is in the wrong class | Move method |
| Shotgun surgery | One conceptual change → edits in 5+ files | High coupling; change is expensive and error-prone | Consolidate the scattered concern |
| Primitive obsession | Three strings passed together (street, city, zip) everywhere | The missing type is the abstraction you need | Introduce parameter object / value type |
| Boolean blindness | Method takes 3+ booleans; call sites look like f(true, false, true) | Nobody knows what true means at the call site | Named parameters, enum, or config object |
| Speculative generality | Abstract class with one concrete subclass; interface with one impl; hook method nobody overrides | Complexity paid for, never used | Inline it → dead-code-eliminator |
| Data clump | Same 3+ variables always appear together in signatures | Missing type (same as primitive obsession, across methods) | Introduce a class |
| Message chain | a.getB().getC().getD().doThing() | Caller knows the entire object graph; any link change breaks it | Tell-don't-ask; hide the chain |
| Duplicated code | Two regions > 6 lines, > 80% similar | Bug fixed in one, not the other | Extract; but see FP note below |
Don't dump all findings. Rank by change frequency × smell severity:
Use git log --format= --name-only | sort | uniq -c | sort -rn to get change frequency. Smells in cold code are academic.
| Smell flagged | But actually fine when… |
|---|---|
| Long method | It's a flat sequence of independent steps (setup, setup, setup — a script) |
| God class | It's the app's composition root / DI container — by design, it knows everything |
| Duplicated code | The two copies have different reasons to change. "Coincidental duplication" should NOT be extracted — you'll couple two unrelated concerns |
| Speculative generality | It's a plugin interface and the second impl is on the roadmap this quarter |
| Message chain | The chain is navigating a well-known, stable schema (config.database.pool.size) |
Code:
class OrderProcessor:
def process(self, order, user, warehouse, shipper, payment, notifier,
audit, retry, dry_run): # 9 params
if not dry_run:
if payment.charge(user.card, order.total):
if warehouse.has_stock(order.items):
warehouse.reserve(order.items)
if shipper.can_deliver(user.address.zip): # message chain
label = shipper.create_label(user.address.street,
user.address.city,
user.address.zip) # data clump
# ... 40 more lines ...Findings:
process() does validation, charging, reservation, shipping, notification, auditing. Six responsibilities.retry, dry_run as positional booleans. Call sites: processor.process(o, u, w, s, p, n, a, True, False). Which one is dry_run?street, city, zip always travel together. There's an Address object right there (user.address) — pass it whole.user.address.zip. Minor here (Address is stable), but if shipper took an Address, this goes away with fix #3.Prioritization: git log shows OrderProcessor edited 14 times last quarter. Long method + high churn → extract first.
code-refactoring-assistant for the mechanics. This skill finds; that one fixes.<file>:<line> <SMELL> churn=<commits-last-90d>
<what the structure is>
<why it will cost you — specific to this instance>
<suggested refactoring — one sentence>
<false-positive check: does the suppression rule apply?>
---
Ranked by (churn × severity). Fix the top 3; ignore the rest until they climb.47d56bb
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.