A GitHub Copilot agent plugin that finds needlessly complex code, proves a simpler version is equivalent, rewrites it, and then vaccinates the repository so the next agent run doesn't reintroduce the complexity.
AI writes code that works and nobody can read. Uncomplicator measures the damage against published complexity standards, proves a simpler version is behaviourally and performance-identical, rewrites it in revertible batches, and patches your repo's instruction files so the next agent run starts simple.
Python 3.9 or later must be on your PATH as python or py.
This is not optional. The scanner is what separates measured complexity from an agent's opinion about complexity, and every stage depends on it — Discover ranks by it, Apply gates on it, and the ratchet hook runs it on every edit. Without Python the plugin installs cleanly and then cannot measure anything.
Check with python --version.
Everything else degrades gracefully — see optional analysers below.
VS Code — one command:
Ctrl+Shift+P → "Chat: Install Plugin From Source"
→ https://github.com/vibeCoder500/UnComplicator
GitHub Copilot CLI:
copilot plugin marketplace add vibeCoder500/UnComplicator
copilot plugin install uncomplicator@uncomplicatorVS Code auto-discovers plugins installed by the CLI, so that one command covers both.
Optional analysers — the scanner works without them, with reduced coverage:
pip install -r scripts/requirements.txt # lizard (15+ languages), radon
npx jscpd --version # duplication, no install neededMissing optional tools narrow what gets measured; they never produce a wrong number.
Languages with no analyser path are reported in scorecard.tier_b_languages and their
findings are marked Tier B, which cannot gate a change.
Pick Uncomplicator Discover from the agents dropdown, or type
/uncomplicator:complexity-scan. Then click through the handoff buttons:
Discover → Plan → Verify → Apply → Inoculate
You approve every stage boundary. Nothing edits source until Verify has built a safety net and Apply has passed every gate.
| Mode | Writes | What it guarantees |
|---|---|---|
| Discover | .uncomplicator/findings.* |
Read-only. Ranked, evidence-backed inventory using published metrics. Classifies every finding essential or accidental with a written justification. |
| Plan | .uncomplicator/plan.* |
Names a catalogued, behaviour-preserving transformation per finding. Drops anything that doesn't lower the number. |
| Verify | tests, .uncomplicator/verification.* |
Builds characterization tests, validates them with mutation scoring, snapshots the public API, captures benchmarks. Rejects what it cannot cover. |
| Apply | source, .uncomplicator/report.md |
Atomic batches gated on build, lint, tests, API diff, benchmark, and metric delta. Reverts on any failure. |
| Inoculate | agent-steering files | Patches copilot-instructions.md, AGENTS.md, CLAUDE.md, instructions files, linter configs, CI — idempotently. |
Not by vibes. Every threshold traces to a published standard:
| Metric | Limit | Source |
|---|---|---|
| Cognitive complexity | 15 | SonarSource S3776 (Campbell 2018) — the primary metric |
| Cyclomatic complexity | 10 | McCabe 1976 / NIST SP 500-235 |
| Nesting depth | 3 | ESLint max-depth, Linux kernel style |
| NPath | 200 | Nejmeh 1988 / PMD default |
| Maintainability Index | ≥ 20 | Visual Studio Code Metrics |
| Duplicated lines | < 3% | SonarQube quality gate |
Plus an 18-pattern AI-slop catalogue (AS-01…AS-18) covering speculative
generality, pass-through layering, defensive over-validation, catch-log-rethrow ladders,
near-clones, reinvented stdlib, arrow code, async theatre, and more.
Fred Brooks distinguished essential complexity (inherent in the problem, irreducible) from accidental complexity (introduced by how we expressed it, removable).
Uncomplicator only removes accidental complexity. Every finding must carry a written justification for why it is accidental — a finding without one is rejected by schema validation, not merely unpolished.
Anything can delete code. Knowing when not to is the product.
Six independent layers, none trusted alone:
- Closed transformation set — named, catalogued refactorings only. Never a creative rewrite.
- Precondition checks — each transformation's own, plus six universal ones.
- Test safety net — characterization, golden master, property-based, differential.
- Mutation score — proves the net is sensitive. A green suite means nothing if the tests can't detect change.
- Public API diff — catches contract breakage no test exercises.
- Gated atomic batches — one transformation per commit, revert on any gate failure.
Plus ten performance invariants checked statically, before any benchmark runs. No asymptotic change, no work moved into a loop, no lazy→eager conversion, no removed caching, no allocation in a hot path, no altered async semantics. A refactoring that violates one is rejected however much cleaner it reads.
- Change observable behaviour, error types, or serialisation formats
- Fix a bug (it reports them; the refactored code reproduces them exactly)
- Delete, skip, or weaken a test
- Bypass a gate — no
--no-verify, no lowered thresholds, no suppression comments - Add, remove, or upgrade a dependency
- Touch auth, crypto, secrets, audit logging, generated code, vendored code, or migrations
- Auto-fix a swallowed exception or async-semantics change (both are R3, human-approved)
plugin.json Agent Plugins 1.0 manifest
skills/ Portable — works in any conformant client
complexity-standards/ Metrics, thresholds, rubric, findings schema
ai-slop-patterns/ AS-01..AS-18 with detection and fixes
safe-refactoring-catalogue/ Transformations, preconditions, perf invariants
behavior-preservation-harness/ Safety-net recipes and templates
complexity-scan/ Runnable scan (slash command)
agent-steering-discovery/ Find and patch instruction files
com.github.copilot/ Copilot-specific
agents/ The five modes, chained with handoffs
hooks/hooks.json PostToolUse complexity ratchet
scripts/
scan.py Deterministic scanner
ratchet.py Hook entry point
uncx/ Cognitive complexity engine, analysers, scoring
templates/ config.default.yml, CI gate
fixtures/fixture-ts-slop/ Evaluation fixture + answer key
python scripts/scan.py --root . --out .uncomplicator
python scripts/scan.py --file src/orders/OrderProcessor.ts --jsonTwo deterministic paths, both Tier A:
- Python — exact, over the
astmodule. - Brace languages — comment- and string-stripped token scanner; uses
lizardfor function boundaries when installed, falls back to a built-in detector otherwise.
Every metric records which tool produced it. Where no analyser exists, findings are marked Tier B (estimate) and may prioritise but never gate.
Uncomplicator grades its own scanner C. Two of its three hotspots are the tokenizer
in uncx/cognitive.py — a lexer is inherently branchy, which is essential complexity,
not accidental. That is the distinction the whole plugin is built on, visible in its own
source.
hooks.json registers a PostToolUse hook. After any edit, the file is re-scored
against .uncomplicator/baseline.json and a warning is printed if cognitive complexity
increased.
Instructions guide the model and dilute over a long conversation. A hook runs
regardless of whether the model remembered. Switch --warn-only to --block in
com.github.copilot/hooks/hooks.json to make it refuse the edit.
- Agent files deliberately omit a pinned
model:. Add one to the frontmatter if you want a specific model; the default follows your model picker. complexity-scanusescontext: fork, which needsgithub.copilot.chat.skillTool.enabled. Without it the skill still runs inline.- Prompt files are deprecated for Agent Host. This plugin is built on skills and agents, so nothing here needs migrating.
MIT