Skip to content
| Marketplace
Sign in
Visual Studio Code>Linters>CleanLensNew to Visual Studio Code? Get it now.
CleanLens

CleanLens

MusaAlahmed

|
3 installs
| (0) | Free
Local Git-based Clean Code analysis. Replays each commit to attribute every violation to the developer who actually introduced it (not whoever last touched the file), and gives each developer a fair, shrinkage-adjusted quality score. Dashboard + inline diagnostics + CLI. Docs in English & Arabic.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

CleanLens

English · العربية

Fair, local Clean Code analysis for a Git repository. CleanLens replays your commit history — comparing each file before and after every commit — so each code smell is charged to the developer who actually introduced it, never to whoever last touched the file. Every developer gets a quality score based on the density of the issues they introduced per 1,000 lines they wrote, with Bayesian shrinkage so a small sample can't inflate it. Quality and contribution volume are always shown separately.

  • Runs entirely on your machine — no source code or developer data leaves it, no sign-in.
  • Interactive dashboard + inline editor diagnostics as you type.
  • A cleanlens CLI with the same report for team reports, CI and pre-commit gates.
  • Docs in English & Arabic.

CleanLens dashboard — per-developer Clean Code Score, confidence, contribution and a violations table with attribution status

How it works

  1. Git checks & rules — confirms it's a repo with commits, loads .clean-code-tracker.json (or a built-in preset).
  2. Scan — 14 Clean Code rules for JS/TS/JSX/TSX (AST) and Python (heuristic), plus duplicate-code detection.
  3. Replay the history — walks the newest 500 commits (configurable), and for every changed file diffs it --unified=0 -w -M -C and analyses the version before and after the commit. A stable per-violation fingerprint (rule + path + symbol + normalized context) matches issues across line-number churn.
  4. Classify & attribute — a violation is introduced (charged to the commit author) only when it first appears on lines that commit changed (high confidence) or in a symbol it modified (medium); otherwise existing (never charged), fixed (credited), excluded or unattributed.
  5. Score — per developer, per category: score = 100·e^(−adjustedDensity / scale) where adjustedDensity is the weighted introduced-violation points per 1,000 lines they wrote, shrunk toward the project mean; final = duplication·0.30 + structure·0.45 + hygiene·0.25. Confidence and a "not ranked" flag come from how much code they wrote. Results are cached per commit, so re-runs only analyse new commits.

Everything is configurable

  • Clean Code rules — enable/disable each of the 14 rules, set its severity (low/medium/high/critical) and its threshold in .clean-code-tracker.json (committed, team-wide) or a personal .clean-code-tracker.local.json override. Presets for JavaScript, React, Python and Django.
  • Scoring & analysis — tune the severity weights, the per-category scales, the 0.30 / 0.45 / 0.25 category weights, the ranking threshold, the commit window (maxCommits / since) and every exclusion list — from .clean-code-tracker.json or from VS Code settings (cleanlens.*, see Settings).
  • Exclusions — sensible defaults (node_modules, dist, build, generated files, lock files, migrations…) are merged with your own globs, .gitignore and linguist-generated markers — never replaced.

Full documentation, the exact formulas and the pipeline walkthrough are on GitHub.


Overview

Analyzes a Git repository entirely on your machine, shows every contributor and their activity, and — by replaying each commit and comparing the code before and after — attributes each Clean Code violation to the developer who actually introduced it (not whoever last touched the file). Each developer gets a fair quality score based on the density of the smells they introduced per 1,000 lines they wrote, with Bayesian shrinkage so a tiny sample can't game it.

It ships as two front-ends over one analysis core:

  • a VS Code extension — an interactive dashboard, plus inline diagnostics that underline violations in the editor as you type;
  • a cleanlens CLI — the same report as text or JSON, for team reports, CI, and pre-commit gates.

Privacy: all analysis runs locally. No source code and no developer data ever leaves your machine, and no sign-in is required. See docs/PRIVACY.md.


Table of contents

  • What it produces
  • Two ways to run it
  • Quick start
  • How it works — the pipeline
    • 1. Git checks
    • 2. Loading the rules
    • 3. Extracting developers
    • 4. Scanning the code
    • 5. Attributing violations per commit
    • 6. Scoring
    • 7. Display
  • The 14 rules in detail
  • Configuration file
  • VS Code commands
  • Inline editor diagnostics
  • Settings
  • CLI manual
  • Performance
  • Limitations you must communicate to your team
  • Contributing

What it produces

A report with project-level totals and a card per developer:

