Brain · Brain health

Tell an unmeasured brain from an unhealthy one

Brain health scores a repository's brain on four dimensions and averages only the ones it could measure. A dimension with nothing behind it reports a dash, not a zero, so a new install reads as unmeasured rather than as failing.

For: the engineer who keeps a repository's brain, and the lead reading the team rollup

What it does, and why it helps

Four sub-scores, each computed on the machine with no model call. Coverage is the share of top-level brain files edited inside the last 30 days. Freshness compares the median file age against a 14-day target: at or under the target is 100, at four times the target is 0, linear between. Drift is the share of brain files carrying a citation-rot or vector-drift event, plus any Brain Wiki page whose inline source references no longer resolve. Adoption is the share of reviewed proposals that were accepted. The composite is the equal-weight mean of whichever of the four returned a number, and the line under it says how many that was.

Adoption's denominator is the part worth knowing. A proposal that timed out before anyone opened it counts as expired, and expired rows are excluded from the score rather than counted as rejections. This repository's own numbers are why: 203 outcomes, 140 expired, 63 accepted, none rejected. Adoption read 5 percent and the recommendation said to tune the proposer, when nothing had been rejected and the real problem was a queue nobody drained. The expired count now rides beside the score, and draining the queue is its own recommendation.

The pain. A brain decays quietly. Files go stale, cited paths stop resolving, proposals expire unread, and none of it shows up until someone asks a question the brain can no longer answer.

The point of view. A health number is only worth reading next to what it left out. Score the dimensions that had data, name the ones that did not, and never average a zero in for a thing nothing measured.

What gets easier. Knowing which lever to pull. The worst measured sub-score is ranked first, and the top three recommendations each carry a link to the tab that fixes it and, where a verb exists, a Preview and an Apply.

When it helps. A repository whose brain is written by agents and read by people, where nobody owns the question of whether it is still true. The tab reads what is already on disk, so it works on the first run.

Its limits. It grades whether the brain is kept, not whether it is correct: a wrong fact edited yesterday scores full marks on all four. Coverage and Freshness trend only from the days the score was read, because a file modification time cannot be re-read for a past day. The composite is a mean of what was measured, so a brain with one measurable dimension and three dashes still shows a number.

Understand it in 30 seconds

30.1 s, captions on. Narration: Microsoft Zira Desktop (provisional voice; an approved narration source is pending).Transcript
Read the narration
  1. 0:00 A new brain scored twenty-five.
  2. 0:02 Nothing had been measured yet.
  3. 0:06 Average only what you measured.
  4. 0:08 A dimension with no data reports a dash, not zero.
  5. 0:13 Four sub-scores, and the composite says how many it covered.
  6. 0:17 Expired proposals are excluded, not rejections.
  7. 0:23 A dash is a question, not a grade.
  8. 0:26 Fix the worst measured score.

Synthetic example. Read the guide

Where to find it

Where to find it

  • Desktop: localhost:4000, then Memory in the sidebar, then Brain health under All tools, in the Evidence readers group.
  • Hosted: repoops.ai/team/brain-health, from Memory in the sidebar, then Brain health under All tools, in the Evidence readers group.
  • Keyboard: ⌘ K, then type “Brain health”.

When to use it

The score dropped and nobody changed the brain

Situation. Coverage and Freshness were steady, then both fell over a week. No file was deleted and no sweep ran.

What you do. Open the tab, set the trend window to 60, and read the note under the Coverage and Freshness sparklines. Then read the sub-score line: Coverage names how many of the brain files are stale, Freshness names the median age against the target.

What you see. The card note reads the stale count over the total, and the median age in days against the 14-day target. The sparkline label says how many days were measured, and a shorter series says so rather than drawing a flat line across days nobody recorded.

What it establishes. Nothing changed the brain. Time passed, files aged past the 30-day staleness cutoff, and the two age-derived scores fell because they are meant to. The lever is a refresh sweep, and Freshness raises it as a recommendation when the median is over target.

Adoption reads a dash while the queue is full

Situation. The Outcomes tab has hundreds of rows and the Adoption card shows a dash with the note that no outcome rows were reviewed, or a low score beside an expired count.

What you do. Read the Adoption note. If it names expired rows, open the recommendation for draining the queue, which links to the Outcomes tab. Press Preview first to see what the verb would write, then Apply.

What you see. The recommendation names how many proposals expired unreviewed and carries the raise_alert verb. Preview posts a dry run and the toast reports the preview summary. Apply posts the real run and the toast reports what was applied, or that the verb was queued for approval.

