Docs

See what a decision touches before you change it

RepoOps parses every cross-reference in your repository brain and shows both directions per file: what links to it, what it links to, each with the source line and a snippet. No model call, so the answer is the same every time.

For: the engineer about to edit a decision or an error entry, and the owner who wants to know which knowledge nobody cites

What it does, and why it helps

The walk reads three directories in order: the brain root, then pull-requests/, then sessions/. In each markdown file it looks at one line at a time and captures three kinds of reference: a markdown link [text](file.md), a [[wikilink]], and a bare file.md mention in prose. A target resolves by base name against the files the walk actually read, so a reference to something it did not read is dropped rather than drawn as a dangling edge. Self-links are skipped, and one source line contributes one edge per target however many times it names it.

Each reference carries its line number and the trimmed line as a snippet, so an inbound row links to /brain/{repo}/{from}#L{line} and lands on the sentence that wrote the link. A file with no inbound and no outbound reference is flagged as an orphan. The walk stops at 2,000 files per repository and reads the first 500 KB of each file, and the tab says so: anything past those bounds is unread, so the totals are a floor and a file can read as an orphan when the file linking to it was never opened.

The pain. You are about to rewrite a decision, and the file itself does not say who is standing on it. Grepping the brain finds the string, not the direction, and it tells you nothing about the files that no longer matter to anyone.

The point of view. Knowledge is a graph whether or not anyone draws it. Read who cites a file before you change it, and treat a file nobody cites as a question rather than a verdict.

What gets easier. Two questions in one open: what does this file depend on, and what depends on it. Each answer is a row with a file, a line and a snippet, and the inbound rows are links, so following a citation back is a click.

When it helps. Editing or retiring a brain file, auditing brain hygiene after a long run of sessions, or handing a repository to someone who has not read it.

Its limits. It reads prose references only, never source code, so it is not a code impact graph. It is per repository: there are no cross-repo edges. Targets resolve by base name, so two files with the same base name in different directories collapse into one target. The bounds are fixed in the module and the totals are a floor, never a count.

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 You are about to change a decision.
  2. 0:02 Who else is standing on it?
  3. 0:06 RepoOps reads every link in the brain and shows both directions.
  4. 0:10 No model, no guess.
  5. 0:13 Each row names the file, the line and the snippet.
  6. 0:16 Files past the caps go unread, so the totals are a floor.
  7. 0:23 Read who cites it, then change it.
  8. 0:25 The guide covers the caps.

Synthetic example. Read the guide

Where to find it

Where to find it

  • Desktop: localhost:4000, then Memory in the sidebar, then Relationships under All tools, in the Decisions and errors group.
  • Hosted: repoops.ai/team/relationships, from Memory in the sidebar, then Relationships under All tools, in the Decisions and errors group.
  • Keyboard: ⌘ K, then type “Relationships”.

When to use it

Before you rewrite a decision

Situation. A convention in decisions.md is about to change, and several sessions and pull request records were written against it.

What you do. Open Relationships, type the file name into the filter box, and expand the card. Read the inbound group, then follow a row to the line that cited it.

What you see. The card head shows the counts as pills, one for inbound and one for outbound. Every inbound row names the citing file, its line, and the trimmed line as a snippet, and links to that line in the brain viewer.

What it establishes. You know which records you are invalidating, and you know it is a lower bound: files past the 2,000-file walk or past the first 500 KB of a file were not read.

Finding knowledge nobody cites

Situation. The brain has grown for months and some of it may be dead. You want the files that no other file references and that reference nothing.

What you do. Open the tab with no filter and read the sub line for the repository totals, then look for the cards carrying the orphan pill.

What you see. The sub line reads as repos, brain files scanned with the 2,000 cap named, edges, and orphans. An orphan card is drawn with a dashed border and its body shows both empty-state sentences.

What it establishes. A list of candidates to fold into a better-referenced file or delete. An orphan is a prompt to look, not proof the file is unused: the reference may sit in a file the walk did not read.

Before you start

Supported versions
RepoOps desktop v0.3.1, the release this guide was read against. Nothing else needs installing: the walk is plain file reading and string parsing in the aggregator process.
Where it runs
Local: Memory, then Relationships under All tools, with Relationship graph as its subtab; the palette and its own URL reach it too. Hosted: Memory, then Relationships under All tools (repoops.ai/team/relationships), over your team's published or GitHub-pulled brain snapshot.
Permissions
Local: none. The tab reads the mirrored brain directory of every repository in repos.config.json. Hosted: a signed-in team member, narrowed by per-member repository access and by the rule that a personal repository never rolls up to a team.
Connections
Local: none, and no API key. Hosted: either the Brain snapshot publisher turned on with this device bound, or a GitHub repository connected so RepoOps pulls its brain server-side.
Plan
The local tab is free. Publishing a brain snapshot needs a paid plan: the ingest route refuses a free or lapsed team with 402 and the message that a paid plan (Solo Hosted or above) is required to publish a brain snapshot.