Developers: 5
Analyzed files: 287
Analyzed commits: 480
Total violations: 124
Unattributed: 3

Musa
  Clean Code Score: 73/100
    duplication 88 · structure 72 · hygiene 78
  Analyzed Lines: 3,140
  Confidence: Reliable
  Contribution: 42%
  New Violations: 39
  Fixed Violations: 12
  Existing Violations: 51 (informational)
  Unattributed Violations: 0 (informational)
  Weighted Violations: 118
  Net Quality Impact: +27
  Violation Density: 37.58 / KLOC
  Active days: 24

The score is a weighted mean of three per-category sub-scores (duplication ×0.30 + structure ×0.45 + hygiene ×0.25) so a problem in one dimension does not read as an across-the-board failure. Only violations a developer introduced (with high/medium confidence) count; existing, excluded and unattributed ones are informational. Contribution (how much code you wrote) is shown next to the score but never mixed into it. A developer with no analysed code scores —, not 100, and one below the ranking threshold (1,000 analysed lines by default) is shown but not ranked.

In the extension, clicking any violation opens the file at the exact line. In the CLI, the same numbers are printed to stdout (or emitted as JSON).


Two ways to run it

VS Code extension cleanlens CLI
Best for a developer at work — see your own violations, click to open the file scheduled team reports, CI, pre-commit gates
Output interactive dashboard: cards, search, severity filters text or --json on stdout
Needs the project open in VS Code one command; runs headless on a server
Automation no yes — --fail-on returns a non-zero exit code
Entry point src/extension.ts src/cli/index.ts

Both call the same function, analyzeRepository — identical rules, identical numbers.


Quick start

In VS Code

  1. Open a folder that contains a Git repository.
  2. Run CleanLens: Initialize Project from the Command Palette — it detects the project type, proposes a rule preset (JavaScript / React / Python / Django), and writes .clean-code-tracker.json after you confirm.
  3. Run CleanLens: Run Analysis.
  4. The Dashboard opens automatically; reopen it any time with CleanLens: Open Dashboard.

In the terminal

# from a package that has it installed
cleanlens

# or without installing (once published)
npx cleanlens --violations

If there is no .clean-code-tracker.json, the CLI falls back to built-in defaults (with a warning on stderr). Use --preset <name> to pick a different baseline without a config file.


How it works — the pipeline

Both front-ends call analyzeRepository(root, options). Seven steps run in order:

1. Git checks  →  2. Load rules  →  3. Extract developers
                        ↓
4. Scan code files (14 rules)  →  5. Attribute violations (walk each commit,
                        ↓            diff before/after, fingerprint & classify)
                   6. Score  →  7. Display (Dashboard / stdout)

Steps 1–6 are shared code with no VS Code dependency. Only step 7 differs between the extension and the CLI.

1. Git checks

src/git/gitService.ts

git rev-parse --is-inside-work-tree   # is this a repository?
git rev-parse HEAD                    # does it have any commits?

If either fails the analysis stops with a clear message (not a Git repo / no commits). In code this is an AnalysisError; the extension shows it as a notification, the CLI prints error: … to stderr and exits 2.

2. Loading the rules

src/configuration/configLoader.ts · src/configuration/configValidator.ts

  • Reads .clean-code-tracker.json from the project root (skipped when the CLI is given --preset).
  • Validates it: version must be 1, every rule name must be one of the known 14, every severity must be low|medium|high|critical, every limit must be a positive number, options must be numbers/booleans. Any error stops the analysis and is shown to you.
  • If .clean-code-tracker.local.json exists, its rules are merged on top of the official ones — this is per-developer and never changes the official report. It belongs in .gitignore.
  • If there is no config file at all, built-in defaults are used and a warning is emitted.

3. Extracting developers

src/git/contributors.ts

git log --no-merges --format="%aN|%aE|%aI"

Each line yields name · email · ISO date. Commits are grouped by lowercased email:

Field How it is computed
Active days the set of distinct calendar days (YYYY-MM-DD); 5 commits on one day counts as one day
First / last contribution min / max commit date

