What is dowsing?
The problem it solves
In a large codebase — a monorepo especially — a team keeps running into one question:
With the time we actually have, where do we fix things so it pays off most?
Technical debt is unbounded. Refactoring candidates are unbounded. Time is not.
Conventional static analysis (ESLint, SonarQube) looks at a snapshot and lists every problem as equally important. It produces thousands of warnings and no priority. And fixing code that is complex but that nobody ever touches returns approximately nothing.
The central insight
Adam Tornhill, who created this field with CodeScene, put it simply:
Not all code is equal. Only code that is both changed often and complex — a hotspot — is genuinely a problem, and that is where investment pays off.
And "changed often" is already written down, in your git history.
Crossing code structure (static analysis) with change history (version control mining) is behavioral code analysis.
What dowsing adds
dowsing reworks that insight specifically for TypeScript monorepos.
1. Package boundaries are first-class
CodeScene supports 39 languages, and monorepos are retrofitted onto it as "a collection of folders". It does not understand npm/pnpm workspaces, or the package boundaries and dependency graph of Turborepo/Nx.
dowsing reads your workspace configuration directly and runs the behavioral analysis on top of the package graph. Everything below follows from that.
2. It finds hidden coupling
Two packages with no dependency between them that keep being changed in the same commit — coupling that never appears in the structure.
affected in Nx or Turborepo tells you what to rebuild; it does not see this. Looking at the dependency graph alone, you cannot find it.
A real detection:
@acme/admin-web ↔ @acme/customer-web 33% coupling, 91 co-changes, no dependencyRunning dowsing why on that pair showed server-api.ts and the auth pages existing in near-identical form in both, changed together by commits like "add re-login prompt on session expiry to both web apps". Not a shared abstraction — copied code.
3. It checks whether change frequency is real
A git line diff cannot tell you whether the meaning changed. Renaming an identifier, reformatting, or editing comments all look like large diffs and inflate change frequency. CodeScene itself lists "renaming a type inflates churn" as a known weakness.
dowsing compares the AST of each revision to identify changes that did not alter meaning. Measured on a real repository: of 568 revisions across the top 20 hotspots, 55 (9.7%) were false churn, and the worst file was 42% inflated.
4. It publishes how every score is derived
CodeScene's Code Health keeps its formulas, thresholds, and weights closed. You cannot reproduce it, verify it, or tune it.
dowsing publishes all of it.
health = 10 − Σ(weight × severity)And it shows which smell cost how many points, down to the function name and line number. Meaning: you can recompute it by hand.
It also prints the score you would get from lines of code alone. If the two are close, that health score is just file length wearing a costume — and you should be able to see that for yourself.
5. It measures whether the fix helped
A ranking is a prediction. After the change lands, dowsing diff <base> reads every changed file at both revisions and reports how much the complexity actually moved.
📉 Measured complexity (base → head):
cognitive -41 / cyclomatic -22 / LoC -111The claim "this was the highest-ROI fix" is then a measurement, not a prediction. dowsing does not do the fixing — that is your agent's job, and the measurement works regardless of who made the change.
What dowsing is not for
- Multi-language codebases. It is all-in on TS/TSX. For breadth, use CodeScene.
- Repositories with no or shallow git history. Change frequency cannot be computed, so half the tool does nothing. In CI,
fetch-depth: 0is mandatory. - Evaluating people. Bus factor and ownership are risk indicators for a team. Do not use them as a performance review. Tornhill gives the same warning.
Next
- Quick start — run it
- Reading the results — how to interpret the output, and what to ignore
- Why these metrics — the research each number comes from