Skip to content

Commit 7a84413

Browse files
add tech debt finder
1 parent cf28ef7 commit 7a84413

File tree

1 file changed

+272
-0
lines changed

1 file changed

+272
-0
lines changed
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
---
2+
name: tech-debt-finder
3+
description: >
4+
Use when the user says "find tech debt", "audit code quality", "what needs cleanup",
5+
"show me debt", "code health check", "scan for smells", or wants a comprehensive
6+
quality assessment before planning a refactor or sprint.
7+
argument-hint: "[path/to/scope or 'full']"
8+
allowed-tools: Bash, Read, Glob, Grep, Agent
9+
---
10+
11+
# Tech Debt Finder
12+
13+
Scans the codebase for architectural and code-level technical debt, producing a prioritized report and creating a GitHub issue with actionable findings.
14+
15+
**Announce at start:** "Using tech-debt-finder to scan for technical debt..."
16+
17+
---
18+
19+
## Configuration
20+
21+
| Setting | Default | Description |
22+
|------------------------|----------------------------|---------------------------------|
23+
| **Scope** | `$ARGUMENTS` or repo root | Directory to scan |
24+
| **nesting_depth** | 4 | Deep nesting threshold |
25+
26+
---
27+
28+
## Execution Flow
29+
30+
### Step 1: Resolve Scope
31+
32+
Parse `$ARGUMENTS`:
33+
- If a path is provided, scope all scans to that directory
34+
- If empty or `full`, scan from repo root
35+
- Identify all Python packages (look for `pyproject.toml` or `src/` dirs)
36+
- Exclude: `node_modules/`, `.venv/`, `__pycache__/`, `build/`, `dist/`, `.git/`
37+
38+
### Step 2: Dispatch Parallel Scanners
39+
40+
Launch **3 agents in parallel** using the Agent tool. Each agent receives the resolved scope path and configuration. Each agent returns structured findings as a list of `{category, item, severity, detail, file, line}`.
41+
42+
Each agent is free to use whatever detection approach works best — grep, AST parsing, external tools (radon, ruff, pip-audit), file reading, or any combination. The goal is accurate detection, not a specific technique.
43+
44+
**Calibration:** This codebase generally follows established practices (DRY, single responsibility, explicit error handling). Set a high bar for findings — flag genuine violations, not borderline cases.
45+
46+
---
47+
48+
**Agent A — Dependency & Environment Scanner**
49+
50+
Detect debt in these categories:
51+
52+
| Debt Type | What It Looks Like | Severity |
53+
|-----------|--------------------|----------|
54+
| **Known CVE** | A dependency has a published security vulnerability (use `pip-audit` or `safety` if available) | Critical |
55+
| **Outdated dependency** | Package >1 major version behind latest | High |
56+
| **Outdated dependency** | Package >1 minor version behind latest | Medium |
57+
| **Unused dependency** | Dependency declared in `pyproject.toml` but never imported in source or tests | Low |
58+
| **Circular dependency signal** | `if TYPE_CHECKING:` blocks or function-level imports used as circular import workarounds | Medium |
59+
| **Pinning gap** | Dependency with no upper bound on major version (e.g. `>=2.0` with no `<3`) | Low |
60+
61+
Return findings with category `dependency`.
62+
63+
---
64+
65+
**Agent B — Structural & Complexity Scanner**
66+
67+
Detect debt in these categories:
68+
69+
| Debt Type | What It Looks Like | Severity |
70+
|-----------|--------------------|----------|
71+
| **God module** | Python file that is excessively long — too many responsibilities in one module | High |
72+
| **High cyclomatic complexity** | Function with complexity >= 16 (use `radon` if available) | High |
73+
| **Moderate cyclomatic complexity** | Function with complexity 11–15 | Medium |
74+
| **Deep nesting** | Code indented beyond `nesting_depth` levels | Medium |
75+
| **Business logic leakage** | ORM/DB calls, HTTP client calls, or validation logic in controller/handler/view files instead of the appropriate layer | High |
76+
| **Import direction violation** | Lower layer importing from higher layer (e.g. models importing from providers, utils importing from domain code) | High |
77+
| **Code duplication** | Substantial blocks of near-identical code across files — same logic with only minor variations (variable names, literals). Look for duplicated functions, repeated conditional chains, and copy-pasted blocks | Medium |
78+
79+
Return findings with category `architecture`, `complexity`, or `duplication`.
80+
81+
---
82+
83+
**Agent C — Code Pattern Scanner**
84+
85+
Detect debt in these categories:
86+
87+
| # | Debt Type | What It Looks Like | Example | Severity | Category |
88+
|---|-----------|-------------------|---------|----------|----------|
89+
| 1 | **Bare except** | `except:` with no exception type — catches SystemExit, KeyboardInterrupt | `except:\n pass` | Critical | error-handling |
90+
| 2 | **Swallowed exception** | `except Exception` where the body is only `pass` or `continue` — no logging, no re-raise | `except Exception:\n pass` | High | error-handling |
91+
| 3 | **Generic catch without re-raise** | `except Exception` block that never re-raises — callers never know the operation failed | `except Exception as e:\n logger.error(e)` | Medium | error-handling |
92+
| 4 | **Any overuse** | `-> Any` or `: Any` in non-test files, especially `dict[str, Any]` where a TypedDict/model would be better | `def get_config() -> Any:` | Medium | code-smell |
93+
| 5 | **Blocking call in async** | `time.sleep`, synchronous `requests.*`, or blocking file I/O inside an `async def` | `async def fetch():\n time.sleep(5)` | High | async |
94+
| 6 | **Mutable default argument** | `def f(x=[])` or `def f(x={})` — the default is shared across all calls, a correctness bug | `def add(item, items=[]):` | High | code-smell |
95+
| 7 | **Magic numbers** | Numeric literals >2 digits in non-test source, excluding common constants (0, 1, 100, HTTP status codes) | `timeout = 8473` | Medium | code-smell |
96+
| 8 | **Dead code — commented out** | Commented-out function defs, imports, returns, or class definitions. Git has the history | `# def old_handler():` | Low | code-smell |
97+
| 9 | **Global mutable state** | Module-level mutable collections (dicts, lists, sets) that get mutated at runtime — thread-safety risk in async contexts | `CACHE = {}\n...\nCACHE[key] = val` | Medium | code-smell |
98+
99+
Return findings with their respective categories.
100+
101+
---
102+
103+
### Step 3: Collect & Classify
104+
105+
Merge all agent results into a single list. Classify by severity:
106+
107+
| Severity | Criteria |
108+
|-------------|---------------------------------------------------------------------------|
109+
| **Critical** | Known CVEs, bare `except:` with `pass` |
110+
| **High** | God modules, swallowed exceptions, blocking in async, layer violations, mutable defaults |
111+
| **Medium** | High complexity (radon), `Any` overuse, deep nesting, magic numbers, duplication |
112+
| **Low** | Unused deps, commented-out code |
113+
114+
**Deduplication:** If the same `file:line` appears in multiple categories, keep the highest severity instance.
115+
116+
**Sorting:** Within each severity group, sort by file path then line number.
117+
118+
### Step 4: Print Report to Terminal
119+
120+
Output the report directly to the user:
121+
122+
```
123+
## Tech Debt Report — {scope}
124+
**Scanned:** {file_count} files | **Date:** {YYYY-MM-DD}
125+
**Findings:** {critical} critical, {high} high, {medium} medium, {low} low
126+
127+
### Critical ({count})
128+
| File | Line | Finding | Category |
129+
|------|------|---------|----------|
130+
| ... | ... | ... | ... |
131+
132+
### High ({count})
133+
| File | Line | Finding | Category |
134+
|------|------|---------|----------|
135+
| ... | ... | ... | ... |
136+
137+
### Medium ({count})
138+
| File | Line | Finding | Category |
139+
|------|------|---------|----------|
140+
| ... | ... | ... | ... |
141+
142+
### Low ({count})
143+
| File | Line | Finding | Category |
144+
|------|------|---------|----------|
145+
| ... | ... | ... | ... |
146+
147+
### Summary
148+
149+
| Category | Critical | High | Medium | Low | Total |
150+
|-----------------|----------|------|--------|-----|-------|
151+
| dependency | ... | ... | ... | ... | ... |
152+
| architecture | ... | ... | ... | ... | ... |
153+
| complexity | ... | ... | ... | ... | ... |
154+
| error-handling | ... | ... | ... | ... | ... |
155+
| code-smell | ... | ... | ... | ... | ... |
156+
| async | ... | ... | ... | ... | ... |
157+
| duplication | ... | ... | ... | ... | ... |
158+
159+
### Hotspots (files with 3+ findings)
160+
161+
| File | Findings | Highest Severity |
162+
|------|----------|------------------|
163+
| ... | ... | ... |
164+
```
165+
166+
### Step 5: Create GitHub Issue
167+
168+
Automatically create a GitHub issue with the findings. No confirmation needed.
169+
170+
**5a. Ensure the `tech-debt` label exists:**
171+
172+
```bash
173+
gh label create "tech-debt" --color "D93F0B" --description "Technical debt findings" 2>/dev/null || true
174+
```
175+
176+
**5b. Build the issue body.**
177+
178+
Format every finding as a checkbox so the team can track resolution:
179+
180+
```markdown
181+
# Tech Debt Audit — {scope}
182+
183+
**Scanned:** {file_count} files | **Date:** {YYYY-MM-DD}
184+
**Findings:** {critical} critical, {high} high, {medium} medium, {low} low
185+
186+
---
187+
188+
## Critical
189+
- [ ] `file.py:42` — Known CVE in dependency X *(dependency)*
190+
- [ ] `file.py:88` — Bare `except:` with `pass` *(error-handling)*
191+
192+
## High
193+
- [ ] `provider.py` — God module, too many responsibilities *(architecture)*
194+
- [ ] `handler.py:55` — Exception swallowed, no re-raise *(error-handling)*
195+
- [ ] `utils.py:30``time.sleep` inside `async def` *(async)*
196+
197+
## Medium
198+
- [ ] `api.py:120` — Cyclomatic complexity 14 *(complexity)*
199+
- [ ] `models.py:45``-> Any` return type *(code-smell)*
200+
- [ ] `config.py:33` — Magic number `8473` *(code-smell)*
201+
- [ ] `handlers.py` + `views.py` — Near-identical request validation logic *(duplication)*
202+
203+
## Low
204+
- [ ] `utils.py:10` — Commented-out function definition *(code-smell)*
205+
206+
---
207+
208+
## Summary
209+
210+
| Category | Critical | High | Medium | Low | Total |
211+
|----------|----------|------|--------|-----|-------|
212+
| ... | ... | ... | ... | ... | ... |
213+
214+
## Hotspots (files with 3+ findings)
215+
216+
| File | Findings | Highest Severity |
217+
|------|----------|------------------|
218+
| ... | ... | ... |
219+
220+
## Recommended Actions
221+
222+
1. **Critical** — fix immediately, security/correctness risks
223+
2. **High** — schedule for current sprint, use `/refactor` for code-level fixes
224+
3. **Medium** — plan for next sprint, use `/planning` for architectural items
225+
4. **Low** — address opportunistically during related work
226+
```
227+
228+
**5c. Handle body size limit.**
229+
230+
GitHub issues have a 65536 character body limit. If the body exceeds 60000 characters:
231+
1. Truncate **Low** findings first, replacing with `- [ ] ... and {N} more low-severity findings`
232+
2. If still too large, truncate **Medium** findings similarly
233+
3. Never truncate Critical or High findings
234+
235+
**5d. Create the issue:**
236+
237+
```bash
238+
gh issue create \
239+
--title "Tech Debt Audit — {YYYY-MM-DD} — {scope}" \
240+
--label "tech-debt" \
241+
--body "$(cat <<'EOF'
242+
{issue body}
243+
EOF
244+
)"
245+
```
246+
247+
**5e. Print the issue URL** to the user after creation.
248+
249+
---
250+
251+
## Error Handling
252+
253+
| Scenario | Action |
254+
|----------|--------|
255+
| `radon` not installed | Skip complexity checks. Note in report: "Complexity checks skipped — install `radon`" |
256+
| `pip-audit` not installed | Skip CVE checks. Note in report: "CVE checks skipped — install `pip-audit`" |
257+
| Scope path doesn't exist | Report error and **stop** |
258+
| No Python files in scope | Report "no files to scan" and **stop** |
259+
| An agent fails | Report partial results from successful agents. Note which scanner failed and why |
260+
| `gh` not authenticated | Print report to terminal. Warn: "GitHub issue creation skipped — run `gh auth login`" |
261+
| Issue body exceeds limit | Truncate Low then Medium findings (see Step 5c) |
262+
263+
---
264+
265+
## What This Skill Does NOT Do
266+
267+
- Does not fix debt — use `/refactor` or `/orchestrate` for that
268+
- Does not replace `ruff` or `pyright` — complements them with higher-level analysis
269+
- Does not run tests or measure coverage — use `/coverage-guard` for that
270+
- Does not modify any source files
271+
- Does not track debt over time — each run is a fresh scan
272+
- Does not analyze git history for bug hotspots

0 commit comments

Comments
 (0)