What it establishes. An unattended inbox is separated from a badly tuned proposer. Adoption stays a dash until somebody decides on a proposal, which is the honest answer: nothing has been reviewed, so nothing can be scored.

Before you start

Supported versions
RepoOps desktop v0.3.1, the release this guide was read against. The tab needs at least one repository in repos.config.json. Nothing else has to be running for the four sub-scores.
Where it runs
Local: Memory, then Knowledge health, or Brain health under All tools, with the Citation rot subtab beside it. Hosted: Memory, then Brain health under All tools, in the Evidence readers group (repoops.ai/team/brain-health), the same four formulas computed across every repository the account has pushed events from, plus a quota burn panel. The hosted view scores from synced events rather than files on disk, leaves the wiki checks out of Drift, and links each recommendation to a tab instead of queueing an action.
Permissions
Local: none. The dashboard binds to 127.0.0.1 by default and the read takes no sign-in. Hosted: a session cookie and a membership of the team, or a device Bearer token bound to that team. The account is resolved from the credential and never from the query string.
Connections
None for the local score. For the hosted rollup, a bound desktop with the one-way event push turned on, which is opt-in and off by default. Drift only moves once a citation-rot scan has run, from the nightly pass or the Re-scan citation rot button.
Plan
The local tab has no plan gate, and the capability map has no brain-health row. The hosted rollup follows the hosted dashboard tiers; cross-repo and cross-developer aggregation is the Team line.

Configure it

  1. Pick the repository and the trend window.

    The Repo select lists what repos.config.json configures, and Trend window (days) offers 14, 30 and 60. The endpoint clamps the value to between 1 and 60 and defaults to 30. Refresh re-reads without changing anything.

  2. Read the composite next to how many dimensions it covers.

    The number under Composite health says it is the equal-weight mean of the measured sub-scores below, and names the count. A dash means nothing was measured at all. The colour is a band, not a grade: 80 and over is green, 50 and over is amber, below 50 is red, and an unmeasured score is grey rather than red.

  3. Give Drift something to measure.

    Drift counts brain files with a citation-rot or vector-drift event. With no events it has nothing to flag. Press Re-scan citation rot to run a scan now and refresh the score; the toast reports the finding count. The daemon's nightly pass runs the same scan, and REPOOPS_NIGHTLY_OFF=1 stops it.

  4. Let the trend fill in.

    Coverage and Freshness read file modification times, which exist only in the present, so they cannot be recomputed for a past day. Every read of the score writes today's pair to a daily store, and a day with no record is left undrawn instead of back-filled with today's value. The series starts short on a fresh install and grows.

  5. Work the top three recommendations.

    The recommender picks the worst measured sub-score first and returns at most three rows. An unmeasured dimension sorts last, so an empty one cannot crowd out a real finding. Each row has Open, and where a verb exists, Preview (a dry run) and Apply, which post to the actions endpoint.

  6. Read the vitals panel as four separate numbers.

    Intelligence vitals (Tier A) sits below the score and answers a different question: not whether the brain is kept, but whether its faculties work. Contradiction precision is scored against a gold set a person labelled by hand, never a model judging a model. The four axes are never summed, and the module holds no composite field. The same numbers print at the terminal with npm run brain-vitals.

SettingWhereA sensible choiceWhy it matters
trendDaysBrain health tab, Trend window (days), or the query parameter30 (the default); 14 and 60 are the other offered valuesClamped to between 1 and 60 by the endpoint. It sets the width of the sparklines and the window for the outcome and drift rows Adoption and Drift are scored over.
repoBrain health tab, Repothe repository whose brain you keepThe endpoint answers 404 for an unknown repository id, and with no repositories configured the tab says to add one in Settings.
staleDaysno control; the default in lib/brain-metrics.mjs30 (fixed)The cutoff Coverage calls a brain file stale. The pure function takes it as an argument, but the endpoint never passes one, so 30 is what every install scores against.
targetDaysno control; the default in lib/brain-metrics.mjs14 (fixed)The median-age target Freshness scores against. At or under the target is 100 and at four times the target is 0, so a brain with a 56-day median reads 0 whatever else is true of it.
REPOOPS_PREWARMthe data directory's .envleave it on (the default)Boot prewarm reads the score once per repository, which is what records that day's Coverage and Freshness pair. Setting it to 0 means the day is recorded only if somebody opens the tab.
REPOOPS_NIGHTLY_OFFthe data directory's .envunset (the nightly pass is on)1 turns off the daemon-owned nightly pass, which is what runs the citation-rot scan that feeds Drift. With it off, Drift only moves when you press Re-scan citation rot.
supervisor.selfThrottleaccount-settings.json in the brain rootfalse (the default)Autonomous threshold adjustment is opt-in. With it on, the Supervisor throttles panel on this tab lists each time a proposer's confidence floor was raised on a regression or lowered on a recovery.
REPOOPS_BRAIN_EMBED_PROVIDERthe data directory's .envleave unset for lexical-only, or name a providerIt decides what the Probe the retrieval layer button can report. Unset and never tried is reported as a configuration choice, not a fault; configured and failing is reported as a fault.
ⓘ
To stop or undo
There is no switch. The score is computed on the read, so not reading it is the only way to stop computing it, and the only thing a read writes is that day's Coverage and Freshness pair. To stop the two background causes: REPOOPS_PREWARM=0 stops the boot read, and REPOOPS_NIGHTLY_OFF=1 stops the nightly citation-rot scan that feeds Drift. A recommendation does nothing until you press Apply.