Configure it

  1. Open it from Memory.

    Memory lists Relationships under All tools, and the link opens it on the repository in view. The palette (type Relationships) and its own URL open it too. For a permanent sidebar row, turn on Show power-user tabs in Settings under Advanced.

  2. Choose the repositories you want graphed.

    The shell opens the tab with repo and repos both set to the repository you have selected, so you see one repository at a time. Open /brain-links.html directly with no query and the endpoint graphs every tracked repository, one section each.

  3. Open a file and read both directions.

    Click a card head to expand it. The body has two groups: what links to this file, and what this file links to. Each row is the other file, its line, and the snippet. Inbound rows link to that line; outbound rows link to the target file.

  4. Filter by name when the list is long.

    The filter box is placeholdered Filter by file name... and matches anywhere in the path, case-insensitively. Cards you have expanded stay expanded while you type, because the open set is kept across re-renders.

  5. Publish the brain only if the team page needs it.

    Settings, the section headed What this machine publishes to your team, then the Brain snapshot switch. It is off by default and also needs a bound device and cloud sync. Turning it on sends the redacted top-level brain markdown, which is what the hosted graph is built from.

SettingWhereA sensible choiceWhy it matters
?repos=<id,id>the Relationships tab URL, set by the dashboard shellwhatever the shell sets (the selected repository)Comma separated. Omit it and the endpoint graphs every tracked repository; ?repo= takes a single id.
Show power-user tabsSettings, Advancedon if you want a permanent sidebar rowOff means the row is drawn only while the tab is active. The palette and the direct URL work regardless.
Brain snapshotSettings, What this machine publishes to your teamoff unless a team page should show the graphThe only switch that moves brain content off the machine. It needs a bound device and a paid plan.
maxFileslib/brain-link-graph.mjs, no control2000 (the default the endpoint uses)The walk stops there, in directory order, so files past it are unread and the totals are a floor.
maxByteslib/brain-link-graph.mjs, no control500000 (the default the endpoint uses)Only the first 500 KB of a file is parsed, so a link written past that point contributes no edge.
MAX_BRAIN_FILESthe hosted page module, no control2000The hosted read budget. A read that fills it shows Files and Links as lower bounds and withholds the orphan count.
?repo=<key>repoops.ai/team/relationshipsomit itWithout it the hosted page shows the most connected repository; with it you pick one, and an unknown or unpermitted key falls back to the default.
REPOOPS_PREWARMthe data directory's .envunset (prewarm on)0 skips the boot warm of /api/brain-graph, so the first open after a restart pays the cold walk instead of reading a warm cache.
ⓘ
To stop or undo
There is no switch that stops the local graph being computed, and none is needed: it reads files already on disk, writes nothing back to the brain, and calls no model. To hide the row, turn Show power-user tabs off. To stop brain content reaching the team, turn the Brain snapshot switch off; the rows already in the hosted store stay until a later publish supersedes them.

What you should see

A brain well under the bounds

Configuration. One tracked repository, fewer than 2,000 markdown files across the brain root, pull-requests/ and sessions/.

Expect. The sub line names the repository count, the files scanned with the 2,000 cap, the edge count and the orphan count. Cards are sorted by inbound count, highest first, then by path.

Verify. Expand the most-cited card and check one inbound row against the file it names: the line number should land on the sentence in the snippet. The freshness line under the heading reads updated just now on a fresh compute.

A brain past the bounds

Configuration. A repository whose brain root, pull-requests/ and sessions/ hold more than 2,000 markdown files, or files larger than 500 KB.

Expect. The scan stops at 2,000 files in that directory order, so sessions/ is the part that gets cut first. Counts are lower bounds and some files read as orphans because the files linking to them were not opened.

Verify. Compare the scanned count in the sub line with the number of markdown files on disk. The legend beside the filter box states the bounds and that the totals are a floor.

The hosted page after a first publish

Configuration. Brain snapshot on, device bound, paid plan, one repository published.

Expect. A smaller graph than the desktop shows. The publisher sends top-level brain markdown only, not sessions/ or pull-requests/, so every edge that ran through those records is absent. Files with no link at all are counted as orphans but not listed as cards.

Verify. Read the three figures at the top of the hosted page. If the read filled its 2,000-file budget, Files and Links are prefixed with at least and Orphans reads not counted, with the reason printed underneath.

Data and cost

