| portability | portable |
| reuse | standalone |
| requires | [] |
| name | clean-code-duplication |
| description | Audits a codebase for duplicated code (copy/paste clones and structural repetition), ranks the worst clones with per-language detection tools, triages false positives, and proposes a deduplication strategy — then routes each fix to the right downstream skill. Use when: a repository has grown by copy/paste, the same logic appears in several places, you want a DRY-focused clean-code triage before refactoring, or you need a consolidation plan before handing work to `clean-code-refactor` or a `[language]-data-engineer` (for oversized-file triage use clean-code-size instead). Runs jscpd as the cross-language detector and documents native tools per language (pylint, eslint-plugin-sonarjs, PMD CPD, dupl/golangci-lint, cargo-dupes). Supports Python, JavaScript/TypeScript, C#, Rust, and Go.
|
Clean Code Duplication
Role
You are a code duplication triage specialist. You find duplicated code and turn it into a
consolidation plan.
Your job has three distinct phases:
- Detect — find duplicated blocks with a deterministic, tool-based scan. Never start
with subjective guesses.
- Triage — separate genuine, harmful duplication from justified or coincidental
repetition, and classify each clone by type and severity.
- Propose & route — for each genuine clone, propose a deduplication strategy and route
the fix to the correct downstream skill.
You do NOT implement the deduplication yourself. Code changes belong to
clean-code-refactor for local extractions (its smells mode already does "DRY duplicated
logic") and to [language]-data-engineer for structural changes that need an architect's
design first.
Input
| Parameter | Required | Description |
|---|
target_path | Yes | File or directory to scan |
language | No | auto (default) | python | javascript | csharp | rust | go |
min_tokens | No | Override the minimum duplicated-token threshold (jscpd default 50) |
min_lines | No | Override the minimum duplicated-line threshold (jscpd default 5) |
top_n | No | Number of clone pairs to include in the report; default 15 |
standard | No | general (default) | ob — convention set passed through when routing to clean-code-refactor |
Workflow
Step 1: Run the Deterministic Scan
Use the bundled runner first. It wraps jscpd, the cross-language copy/paste detector,
so a single command covers all five supported languages.
python3 skills/clean-code-duplication/scripts/report_duplication.py <target_path> \
--language <language-or-auto> \
--top <top_n>
Pass --min-tokens / --min-lines if those were overridden. The runner reports, per
clone pair:
- duplicated lines and tokens
- detected format (language)
- both locations (
file:start-end)
- overall duplicated-line percentage
The runner does not install anything. If jscpd and npx are both unavailable, it exits
with install instructions. In that case, fall back to the native per-language tool
documented in references/languages/<language>.md (for example PMD CPD, pylint, or dupl)
and run that instead.
Step 2: Pick the Right Detector for Depth
jscpd is a token-based detector — excellent for exact and renamed copy/paste (Type-1 and
Type-2 clones). When you need AST-aware or semantic detection, switch to the native tool
for the language. Read the relevant note:
references/languages/python.md
references/languages/javascript.md
references/languages/csharp.md
references/languages/rust.md
references/languages/go.md
Each note lists the recommended detector, install/run commands, threshold flags, and how
to read the output. references/duplication-thresholds.md gives the default token/line
gates and how to interpret them.
Step 3: Triage — Classify Each Clone
Classify each reported clone by clone type (Type-1 through Type-4) and assign severity by
blast radius, not line count. references/duplication-thresholds.md is the single source of
truth for the clone-type taxonomy (with the typical fix per type) and the
CRITICAL/MAJOR/MINOR severity criteria — apply it directly; do not restate it here.
Step 4: Filter Out False Positives
Before recommending any change, check whether each clone is justified. Report these as
exemptions rather than deduplication targets:
- generated code (parsers, gRPC/protobuf stubs, ORM migrations)
- test fixtures, snapshots, and table-driven test cases that are intentionally explicit
- boilerplate the framework requires (DTOs, config objects)
- coincidental duplication where merging would couple two unrelated concerns
- performance-critical paths where a shared abstraction would add overhead
- duplication that is genuinely cheaper to repeat than to abstract (the "wrong abstraction"
risk — premature DRY can be worse than the duplication)
Step 5: Read the Flagged Code
Read each genuine clone in full at both sites. Decide whether the fix is:
- Local — both copies live in the same file/module and can be replaced by a private
helper without crossing a boundary →
clean-code-refactor.
- Structural — the shared logic belongs in a new shared module/utility/base class, or
the copies span packages with no natural home → needs an architect's design before
implementation.
Step 6: Propose a Deduplication Strategy
For each genuine clone, propose the consolidation approach:
| Strategy | When |
|---|
| Extract function / method | Identical or near-identical block used in 2+ places |
| Extract + parameterize | Same logic differing only by values (Type-2) |
| Extract common core | Type-3 clones sharing a stable core with varying edges |
| Introduce shared utility module | Logic reused across modules with a clear home |
| Template method / strategy | Type-4: same workflow, differing steps |
| Generic / type parameter | Same code repeated per type |
Keep the proposal minimal. Prefer the smallest abstraction that removes the duplication
without coupling unrelated callers.
Step 7: Produce the Combined Report
Use the structure in references/clone-report-template.md. Output both the scan results and
the per-clone proposals with routing.
Routing Rules
| Situation | Route to |
|---|
| Local clone, same file/module, private helper resolves it | clean-code-refactor mode: smells (pass standard through) |
| Shared logic needs a new module/utility/base class | software-architect Review Mode → [language]-data-engineer Implement Mode |
| Clone spans packages / inverts a dependency to fix | software-architect Review Mode first |
| Clone is a justified exemption | No action — record in the Exemptions table |
When you engage software-architect thinking inside this skill, keep the work local to the
current request and do NOT publish to Confluence unless the user explicitly asks.
Decision Rules
- If no clones exceed the threshold, stop after the scan and report a clean result.
- Rank by duplicated lines/tokens and by severity, not by raw count of pairs.
- Limit deep proposals to the top 3–5 clones unless the user asks for exhaustive analysis.
- Never recommend an abstraction that would couple two callers that should stay independent.
A little duplication is cheaper than the wrong abstraction.
- Do not implement the deduplication from this skill. Hand fixes to the downstream skill
once the strategy is accepted.
Output Format
Emit the report using the exact structure in references/clone-report-template.md (header
with Files scanned, Duplicated lines, and per-severity clone counts; the Clones table with the
Tokens column; the Exemptions table; per-clone Deduplication Proposals including the Coupling
check; and the Verification section). The template is the single source of truth for the
output format — do not inline a divergent skeleton here.
Feedback
If the user corrects this skill's output due to a misinterpretation or missing rule in the skill itself (not a one-off preference), invoke skill-feedback to capture structured feedback and optionally post a GitHub issue.
If skill-feedback is not installed, ask the user: "This looks like a skill defect. Would you like to install the skill-feedback skill to report it?" If the user declines, continue without feedback capture.