Codebase Stats (project health dashboard)
A multi-tab report on one real project: its size, health, git activity, dependency risk, AI spend and test coverage, gathered from the filesystem, git, npm and Omniscio's own database into a single modal. Covers opening it, the headline numbers, the per-tab detail, ignoring a noisy finding, and spawning a fix-it session from one.
What it is
Codebase Stats is a multi-tab modal that analyzes a real project and reports on its size, health, git activity, dependency risk, AI spend, and test coverage — everything you'd normally get from a half-dozen CLI tools, gathered and presented in one place. It scans the filesystem, reads git log, checks package.json, runs the coverage tool, and aggregates session costs from Omniscio's own database. Results cache for 24 hours so repeat opens are instant, but you can force-refresh anytime. The modal is per-project and only shows for real codebases — virtual projects (Gmail, SMS, OpenClaw, Skills, etc.) don't have a filesystem to analyze so the menu item is hidden there.
Where to find it
It opens from a project's three-dot menu in the left sidebar, under View Codebase Stats. Because it needs a folder to scan, the menu item is only there for real projects — the built-in virtual rows such as Gmail, SMS or Skills have no filesystem behind them and never show it.
How it behaves
How to use it
- Open the modal. Click the three-dot menu on any real project in the left sidebar → View Codebase Stats. The modal takes over the screen.
- Skim the Overview. The first tab shows 8 headline numbers: total lines, source vs test lines, commits in last 30 days, AI spend to date, test count, TODO count, dependency count, and known vulnerabilities. If any secrets were detected, a red alert banner appears at the top.
- Drill into tabs. Switch between Files (language breakdown + extension table), Health (TODO/FIXME count,
anytypes, detected secrets, large files over 300 lines), Git (activity, churn hotspots, knowledge silos, stale files), Deps (outdated and vulnerable packages by severity), Costs (input/output token usage and total dollars), and Coverage (donut chart + untested file list). If the file scan hit an aggregate cap — too many files, too much cumulative content, or too deep a folder tree — an amber banner at the top of the Overview and Files tabs explains which cap stopped it and that the analysis is partial. - Run coverage manually. The Coverage tab doesn't auto-run — click Run Coverage and Omniscio invokes your test suite with
@vitest/coverage-v8instrumentation (and offers a one-click install if the provider is missing). Progress streams live as it works. - Ignore noisy findings or launch a fix-it session. Click the X on any flagged finding (a large file, a TODO, a detected secret) to hide it from future reports — restore later from the "show ignored" toggle. Or click Fix in Session on a Health finding to spawn a new Claude session with a pre-written prompt asking it to address that specific problem. Use Refresh (bottom-left) to bypass the 24h cache.
For agents
How it works
The modal is /src/renderer/src/features/dashboard/CodebaseStatsModal.tsx (~557 lines) with 7 tab IDs defined in its TABS array: overview | files | health | git | deps | costs | coverage. It's opened from the project's three-dot menu (/src/renderer/src/features/dashboard/ProjectListItem.tsx), gated on !isVirtualProject(project.folderPath). On mount the modal invokes IPC.CODEBASE_STATS_ANALYZE, which runs /src/main/services/codebase-analyzer.ts — that scan asks git which files belong to the project (git ls-files --cached --others --exclude-standard), which is both fast and correct by construction: it honours the project's own ignore rules, so build output and machine junk that merely sits inside the folder are never counted. It falls back to walking the filesystem when the folder is not a git repository root (guarded with git rev-parse --show-prefix, so a folder nested inside a larger repo is not reported as that repo). Both sources refuse junk by shape rather than by one spelling of its name: any *.git directory, any node_modules* directory, and — the catch-all — any file whose leading content contains a NUL byte, whatever its extension. A file counts as "test" if its path or name matches /test|spec/; files over 300 lines are flagged "large". Files are then read with a bounded fan-out (threadpoolSize() × 4) rather than one at a time, and the results are accumulated in list order so the same tree always produces the same numbers. The scan is bounded (generous defaults: ~150,000 files, ~2 GB of cumulative content, ~40 folder levels) so a huge monorepo or a mis-pointed folder can never make it unbounded — but the caps are sized to fully scan a large real repo (Omniscio itself measures ~61k files / ~878 MB) rather than truncate it. The byte cap is a work/time budget, not a memory guard: the walk reads each file's content transiently and keeps only per-file {path, ext, lines, bytes}, so raising it costs scan time, not heap. When a cap does trip, the walk stops and truncated is set on the result so both the Overview and Files tabs show the amber "analysis is partial" banner (one shared TruncationBanner) rather than let a short scan look complete on the default view. A CODEBASE_STATS_ANALYSIS_VERSION stamp on the cached blob makes a logic change like a cap raise self-applying: the on-demand handler treats a cache written by an older analyzer as stale and re-scans, instead of serving now-wrong numbers for up to 24h. Secret detection uses a fixed pattern list (AWS keys, GitHub PATs, Slack tokens, Stripe sk_live_, PEM private keys) plus a generic high-entropy regex. Results stream back incrementally via IPC.CODEBASE_STATS_PROGRESS push events so sections populate as they finish. Git stats come from git log shellouts; dependency data from npm outdated --json and npm audit --json; coverage data from the coverage-final.json vitest writes. The 24-hour cache lives in SQLite table codebase_stats_cache, and per-project ignored findings live in codebase_stats_ignores — both managed by /src/main/db/queries-codebase-stats.ts. The Costs tab pulls from IPC.PROJECT_COST_ROLLUP, which sums input/output token costs across every session in the project. Fix in Session on a Health finding creates a new session with a pre-written prompt asking Claude to address the specific file/line flagged.
Background warming (pre-computed so the modal opens instantly)
The 24h cache is also pre-warmed in the background, so opening the modal is instant instead of triggering a cold scan. A main-process service — /src/main/services/codebase-stats/codebase-stats-warmer.ts (scheduler) + /src/main/services/codebase-stats/codebase-stats-warmer-logic.ts (pure, unit-tested decision rules) — periodically warms a small batch of projects into codebase_stats_cache, reusing the same analyzeCodebase engine. No new table, no migration, no new view.
Built to never load the machine, even at 1000 projects:
- Change-detection. Probes
git rev-parse HEADand skips any project whose cachedgit_commit_hashstill matches (within a 7-day backstop). Steady-state work is ~zero, since most projects don't change on a given day. - Light mode. Calls
analyzeCodebase(…, { skipDeps: true }), skipping the only network step (npm audit+npm outdated).depsstays null (modal shows "No dependency data available"); vulnerability/outdated numbers fill in only on an on-demand open + Refresh. A per-file size cap also prevents one giant file from OOMing a sweep. - Throttle. ONE PROJECT AT A TIME, a small batch per ~5-min tick, a pause between projects, first run deferred ~2 min after boot, and a load gate re-checked between projects — free RAM always, plus CPU and disk pressure. The CPU/disk terms can hold ticks back for at most ~4 h: past that a starvation floor forces one small batch whose first project always runs, so even a permanently busy box keeps its stats refreshing (a box short of RAM is never forced). HEAD probes use a rotating slice so a fresh commit is caught over time without probing all 1000 each tick. Inside a single project the file reads use a bounded fan-out (
threadpoolSize() × 4) — a serial scan measured ~10 files/s, which put a large repo at ~19 minutes and made the 5-minute per-project budget unreachable. - Never degrades. Merges onto the prior cache row, preserving any richer
coverage/depsa full on-demand scan produced. - Control. The
codebaseStatsBackgroundEnabledsetting (Settings → Diagnostics, default on) + theAMC_DISABLE_CODEBASE_STATS_WARMERenv kill switch. Start/stop is wired at startup (/src/main/startup/registry.ts) and on toggle (/src/main/services/settings-apply.ts).
Invariants are locked in /.claude/memory/contracts/background-codebase-stats-warmer-contract.md.
Related
Running an analysis on a schedule rather than by hand is a job for the step machinery described on the use recipes page. The projects that are exempt from stats because they have no local folder are covered on OpenClaw provider.
- /.claude/memory/contracts/background-codebase-stats-warmer-contract.md — the background warmer's test-locked invariants
- use-recipes.md — if you want to run codebase analysis on a schedule across many projects, wire it into a recipe step
- openclaw-provider.md — OpenClaw projects are exempt from stats (no local filesystem)
Last verified 2026-09-26