What is captured
Nothing new. The graph is derived on each request from the markdown already in the repository's .claude/brain directory, and nothing is written back to the brain.
Who can see it
Local by default. The desktop tab reads your own mirrored files over localhost. The hosted page shows only a team's own snapshot rows, bounded by team id and narrowed by per-member repository access, with personal repositories excluded before the read.
How long it is kept
No retention setting, because the feature stores no history. The last successful response is kept in the per-machine SQLite store (data.db in the data directory, rows prefixed apilkg:), skipped above 2,000,000 bytes and capped at 200 rows across all cached endpoints, so a restart paints the previous answer while a fresh walk runs. In memory the graph is memoized per brain directory, 64 directories at most, invalidated by the modification time and entry count of the three scanned directories. Hosted, a published file stays in the brain snapshot store until a later version of that repository supersedes it.
What leaves the machine
None from the local tab. The walk, the parse and the render happen on your machine and no model is called. The Brain snapshot publisher is the only path that moves this content, and it is off by default: it sends the redacted top-level brain markdown, at most 500 files, 1 MiB per file and 5 MiB per snapshot, and the server re-runs the same redaction before storing.
What it costs
No model call, no API key, no metered spend. The cost is file reading and string parsing, which is why the result is identical on every run over the same files.

When the result differs

SymptomLikely causeNext action
There is no Relationships row in the sidebar.It is registered in the power-user subgroup, which the shell holds back.Open Memory and choose Relationships under All tools, open it from the palette, or turn on Show power-user tabs in Settings under Advanced.
A file you know cites this one is missing from the inbound group.The citing file was past the 2,000-file walk, the citation sat past the first 500 KB of it, or it lives outside the brain root, pull-requests/ and sessions/.Read the sub line for the scanned count, and treat the group as a floor. The empty-state sentence names the same three directories and the cap.
A file reads as an orphan although it clearly has links.Its targets were not among the files the walk read, so the edges were dropped rather than left dangling. A markdown link inside backticks is also skipped, because inline code spans are blanked before the markdown-link pass.Check whether the target file was scanned, and move a real citation out of the code span.
A path-style mention such as .claude/brain/decisions.md produces no edge.The bare-mention pattern needs a line start or a space immediately before the file name, so a mention inside a path does not match.Write it as a markdown link or a wikilink, which both resolve by base name.
An edge points at a file with the right name in the wrong place.Targets resolve by base name, so two files sharing a base name in different directories collapse into one target.Read the from and to paths on the row, and rename one of the two files if the collision matters.
The hosted page says No snapshot yet.The team has no published or GitHub-pulled brain for any repository you can see.Turn on the Brain snapshot switch on a bound device with a paid plan, or connect a GitHub repository so RepoOps pulls the brain server-side.
The hosted graph is much smaller than the desktop one.The publisher sends top-level brain markdown only, never sessions/ or pull-requests/, so every edge through those records is absent.Expected. Use the desktop tab when you need the session and pull request citations.
Disable
Turn Show power-user tabs off to hide the row, and the Brain snapshot switch off to stop brain content leaving the machine. The local computation itself has no switch.
Roll back
Not provided, and there is nothing to roll back: the feature reads files and writes none. The markdown it reads is versioned by git in your own repository.
Revoke access
Turn the Brain snapshot switch off, or disconnect the device in the desktop app, which forgets the binding and revokes the device token on the server. Hosted visibility is narrowed further by per-member repository access and by the personal-repository exclusion, both applied before the read.
Delete
Not provided. No route deletes a stored graph or a published snapshot. The local cached response is a row prefixed apilkg: in data.db in the data directory; the hosted copy is rows in the brain snapshot store, replaced when a later version of that repository publishes, and pruned for a GitHub-sourced repository when a file disappears upstream.

Maintenance evidence

Feature id
brain-links (spine leaf relationships)
Owner
Brain intelligence program, P3 (the brain link graph and backlinks), with the hosted surface under Hosted UI parity W2 and Cloud-hosted localapp phases B.1 and B.2. 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-links.html, public/settings.html) and from the hosted page module, not from a running instance. The caps, the cache bounds and the publish gate were read from the modules cited above.
Example fixtures
No fixture file. lib/brain-link-graph.test.mjs (14 cases) pins the parser over in-memory corpora: the three reference kinds, base-name resolution, dropped dangling references, per-line dedupe, orphan counting, sort order and snippet trimming. lib/brain-link-graph.memo.test.mjs (2 cases) pins the stat-fingerprint memo against a temporary brain directory. website/lib/brain-link-graph.test.ts (3 cases) holds the hosted port to the same contract, and website/lib/github/brain-link-index.integration.test.ts (11 cases) covers the cached indexer, tenant isolation and the push-webhook refresh against a real in-process Postgres.
Source references
lib/brain-link-graph.mjs, lib/markdown-links.mjs, lib/routes/brain.mjs, lib/canonical-tabs.mjs, lib/api-cache.mjs, lib/api-cache-disk.mjs, lib/prewarm.mjs, lib/brain-publisher.mjs, lib/routes/publish-toggles.mjs, public/brain-links.html, public/settings.html, website/app/team/(home)/relationships/page.tsx, website/lib/github/brain-link-index.ts, website/app/api/brain/ingest/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 d5a484a7b111, LDG-1014) with the breadcrumb Memory, which lists the feature under Moved here, checked against main at 7aab4cd82 with LDG-1014 part 1. 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