Merging duplicate identities. git log respects .mailmap. On top of that:

  • Contributors are merged into one developer automatically when they share any of: a display name (case-insensitive); a single-word username that differs only by trailing digits/punctuation (MUSAALAHMED4 ↔ MUSAALAHMED); or a distinctive email handle (ayman@work ↔ ayman@personal, or 1234+ayman@users.noreply.github.com). Emails, active days and commits are combined. Disable with cleanlens.mergeSameNameAuthors: false (or the same key in .clean-code-tracker.json).
  • Ambiguous cases the heuristics leave alone on purpose (e.g. Anas vs Anas Daas) — list them explicitly:
    "developers": [
      { "displayName": "Musa", "emails": ["musa@work.com", "12345+musa@users.noreply.github.com"] }
    ]
    
  • When a merge joins two different names, the developer is shown as "Primary Name - Other Name" (the earliest contributor's name first) so it is clear the identities were combined.

4. Scanning the code

4a. Choosing files — src/analyzers/fileScanner.ts

  • Walks the directory tree recursively.
  • Always skipped: .git, node_modules, .svn, .hg.
  • Skipped by exclude: each glob from the config is matched with the small matcher in src/analyzers/glob.ts (** → any path segment(s), * → within one segment, ? → one character). Patterns are tested against both the relative path and the file's basename.
  • Kept extensions: .js .jsx .mjs .cjs .ts .tsx .py.
  • Any file larger than 1 MB is skipped.

4b. Choosing an analyzer — src/analyzers/runAnalyzers.ts

By extension: JS/TS → jsAnalyzer, Python → pyAnalyzer. Each file is read as text and passed with the resolved config; the analyzer returns a list of RawFinding objects (rule id + file + line range + message).

4c. How each file is analyzed

JavaScript / TypeScript / JSX / TSX — real AST analysis using the TypeScript compiler (ts.createSourceFile with parent pointers), then a single recursive walk over every node. Function-like nodes checked: function declarations/expressions, arrow functions, methods, constructors, accessors.

  • Cyclomatic complexity starts at 1 and adds 1 for each if, for, for..in, for..of, while, do, non-empty case, catch, ternary ?:, and each && / || / ?? — without descending into nested functions (those are counted on their own).
  • Nesting depth is a counter incremented when entering if / for / while / do / switch; else if does not add a level.
  • Unused code: every identifier occurrence in the file is counted; a non-exported import / variable / function whose name appears only once (its declaration) is reported.

Python — there is no full AST; analysis is heuristic, based on indentation and text patterns (src/analyzers/pyAnalyzer.ts):

  • Block boundaries come from indentation (a block ends at the first line that dedents to ≤ the header indent).
  • Complexity ≈ 1 + count of if / elif / for / while / except / and / or inside the body.
  • except …: followed only by pass / ... = empty. print( / breakpoint( = debug statement. Nesting depth = indent ÷ 4.
  • Parameters are parsed from the def signature (ignoring self / cls / *args).
  • An import whose bound name never appears again = unused.

4d. Duplicate code — src/analyzers/duplicateCode.ts

Runs across all analyzed files together:

  1. Normalize every line (trim, collapse whitespace, drop comments and trivial lines like a lone }).
  2. Slide a window of 6 lines (configurable via options.minLines) and hash each window.
  3. Any hash seen in two different places → a duplication violation on the later occurrence, pointing at the first.

4e. From finding to violation — src/analyzers/model.ts

Each RawFinding becomes a Violation with a stable hash id (so the same issue is never counted twice), the severity taken from the config, and the file/line range. Violations are sorted by severity.

5. Attributing violations per commit

src/git/commitHistory.ts · src/git/diffService.ts · src/attribution/fingerprint.ts · src/attribution/commitAttribution.ts · src/attribution/attributeReport.ts

The engine walks the newest 500 non-merge commits (configurable — see Settings) oldest-first. For each commit, for each changed source file that is not excluded:

git diff --unified=0 -w -M -C <parent> <commit> -- <file>   # which lines changed (whitespace-insensitive, move/copy aware)
git cat-file --batch                                          # the before / after blobs (one spawn per commit)

Both revisions of the file are analysed with the same 14 rules. Every violation gets a stable fingerprint — hash(ruleId + normalizedPath + symbolName + normalizedCodeContext) — so it can be matched across line-number churn without using line numbers.

Compared before vs after Status Effect
fingerprint only in after, on a line the commit added/changed introduced · confidence high charged to the commit author
fingerprint only in after, overlapping a symbol the commit modified introduced · confidence medium charged to the commit author
fingerprint only in after, no evidence the edit caused it introduced · confidence low recorded, not scored
fingerprint only in before fixed credited to the commit author
fingerprint in both existing never charged to anyone
a revision could not be read/parsed unattributed informational only
the file is generated / vendored / ignored excluded not analysed at all

A HEAD violation that never appears entering an analysed commit predates the window → existing. A root commit (no parent) is diffed against the empty tree, so all of its code is genuinely new. Author emails map to developer ids via the developer list; .mailmap is applied by Git automatically.

Per-commit results are cached by commit hash (see Performance), so re-runs only analyse new commits. The cache is invalidated automatically when the rules, weights or exclusions change.

6. Scoring

src/scoring/scoringConfig.ts · src/scoring/cleanCodeScore.ts

Severity weights: low=1, medium=3, high=5, critical=8. Analyzed lines = the lines the developer actually added or modified across analysed files (not "lines they currently own").

Each developer is scored on the density of the violations they introduced (high/medium confidence only), per 1,000 analysed lines, per category:

Category Density Scale (density → ~37)
duplication (detectDuplicateCode, within-file) weighted introduced points ÷ analyzed KLOC 15
structure (maxFunctionLines, maxFileLines, maxParameters, maxComplexity, maxNestingDepth, requireSingleResponsibility, requireDocumentationForComplexCode) same 45
hygiene (detectUnusedCode, requireClearVariableNames, requireErrorHandling, forbidEmptyCatchBlocks, forbidHardcodedSecrets, forbidDebugStatements) same 38
adjustedDensity(cat) = (weighted(cat) + projectDensity(cat) × 1) / (analyzedKLOC + 1)
categoryScore(cat)   = round(100 × e^(−adjustedDensity(cat) / scale(cat)))
CleanCodeScore       = round(dup × 0.30 + structure × 0.45 + hygiene × 0.25)

Volume fairness — Bayesian shrinkage. Each density is blended with the project-wide density, weighted by how much code the developer wrote (priorKLOC = 1). A 300-line contributor is pulled strongly toward the project mean; a 25 KLOC contributor keeps their real number. This is what stops a tiny clean sample from scoring 100 and a large honest contributor from looking worse than a tiny one.

Confidence level, from analysed lines: <300 insufficient, 300–999 provisional, 1000–4999 reliable, ≥5000 highly_reliable. Below the ranking threshold (minLinesForRanking, default 1000) a developer is shown but not ranked. A developer with no analysed code scores —, not 100.

Net Quality Impact = introducedWeighted − fixedWeighted is shown per developer for context; fixing a lot of debt is visible but cannot push the score above 100.

Quality vs contribution stay separate. Clean Code Score (0–100) measures code quality. Contribution (% of analysed lines written) measures volume. They are displayed side by side and never combined into one number.

Every constant lives in src/scoring/scoringConfig.ts and can be overridden from the config file / VS Code settings — tune there, not at the call sites. Treat the number as comparative, not an absolute grade.

7. Display

The ProjectReport object returned by analyzeRepository is then rendered:

  • Extension — stored in ReportStore (src/views/treeProviders.ts), which pushes updates to the sidebar (Dashboard / Developers / Violations) and to the Webview panel (src/views/dashboardHtml.ts): project stats, a card per developer with a score bar, and a violations table with free-text search and severity filters. Clicking a row opens the file at the line. The report also feeds the inline editor diagnostics.
  • CLI — formatted by src/cli/format.ts into the text block shown above, or serialized with JSON.stringify when --json is given.

The 14 rules in detail

Full reference with defaults and per-language coverage: docs/RULES.md.

Rule id Reported when Default limit
maxFunctionLines a function is longer than the limit 40 lines
maxFileLines a file is longer than the limit 400 lines
maxParameters a function takes more parameters than the limit 5
maxComplexity cyclomatic complexity exceeds the limit 10
maxNestingDepth control-flow nesting is deeper than the limit 4
detectDuplicateCode an identical block repeats across the project options.minLines = 6
detectUnusedCode an import / variable / function is never used —
requireClearVariableNames a vague name such as data1 or x —
requireErrorHandling a failure-prone operation with no try —
forbidEmptyCatchBlocks an empty catch / except —
forbidHardcodedSecrets an API key or password written in the code —
forbidDebugStatements console.log / debugger / print / breakpoint —
requireSingleResponsibility a class with too many methods, or a function that is both long and complex options.maxMethods = 10
requireDocumentationForComplexCode function complexity ≥ threshold with no JSDoc / docstring options.complexityThreshold = 15

Heuristic rules — requireErrorHandling, requireSingleResponsibility, and requireDocumentationForComplexCode are approximate by nature and can produce false positives. Lower their severity or raise their thresholds if they are noisy for your team.


Configuration file

.clean-code-tracker.json is created in the project root, committed to Git, and applied to everyone. Shape:

{
  "version": 1,
  "rules": {
    "maxFunctionLines": { "enabled": true, "severity": "medium", "limit": 40 },
    "maxComplexity":     { "enabled": true, "severity": "high",   "limit": 10 },
    "forbidHardcodedSecrets": { "enabled": true, "severity": "critical" },
    "detectDuplicateCode": { "enabled": true, "severity": "medium", "options": { "minLines": 6 } }
  },
  "exclude": ["fixtures/**", "*.snap"],
  "excludeGenerated": true,
  "excludeMigrations": true,
  "excludeLockFiles": true,
  "analysis": { "maxCommits": 500, "since": "" },
  "scoring": {
    "minLinesForRanking": 1000,
    "severityWeights": { "critical": 8 },
    "categoryScales": { "duplication": 15, "structure": 45, "hygiene": 38 },
    "weights": { "duplication": 0.3, "structure": 0.45, "hygiene": 0.25 }
  }
}

exclude is merged with the built-in defaults (node_modules/**, dist/**, build/**, coverage/**, .next/**, vendor/**, __pycache__/**, staticfiles/**, generated/**, *.min.js, *.map, *.generated.*), plus **/migrations/** and the lock files unless you disable those flags, plus anything in .gitignore and files flagged linguist-generated in .gitattributes or carrying a @generated / DO NOT EDIT header. Excluded files never count toward analysed lines, violations or the score. scoring and analysis are optional; omit them for the defaults.

Each developer may add .clean-code-tracker.local.json (same shape, rules only) to tighten their own feedback without touching the official report. Add it to .gitignore.


VS Code commands

Command Action
CleanLens: Initialize Project detect project type, pick a preset, write .clean-code-tracker.json
CleanLens: Configure Rules open the config file (offers to initialize if missing)
CleanLens: Run Analysis run the full pipeline and open the Dashboard
CleanLens: Open Dashboard reopen the Webview panel

Inline editor diagnostics

Violations show up in the editor as you work — you do not have to run a full analysis first. src/views/diagnostics.ts owns a DiagnosticCollection, so each violation appears like any linter finding:

  • a coloured squiggle under the offending line(s);
  • a hover with the rule title and message (e.g. Long function: Function handleRequest has 63 lines (limit 40).);
  • an entry in the Problems panel (⇧⌘M), grouped by file;
  • a marker in the gutter and the file's tab.

Severity maps to VS Code's levels:

Rule severity Editor level
critical, high Error (red)
medium Warning (yellow)
low Information

Two feeds

Feed Trigger Coverage
Full after Run Analysis all 14 rules, every file, including cross-file detectDuplicateCode
Live while you type (400 ms debounce), and on file open / save file-scoped rules for the edited file only — no detectDuplicateCode, no attribution

The live feed re-runs just the single-file analyzer (jsAnalyzer / pyAnalyzer) for the active document, using the current .clean-code-tracker.json — a FileSystemWatcher reloads the rules the moment you edit that file. While you are editing a file, its live diagnostics temporarily replace that file's full-analysis diagnostics; the next Run Analysis restores the complete set (including duplicates).

If the buffer does not parse mid-edit, the previous diagnostics are kept rather than cleared. Closing the file, or turning cleanlens.liveDiagnostics off, swaps that file back to its full-analysis diagnostics (or clears them if no analysis has run).


Settings

Setting Default Effect
cleanlens.liveDiagnostics true Underline violations in the editor as you type, before running a full analysis. Set to false to only show diagnostics after Run Analysis.
cleanlens.exclude [] Extra glob patterns to exclude, merged with the built-in defaults.
cleanlens.excludeGenerated true Skip files flagged linguist-generated or carrying a @generated / DO NOT EDIT header.
cleanlens.excludeMigrations true Skip **/migrations/**.
cleanlens.excludeLockFiles true Skip package-lock.json, yarn.lock, pnpm-lock.yaml.
cleanlens.mergeSameNameAuthors true Merge contributors that share a display name into one developer.
cleanlens.analysis.maxCommits 500 Walk only the newest N non-merge commits. 0 = whole history.
cleanlens.analysis.since "" Only walk commits after this date (any git log --since value).
cleanlens.scoring.minLinesForRanking 1000 Analysed lines a developer needs to enter the ranking.
cleanlens.cache.enabled true Cache per-commit results so re-runs only analyse new commits.

Run Analysis is cancellable and shows progress (Analyzing commits (240/500)).

The extension activates on onStartupFinished, so the live feed works as soon as VS Code finishes loading — you do not need to open the CleanLens sidebar first.


CLI manual

Synopsis

cleanlens [path] [options]

path — the repository to analyze. Defaults to the current working directory. It must be inside a Git working tree with at least one commit.

Options

Option Effect
--json Print the full ProjectReport as pretty JSON to stdout instead of the text report. Everything (developers, violations with developerId, line ranges) is included.
--markdown Print a full English report in Markdown instead of the text summary: run metadata, the scoring formula, severity and rule breakdowns, a per-developer section, a Files with violations table that lists the violating line numbers, and an All violations table. Redirect to a .md file to share.
--violations In text mode, also print every violation, sorted by severity, as [severity] Rule title — path:line (status/confidence; introduced by). Ignored with --json (JSON always contains them).
--preset <name> Ignore .clean-code-tracker.json and use a built-in baseline: javascript, react, python, or django. Useful in CI where you do not want to depend on a committed config, or to compare against the defaults.
--max-commits <n> Walk only the newest N commits for attribution (default 500).
--full-history Walk the entire commit history (overrides --max-commits).
--since <date> Walk only commits after this date (any git log --since value).
--no-cache Do not read or write the per-commit analysis cache ($TMPDIR/cleanlens-cache).
--fail-on <severity> After printing the report, exit with code 1 if any violation is at or above <severity> (low | medium | high | critical). This is the quality gate.
-h, --help Print usage and exit 0.

Output streams

Stream Contents
stdout the report only — the text block, or JSON with --json
stderr progress (Scanning files (12/87)), warning: lines, and error: lines

So redirects stay clean:

cleanlens --json > report.json          # only JSON in the file
cleanlens --violations 2> /dev/null      # hide progress and warnings

Exit codes

Code Meaning
0 analysis completed (and --fail-on, if given, was not triggered)
1 --fail-on matched — violations at or above the given severity exist
2 could not analyze — not a Git repo, no commits, invalid config, or a bad option

Examples

# human-readable report for the current repo
cleanlens

# full listing, using the Django preset instead of a config file
cleanlens ./services/api --preset django --violations

# machine-readable, for a dashboard or a diff between runs
cleanlens --json > clean-code-$(date +%F).json

# quality gate: fail the build on any high or critical violation
cleanlens --fail-on high

GitHub Actions

name: clean-code
on: [pull_request]
jobs:
  analyze:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0          # commit-by-commit attribution needs history
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npx cleanlens --fail-on critical

fetch-depth: 0 matters: a shallow clone has almost no history, so attribution falls back to a few commits and most violations show as existing.

Pre-commit hook

# .git/hooks/pre-commit  (chmod +x)
#!/bin/sh
npx cleanlens --fail-on critical || {
  echo "Commit blocked: critical Clean Code violations."
  exit 1
}

Performance

  • Analysis runs on demand only, with progress reporting and a cancel button.
  • The commit walk is cached by commit hash under $TMPDIR/cleanlens-cache (CLI) or the extension's global storage. A re-run only analyses new commits; the cache is invalidated automatically when rules, weights or exclusions change.
  • Only the newest 500 commits are walked by default (analysis.maxCommits).
  • Git calls are batched — one git log, then one git diff + one git cat-file --batch per commit (not one call per changed file), and commits are analysed 12-way in parallel. Each file revision is parsed at most once (content-addressed by its blob sha).
  • node_modules, virtualenvs and generated folders are excluded before any file is read.
  • Files over 1 MB and non-source extensions are skipped.

Limitations you must communicate to your team

  • Attribution compares a file's violations before and after each commit. It charges a developer only for smells that first appear on lines they changed (or in a symbol they modified) — a one-character edit no longer transfers a whole file. Whitespace-only reformats are ignored (-w); moved/copied code is tracked (-M -C), but cases Git cannot detect fall back to existing/low and are not charged.
  • Only JS/TS and Python files are analysed; other files count as not analysed.
  • Violations older than the analysed commit window show as existing and are never charged. Widen analysis.maxCommits (or --full-history) for full coverage.
  • Cross-file clone detection runs on the HEAD snapshot only; the per-commit duplication signal is within-file.
  • The Clean Code Score is an indicative signal to improve project quality, not an absolute judgement of a developer. Always show it next to the violation details, the confidence level and the ruleset used.

Contributing

Project structure, local development and the release process are in CONTRIBUTING.md.


Author & license

Created and maintained by MUSAALAHMED4 (Musa Al Ahmed). Licensed under MIT — see LICENSE.txt.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft