Agent Skills: Smell Scan

>

UncategorizedID: DieGopherLT/claude-kit/smell-scan

Install this agent skill to your local

pnpm dlx add-skill https://github.com/DieGopherLT/dotclaudefiles/tree/HEAD/plugins/refactoring-guru/skills/smell-scan

Skill Files

Browse the full folder contents for smell-scan.

Download Skill

Loading file tree…

plugins/refactoring-guru/skills/smell-scan/SKILL.md

Skill Metadata

Name
smell-scan
Description
>

Smell Scan

Turn a passive Clean Code reading into a reactive analysis of real code. Given a target — a file, a directory, or a specific function/type — detect concrete code smells from the refactoring.guru taxonomy, persist them as a source-of-truth (SoT) file per domain, report each finding with its location, confidence, and mapped techniques, then offer to apply a fix via the refactor skill.

Detection always fans out through a Workflow that pipelines each domain through its own 5-detector batch — one domain or many, the mechanism is the same, so there is only one synthesis path to keep correct. Detection and reporting only — this skill never edits code.

Step 1 — Resolve the target

Determine what to scan from the user's request:

  • An explicit path (src/order-service.ts), a directory, or a named function/type.
  • If the request is "this" / "this code" with no path, use the file or symbol currently in focus in the conversation. If genuinely ambiguous, ask one short clarifying question before scanning.

Step 2 — Partition into domains

A domain is a top-level module folder under a conventional root: src/, packages/, plugins/, or the repo root itself when none of those roots is present. Map the resolved target UP to the domain(s) that contain it:

  • A single file or a nested directory maps to the one top-level folder that contains it.
  • If the target itself IS one of those roots (e.g. the user asks to scan all of plugins/), every immediate child directory of that root is its own domain.

domainCount is the number of distinct top-level domains the target resolves to. The domain identifier used everywhere downstream (SoT filename, domain field, path field on findings) is the repo-relative path (e.g. src/orders, plugins/refactoring-guru). Absolute paths are what gets passed to the Workflow in Step 3; the script derives the repo-relative form itself from the repoRoot argument, so no manual conversion happens here.

If domainCount is 0 (the target does not resolve to anything scannable), tell the user there is nothing to scan and stop here.

Step 3 — Dispatch the Workflow

First capture two values the script needs but cannot derive itself — one scanned_at timestamp (Date.now()/new Date() would break Workflow resume) and the absolute repoRoot (used to normalize paths and to build absolute write paths):

date -u +%Y-%m-%dT%H:%M:%SZ
git rev-parse --show-toplevel

Then invoke, regardless of domainCount — one domain and many both flow through the same pipeline, so there is no separate manual synthesis path to keep in sync by hand:

Workflow({ scriptPath: "${CLAUDE_PLUGIN_ROOT}/skills/smell-scan/scripts/workflow.js", args: { domains: ["<absolute path to domain 1>", "<absolute path to domain 2>", ...], repoRoot: "<absolute repo root>", scannedAt: "<captured ISO timestamp>" } })

The Workflow pipelines each domain through its own 5-detector batch (bloaters, oo-abusers, change-preventers, dispensables, couplers) and synthesizes its findings in plain JS (see the script's synthesizeDomain): merging the 5 detectors' results, normalizing file to a repo-relative path (via repoRoot), deriving technique from the head of techniques, computing severity from confidence bands, and flagging cross_cutting for Shotgun Surgery, Inappropriate Intimacy, and Divergent Change. It then assigns reference codes globally across every domain (stable-sorted by confidence descending, one counter per category prefix — B/OO/CP/D/C — never restarting per domain) and serializes one source-of-truth file per domain.

It returns { domains: [{ domain, total, findings }], total, files: [{ path, content }] } with no filesystem writes — the files array carries each domain's SoT already serialized, with an absolute path (joined under repoRoot) ready to persist verbatim in Step 4.

Step 4 — Persist the returned files

The Workflow has already assigned codes and serialized each domain's source-of-truth file, and each files entry's path is already absolute. This step has no derivation left — just write what the script returned:

mkdir -p "<repoRoot>/.claude/refactoring-guru/findings"

Then, for each entry of the returned files array, Write(file_path=<entry.path>, content=<entry.content>) verbatim. Each content is a fully-formed SoT document; do not reshape, re-sort, or re-slug it, and do not rewrite the absolute path. A clean domain (zero findings) still returns an entry — write it too; its SoT records the scan with an empty findings array. The content shape, for reference:

{
  "domain": "src/orders",
  "scanned_at": "2026-06-30T14:00:00Z",
  "total": 2,
  "findings": [
    {
      "code": "B1",
      "smell": "Long Method",
      "category": "Bloaters",
      "path": "src/orders/order-service.ts",
      "line_range": [45, 120],
      "evidence": "75-line function performs validation, transformation and persistence",
      "confidence": 92,
      "severity": "high",
      "technique": "Extract Method",
      "resolution_plan": "Extract validation (45-60), transformation (61-95), persistence (96-120) into three named functions; the body becomes three calls.",
      "cross_cutting": false
    }
  ]
}

Step 5 — Present the prioritized report

Render the findings ordered by severity (critical → high → medium → low). Each finding's reference code (B1, B2, OO1, CP1, D1, C1, …) is a per-scan handle the user can pass straight to refactor.

For each finding, show:

### <code> · <smell> — <severity> (confidence <n>)
- File: <path>:<line_start>-<line_end>
- Evidence: <evidence>
- Technique: <technique>

When domainCount > 1, also show the domain each finding belongs to, grouped or annotated so the user can tell which SoT file it lives in. Group by severity band; within a band, keep confidence ordering. Lead the report with a one-line summary: total findings and the count per severity. If total is 0 across every domain, say the target is clean of high-confidence smells — do not pad with low-confidence noise.

Reference codes are assigned per scan, sequentially within each category prefix, globally across every domain scanned. They are stable only within this scan; re-scanning may renumber. The smell types and their detection criteria live in ${CLAUDE_PLUGIN_ROOT}/references/smell-catalog.md.

Step 6 — Offer to refactor

After the report, offer to apply a fix:

  • The user can pass a reference code (refactor B1) or name a technique and location explicitly.
  • Invoking the refactor skill resolves the code unambiguously — even across a multi-domain scan, since codes are globally unique — and carries the finding's technique, file, location, and smell context into a safe test → refactor → test → commit cycle. Recommend tackling findings highest-severity first, and one technique at a time.

Do not start refactoring from this skill. This skill detects and reports; refactor applies.

References

Load on demand, only when needed:

  • ${CLAUDE_PLUGIN_ROOT}/references/smell-catalog.md — the 26 smells: reference code, detection criteria, problem, and mapped techniques. Consult to explain a finding or justify a confidence call.
  • ${CLAUDE_PLUGIN_ROOT}/references/refactoring-techniques.md — the 67 techniques: when to apply and mechanics. Consult to explain why a technique maps to a smell.
  • ${CLAUDE_PLUGIN_ROOT}/references/workflow.md — the safe test → refactor → test → commit cycle that any fix should follow.

Scope notes

  • The taxonomy includes OOP-specific smells (marked in the catalog). For non-OOP targets, detectors do not invent class/inheritance smells — those surface only when real type-hierarchy code is present.
  • Findings are evidence-based: every one cites a file and line range with a concrete observation. Silence (zero findings) is a valid, correct result for clean code.
  • SoT files under .claude/refactoring-guru/findings/ are transient analysis artifacts, gitignored — they are not meant to be committed.