What you should see

A kept brain on a machine that has been running a while

Configuration. A repository with brain files, a citation-rot scan behind it, and outcome rows that somebody decided on.

Expect. A composite in the green band over four measured sub-scores, four sparklines, and either no recommendations or one naming the worst lever.

Verify. The line under the composite names the count of measured sub-scores. The meta line above reports the brain files, outcome rows, drift events, regression alerts and throttle events scanned, and the time it was generated. The empty recommendations state says health looks good for this window.

A fresh install, or a repository with no brain yet

Configuration. No brain files, no outcome rows, no drift events.

Expect. A grey dash for the composite with the note that nothing was measured yet, and a dash on each sub-score rather than a zero. On the hosted side the page says there is not enough data yet, and that the absence of a measurement is not a clean bill of health.

Verify. Coverage reads that no brain files were found, Adoption that there are no outcome rows yet, Drift that there are no brain files to drift, Freshness that no brain files were found. None of them is coloured red.

A short trend on a brain that is older than the store

Configuration. A 30-day window on an install where the score has been read on only a few days.

Expect. Adoption and Drift draw the full window, because both are re-derivable per day from their own event rows. Coverage and Freshness draw only the recorded days.

Verify. The note under the Coverage and Freshness cards says how many of the last N days were recorded, and that earlier days are undrawn rather than back-filled. On the hosted side the sub-score note classifies the series as measured, constant or unmeasured, so a line that never moved is not drawn as a trend.

Data and cost

What is captured
One row per repository per UTC day in brain-health-history.jsonl under the data directory, holding the day, the repository id, a timestamp and that day's Coverage and Freshness scores. Nothing else is stored. Every other number on the tab is computed per request from the brain files, the outcome ledger and the local event store.
Who can see it
Local by default. The hosted rollup at repoops.ai/team/brain-health reads the events table for one team, and it only has rows if a bound desktop has the one-way event push turned on, which is opt-in and off by default. Events are redacted at write time, before the pusher sees them. The daily snapshot file is never pushed; the hosted side rebuilds its own trend from event timestamps.
How long it is kept
The snapshot store keeps at most 2000 rows across all repositories, oldest dropped first, and a second write on the same day replaces that day rather than appending. No environment variable shortens it. The hosted rollup reads events over the trend window plus 30 days, capped at 50000 rows per run; a capped read drops the oldest rows first and the page says so, because a truncated read makes Coverage and Freshness read higher than the full record would give.
What leaves the machine
None for the score. No model call is made anywhere in the four sub-scores, the trend, the recommendations or the vitals panel: the numbers come from file modification times, outcome rows and event rows on this machine. The Probe the retrieval layer button runs two local Ask calls, and those reach an embedding provider only if you configured one.
What it costs
No metered cost. The tab makes no model call, so nothing on it spends. Applying a recommendation runs a verb, and the verbs the recommender offers, file_proposal and raise_alert, write records rather than calling a model.

When the result differs

