Quick start
What you need
- Node.js 22 or newer
- A repository with git history — that is where change frequency comes from
- A TypeScript codebase (monorepo or a single package, both work)
It does not work on a shallow clone
With git clone --depth 1, or the default settings of most CI systems, the history is truncated and change frequency, hotspots, and coupling are all wrong. dowse detects this and warns, but the numbers are not trustworthy. In CI, set fetch-depth: 0.
Run it
Nothing to install.
npx dowse analyzeWithin seconds you get something like this — about 7 seconds for a monorepo of 2,238 files and 3,920 commits.
Discovering workspace... 40 packages (pnpm)
Reading git history (since 12 months ago)... 3920 commits
excluded: 6 merge, 0 bot, 1 format-only, 0 ignore-revs
Parsing AST (oxc)... 2238 files
Building package graph... 40 packages, 168 edges
Computing change coupling... 500 file pairs, 25 package pairs (1 hidden)
⚠ Top hotspots (complexity=loc):
┌───┬─────────────────────────────┬───────┬────────┬────────┬─────────┐
│ # │ file │ score │ freq │ cx │ commits │
├───┼─────────────────────────────┼───────┼────────┼────────┼─────────┤
│ 1 │ services/api/src/runtime.ts │ 0.999 │ 100pct │ 100pct │ 255 │
└───┴─────────────────────────────┴───────┴────────┴────────┴─────────┘
📌 Top findings (where to look first):
🔥 services/api/src/runtime.ts — changed often and complex (255 commits, 857 LoC)
🔗 @acme/admin-web ↔ @acme/doctor-web — changed together 91 times with no dependencyThe full result is also written to .dowse/dowse.json.
Why it prints what it excluded
Every run states that merge, bot, and format-only commits were removed. Excluding them silently would let you read the output as "everything, analysed" — and a number you cannot tell the scope of is not a number you can act on.
Dig into what it found
Why do these change together?
When hidden coupling shows up, look at what is actually behind it.
npx dowse why @acme/admin-web @acme/doctor-web■ File pairs that change together most
src/lib/server-api.ts ↔ src/lib/server-api.ts 13
src/app/(authed)/page.tsx ↔ src/app/(authed)/page.tsx 15
■ Representative commits (newest first)
c23db79c 2026-07-09 add re-login prompt on session expiry to all three surfaces [A:3 B:6 files]Identically named files on both sides, changed by hand in lockstep. A candidate for extraction into a shared package.
Is that change frequency real?
npx dowse analyze --verify-churnIt compares ASTs to separate real edits from renames and reformatting.
🔍 Churn verification (AST comparison, top 20 files):
513 of 568 revisions were real changes (55 false: 12 renames / 35 format-only / 8 unchanged)
⚠ doctor-call-panel.tsx: 42% of its churn did not change meaningThis runs git show per revision, so it is opt-in and limited to the top N files.
Why is this file complex?
npx dowse health --file src/foo.ts health: 4.9 / 10 (lines-of-code baseline: 10.0)
deductions from 10.0:
-3.00 high cognitive complexity (50 > threshold 15, severity 1.00)
→ validateEnvironmentConfig (cognitive=50, L3)
-2.13 complex function (27 > threshold 10, severity 0.85)
→ validateEnvironmentConfig (cyclomatic=27, L3)The LoC baseline is 10.0 but health is 4.9 — a short but dense file. A metric that only counts lines would miss it entirely.
Where is the knowledge concentrated?
npx dowse knowledgeBus factor per package, plus what would be left unowned if the main developer left.
Use it from an agent
If you use Claude Code, wiring it up as an MCP server is the most practical setup.
claude mcp add dowse -- npx -y dowse mcpFrom then on you can ask "where should I refactor next in this repo?" inside a session and get an answer grounded in the analysis. See Coding agents.
Let it do the fix
npx dowse fixIt hands the top hotspot to an agent, verifies the result with your type checker and tests, and reports how much complexity moved. It is a dry run by default — the change is always discarded.
packages/cli/src/analyze.ts
cognitive -41 / cyclomatic -22 / LoC -111
verified: typecheck ✓ / tests ✓Add --apply to keep it. See Closing the loop.
Next
- Reading the results — how to interpret the scores, and what to ignore
- CLI reference — every command and option
- CI integration — quality gates and PR comments