Complexity Budgets
Use this skill when functions are hard to understand because they branch too much, nest too deeply, take too many parameters, or own too many responsibilities.
Workflow
Run the repository's existing formatter and linter first.
If a repository is indexed by CodeGraph, use
codegraph-worktree-startupfor navigation and blast radius before selecting files to measure. CodeGraph finds the code; complexity analyzers score it.Run the appropriate language analyzer to find hotspots before choosing a threshold:
# Python complexipy . --top 20 --sort desc complexipy . --max-complexity-allowed 10 --failed --suggest-refactors # TypeScript / JavaScript, when @genese/complexity is installed complexity src genese cpx src --language ts --consoleFor changed-code checks, prefer the repository's base reference or staged diff when the tool supports it:
complexipy . --diff main complexipy . --staged=trueAdd the smallest rule that catches the problem — cyclomatic complexity, cognitive complexity, max nesting depth, max function length, or max parameter count — not all of them.
Set the first threshold to the current worst offender, so it stops new outliers without forcing a cleanup PR. For cyclomatic complexity, a starting threshold of 10 is the conventional default across the linters below; raise it to fit existing debt, then ratchet down.
Add focused tests around a complex function before reducing its complexity.
Lower a threshold only after the code is already below the new value.
Tool Bindings
Each tool's cyclomatic-complexity check defaults to a limit near 10 — a sound starting point before ratcheting:
- Python: Ruff with McCabe (
C901) for cyclomatic complexity;complexipyfor cognitive complexity, diff reports, and refactor suggestions. - TypeScript and JavaScript: ESLint
complexityandmax-depth; use typescript-eslint where type information matters. When thecomplexityCLI from@genese/complexityis available, use it for cognitive and cyclomatic reports overts,js,tsx, andjsxcode. - TypeScript hotspot scans:
fta-cliis a good fast file-level triage tool when the repository already uses it, but do not substitute a file-level score for function-level thresholds when a function budget is needed. - Go: golangci-lint with
gocycloorgocognit. - Java: Checkstyle complexity checks plus SpotBugs for bug patterns.
- Kotlin: detekt complexity rules.
- Shell: ShellCheck plus shfmt; extract shell functions once branches grow.
Review Checks
- The rule runs in CI and blocks only changed or newly violating code when the repository has existing debt.
- CI should invoke the same language analyzer used during review. Python CI may
use
complexipyJSON, GitLab, or SARIF output; TypeScript/JavaScript CI may usecomplexity/genese cpxreports or ESLint complexity rules, depending on whether the budget is cognitive, cyclomatic, or both. - Suppressions are rare, local, and include a reason.
- Complexity reduction does not remove behavior coverage.