SymptomLikely causeNext action
The composite is a grey dash.Every dimension returned null. No brain files, no reviewed proposals, no drift events.Read each sub-score note for which one is empty. A dash is the absence of a measurement, not a zero.
Adoption is a dash and the Outcomes tab is full.Every row expired before anyone decided on it, and expired rows are excluded from the denominator.Take the drain-the-queue recommendation and decide on the proposals. The score appears once a proposal is accepted or rejected.
The Coverage and Freshness sparklines are shorter than the window.The daily store only holds the days the score was read, and a past day's file modification times cannot be recovered.Nothing to fix. The note under the card says how many days were recorded. Leaving boot prewarm on records a day on each start.
Drift sits at the same number whatever changes.No citation-rot scan has run, so there are no events to flag files with.Press Re-scan citation rot, and check that REPOOPS_NIGHTLY_OFF is unset so the nightly pass runs it too.
Drift fell after a Brain Wiki was generated.Wiki pages whose inline source references no longer resolve fold into Drift, on top of the brain files.Open the Wiki freshness and wiki verification panels on the same tab to see which pages are unverified, then regenerate or correct them.
The hosted page says there is no rollup for this team yet.No bound desktop has pushed events, or a rollup could not complete.Connect a desktop and turn the event push on. The page distinguishes this from a team whose four dimensions all have nothing to measure.
Hosted Coverage dropped across 2026-08-16 and nothing changed.The rollup used to read events over the same window it judged staleness against, so no file it could see was ever stale and Coverage was pinned at 100 by arithmetic.The page carries the note. Scores from before that date are not comparable with the ones after it.
Disable
Not provided. There is no switch for the score; it is computed on the read. The two background reads that touch it are separable: REPOOPS_PREWARM=0 stops the boot read per repository, and REPOOPS_NIGHTLY_OFF=1 stops the nightly citation-rot scan that feeds Drift.
Roll back
Not provided, and there is nothing to roll back: a score is a read, not a change. What a recommendation writes when you press Apply is a proposal or an alert, and those are undone on the Outcomes and Approval queue tabs, not here. Preview is the dry run that shows what Apply would write.
Revoke access
Hosted only. Disconnecting the device in the desktop app forgets the binding and revokes the device token on the server, which stops new events reaching the rollup. Events already pushed stay in the team's events table.
Delete
Not provided. No route deletes the recorded history. The file is brain-health-history.jsonl in the data directory (REPO_DASHBOARD_DATA_DIR when set, otherwise the repo-dashboard folder under APPDATA on Windows or .repo-dashboard under the home directory), and removing it by hand drops every recorded day.

Maintenance evidence

Feature id
brain-health (spine leaf brain-health)
Owner
Brain-health program (K4.E.3 the local score and trend, K4.E.4 the regression rows, K5.A.6 the hosted rollup, LDG-0526 the snapshot store, G121 the hosted read window; the vitals panel belongs to the brain-benchmark program, Tier A). Guide: LDG-0717.
Supported product version
RepoOps v0.3.1
Last verified
2026-09-15, read against origin/main at 52366bb6d; labels read from the served tab source (public/brain-health.html) and from the hosted page source (website/app/team/(home)/brain-health/page.tsx). Defaults, clamps and caps read from lib/brain-metrics.mjs, lib/brain-health.mjs, lib/brain-health/health-history.mjs and website/lib/brain-health-rollup.ts. Not checked on a running instance.
Example fixtures
No fixture file; the shapes are inline in the tests. lib/brain-metrics.test.mjs covers the four sub-scores, the honest nulls, adoption's reviewed denominator and the recommender's ordering. lib/brain-health.test.mjs covers the trend and the payload. lib/brain-health/health-history.test.mjs covers the day-deduped store and its cap. website/lib/brain-health-score.parity.test.ts holds the local and hosted formulas to the same answers, website/lib/brain-health-rollup.test.ts covers the event projection and the read window, and website/lib/brain-health-trend-shape.test.ts covers measured against constant against unmeasured.
Source references
lib/brain-metrics.mjs, lib/brain-health.mjs, lib/brain-health/health-history.mjs, lib/brain-vitals.mjs, lib/wiki-verify.mjs, lib/routes/brain.mjs, lib/routes/citation-rot.mjs, lib/prewarm.mjs, public/brain-health.html, website/lib/brain-health-rollup.ts, website/lib/brain-health-trend-shape.ts, website/app/api/brain-health/route.ts
Documentation review
Independent review requested on the slice pull request; not yet recorded.
Video review
Narrated story rendered and published 2026-09-26 (render 17cb3bff05c4, LDG-1012) with the breadcrumb Memory, checked against main at b0bb02812. Six frames, the captions and the transcript were reviewed by the authoring agent, not an independent reviewer; the audio was not listened to by a person. Narration is the provisional Windows voice until LDG-0721.

Last updated