Uncomplex Analyzer
Detect complexity → understand intent → replace with libraries or simplify.
Quick Run
# Python
radon cc <file_or_dir> -s --min C
# JS/TS
bunx eslint <file_or_dir> --rule 'complexity: [error, 15]' --format json
Workflow
1. Detect (tools do the work)
Cyclomatic complexity:
# Python — install once: pip install radon
radon cc <directory> -s -j --min C | jq '.'
radon hal <file> # Halstead: effort > 500 = hard to read
# JS/TS
bunx eslint <directory> --rule 'complexity: [error, 15]' --format json
Circular dependencies:
# Python — install once: pip install pydeps
pydeps <directory> --no-output --show-cycles
# JS/TS
bunx madge --circular <directory>
Duplication:
bunx jscpd . --threshold 5 --reporters console --ignore "**/*.json,**/*.md,**/*.lock,**/node_modules/**"
Thresholds: CC 15+ = review. CC 20+ = strong replacement candidate. CC 25+ = split or replace.
2. Analyze Intent
For each complex function, answer: what is this trying to accomplish? (not how)
Then check if someone already solved it:
| Code Pattern | Intent | Python | JS/TS |
|---|---|---|---|
| Manual base64 + HMAC | JWT auth | pyjwt |
jose |
| Nested retry loops | Retry with backoff | tenacity |
p-retry |
| Date string parsing | Date manipulation | pendulum |
dayjs |
| Deep object merging | Object utilities | deepmerge |
lodash/merge |
| Manual HTML parsing | Web scraping | beautifulsoup4 |
cheerio |
| Regex-heavy validation | Schema validation | pydantic |
zod |
| Hand-rolled state machine | FSM / workflow | transitions |
xstate |
| Manual CSV/Excel parsing | Tabular data | pandas |
papaparse |
| Custom caching logic | Cache with TTL/LRU | cachetools |
lru-cache |
| Manual rate limiting | Rate limiter | ratelimit |
bottleneck |
| Hand-rolled queue | Task queue | celery, rq |
bull |
| Custom logging format | Structured logging | structlog |
pino |
| Subprocess orchestration | Task runner | invoke |
execa |
If the pattern isn't in this table, search:
~/.pi/agent/skills/github-quality-search/github_search.py \
"<intent keywords>" -l <language> -s 100 -n 3 --json
Quality gates: 100+ stars, MIT/Apache/BSD, commit in last 6 months, has docs.
3. Decide: Replace or Refactor?
Replace when the problem is generic (dates, HTTP, validation, parsing) and a quality library exists.
Refactor when logic is domain-specific or a library would be overkill. Keep it simple:
- God function → split into named helpers
- Nested closures → LibCST codemod to unnest + Rope to move (see python skill, Part 7)
- God module (1000+ lines) → Rope to move top-level symbols to separate modules
- Deep nesting → guard clauses + early returns
- Copy-paste → extract shared function
- 5+ params → config object
Leave alone when:
- Low churn (stable, not causing bugs)
- Domain complexity (the problem IS complex)
- Intentional — comments explain why, perf-critical path, no-dependency policy
4. Report
Create uncomplex-report-YYYYMMDD.md with:
- Summary stats (files scanned, high-complexity count)
- Each finding: location, complexity score, intent, recommendation (library or refactoring)
- Library replacements table (name, stars, license, migration effort)
- Top 3 priorities
Cross-References
- Prioritize targets:
hotspot-detective(high churn + high complexity = act first) - Clean up after:
dead-code-reaper - Library discovery:
github-quality-search
Combo: hotspot-detective → uncomplex-analyzer → dead-code-reaper
Dependencies
pip install radon pydeps # Python
# JS/TS: bunx eslint, bunx jscpd, bunx madge (zero-install)