Skip to content

Repository files navigation

SourceCompass

See how your codebase fits together.

Developers and coding agents keep rediscovering where features live, how modules connect and which files a change may affect. SourceCompass reads a repository locally and builds an evidence-backed map of it, with file:line sources and freshness warnings on every answer. It uses the TypeScript parser, calls no AI model and sends nothing over the network.

Live demo (a made-up app, no install): https://mithunyc.github.io/SourceCompass/demo/

flowchart LR
  R[Your repository] --> A["Local analysis<br/>TypeScript parser, no AI, no network"]
  A --> M["Evidence-backed map<br/>file:line sources, freshness warnings"]
  M --> V[Visual explorer for people]
  M --> Q[Queries for coding agents]
  W["Optional authored inputs:<br/>architecture, workflows, requirements, findings, maps<br/>you write these; not discovered"] -.-> M
Loading

Quick start

You need Git and Node 20 or newer. Windows 11 is the tested platform. The package is not on npm yet, so you run it from source, as below.

git clone https://github.com/mithunyc/SourceCompass.git
cd SourceCompass
npm install
node eb.mjs init --repo <path-to-your-git-repo> --name myapp --build
node eb.mjs open --in myapp

--name is the instance name; open needs --in myapp because you run it from this folder, which is a different repository from yours. init only reads your repo. Its output stays in this folder's git-ignored instances/.

What it supports

  • Code: TypeScript and JavaScript monorepos that use React Router JSX <Route> trees, or a phone app that switches screens in a reducer. Routes written as objects with createBrowserRouter are not detected. init detects the common layouts and prints what it could not find.
  • Agents: Claude Code and Codex through eb agent-setup, plus generic instructions for any agent.
  • Platforms: Windows 11 (PowerShell and Git Bash) is tested. macOS and Linux are unverified.

Limits

  • Static analysis does not prove runtime behaviour, security, completion, or that a test would fail.
  • No token saving is claimed. It was measured, and the result was none (measurement).
  • It does not cover every framework or repository. More in safety and limits.

Follow a feature through your codebase

Start with a screen, find the files behind it, trace where its data goes, and identify tests that may be affected by a change. Zoom out to see how the feature fits into the architecture.

When SourceCompass cannot trace a connection, it shows the gap instead of inventing an answer. A mapped connection describes the code; it does not prove the feature works at runtime.

The example is the built-in demo, a made-up two-app repo ("Acme Field": an office web app and a phone app). Nothing on this page comes from a real codebase. Each block below is an excerpt of the output of the command above it, run on the demo. Every omitted line is marked "…", except the header line each answer starts with (source, freshness, checkout), which is always left out.

node eb.mjs demo
built demo @6d24fda6 in 831 ms: {"office":9,"field":5} destinations, 1 dead links, 4 tables; freshness FRESH

The demo's source lives in .cache/demo-repo, so the commands below pass --repo .cache/demo-repo. It tells the tool which checkout you are standing in.

1. The architecture overview. arch lists the modules the product needs, built or not.

node eb.mjs arch --in demo --repo .cache/demo-repo
# Acme Field: target modules (made-up example) [EXAMPLE] — 5 modules (1 exists, 3 extend, 1 missing) · 4 links · …
…
## Modules
- [EXISTS] jobs: Jobs · plan · home of 2 workflow(s) · office: Jobs
- [EXTEND] daily-log: Daily log · do · home of 1 workflow(s) · field: Log tab
…
- [MISSING] invoicing: Invoicing · bill · home of 1 workflow(s) · office: Money > Invoices

## Spine (end-to-end paths)
- Log to report to invoice: jobs -exists-> daily-log -missing-> reports -missing-> invoicing · first break after daily-log

This is the target design, which you write. In the demo, the jobs module exists. The rest of this page follows one of its screens, the Jobs Board.

2. The screen. q finds a screen from the words on it.

node eb.mjs q "archive first job" --in demo --repo .cache/demo-repo
## O.route:/jobs — Jobs Board  [Office (web app)]
front door: /#/jobs   declared: apps/web/src/App.tsx:25
…
evidence: navigation=traced (3 in-app links) | implementation=traced: apps/web/src/pages/Jobs.tsx | persistence=static path traced (via app context) | authorization=route guard: RequireAuth (client-side guard; not server authorization) | ui/connected/production=not examined
page: apps/web/src/pages/Jobs.tsx (<Jobs>)
renders (2): apps/web/src/components/JobList.tsx <JobList>, apps/web/src/components/CrewPanel.tsx <CrewPanel>
…

3. A button, its handler, its data path and the table.

node eb.mjs show "O.route:/jobs#ctl:archive-first-job" --in demo --repo .cache/demo-repo
# control "Archive first job" (O.route:/jobs#ctl:archive-first-job) — static chain to a table (not a proven save)
at apps/web/src/pages/Jobs.tsx:6
→ useData().archiveJob() @apps/web/src/pages/Jobs.tsx:6 → apps/web/src/contexts/StoreContext.tsx
→ db.execute() @apps/web/src/contexts/StoreContext.tsx:9 → packages/shared/src/db.ts
▣ jobs (write) @apps/web/src/contexts/StoreContext.tsx:9 · statically traced, branch-insensitive (≤3 hops)
…

Read it top to bottom: the button at Jobs.tsx:6 calls archiveJob from a shared context, which runs a database call that writes the jobs table. The path is found by reading the code. It is not proof that saving works.

4. Tests that may be affected. These are candidates, not verdicts.

node eb.mjs impact apps/web/src/pages/Jobs.tsx --in demo --repo .cache/demo-repo
# impact of apps/web/src/pages/Jobs.tsx (blob c51d4124bf, surface office); …
destinations that depend on it (1): O.route:/jobs
files importing it: 2
tests/verifiers referencing it (1): tests/jobs.test.tsx [imports]

tests/jobs.test.tsx is listed because it imports the file. SourceCompass has not shown that the test would fail if the page broke, so open it and decide. "None found" would mean the tool found none, not that none exist.

5. An implementation gap. When the tool cannot connect two things, it could mean missing implementation or a limit of the analyzer. The source settles which. An implementation gap is a link the code really lacks. The Jobs Board renders a crew panel with a link to /timesheets:

node eb.mjs q "timesheets" --in demo --repo .cache/demo-repo
…
text matches (UI strings): "Open timesheets" @apps/web/src/components/CrewPanel.tsx:3
dead links: /timesheets from apps/web/src/components/CrewPanel.tsx:3
…

Here it is a real gap. How we know: CrewPanel.tsx:3 contains <Link to="/timesheets">, and the demo's router (App.tsx) declares no /timesheets route. The link points at a page that does not exist.

6. An unresolved static-analysis result. This is a connection the tool could not follow. It could mean missing implementation or a limit of the analyzer. The Jobs feature has no such case, so this step uses another screen: the phone app's "Resume today's log" button.

node eb.mjs show "P.screen:home#ctl:resume-today-s-log" --in demo --repo .cache/demo-repo
# control "Resume today's log" (P.screen:home#ctl:resume-today-s-log) — handler not traced
at apps/mobile/src/screens/Home.tsx:2
? onOpenJob comes from the parent component; follow the parent
…

Here it is a limit of the analyzer, not a gap. How we know: Home.tsx receives onOpenJob as a prop, and its parent apps/mobile/src/App.tsx passes a function (open) that pushes the log:entry screen. The tool stops at the prop and says so. Without reading the parent, you could not tell which of the two it was, and the tool does not guess.

What it looks like in the viewer

node eb.mjs open --in demo opens the same map as one HTML page. These screenshots show only the synthetic demo.

The architecture view

  1. Target modules by stage. Jobs is outlined green, "exists". Safety reports, Daily log and Weekly reports are outlined amber, "exists, must grow". Invoicing is dashed violet, "missing: to build".
  2. The path. The solid line from Jobs to Daily log exists. The dotted lines from Daily log to Weekly reports to Invoicing are missing links. Together they are the "Log to report to invoice" path, and the red X on its chip means the path has a break.
  3. Layer table (bottom of the page, "Layer alignment (authored status)"): the implementation status that the team wrote down for each module in the field app, office app, shared logic, backend and sync. It is authored, not discovered from the code.

The Jobs Board screen

  1. Screen header: the Jobs Board, office web app, at /#/jobs, with the file that draws it.
  2. Gate and data: the client-side RequireAuth guard (a check in the app, not server security) and the table it reads or writes, "found by reading code, not by running it".
  3. Not checked: what this map has not examined (a running build, a save-and-sync round trip, production).
  4. What you can do here: the button "Archive first job" and its jobs (write) chain, marked "not a proven save".

The Jobs.tsx file view

  1. Screens that depend on the file: the Jobs Board.
  2. Buttons whose path goes through it: "Archive first job".
  3. Tests and verifiers that mention it: tests/jobs.test.tsx, by import. A candidate.
  4. Tables touched in this file: none; the write happens in the shared context, one hop away.

The demo has no findings or requirements, so its Trace tab is empty and its Maps tab shows a synthetic daily-log map instead of the Jobs feature. Those tabs, and the design inputs behind them, are for teams that keep a written design; see traceability.

Usage details

Prerequisites are the same as in the quick start; the one dependency is TypeScript, pinned in package-lock.json. init prints what it detected and what it could not, and drafts instances/<name>/brain.config.json; check it once. The instance name defaults to the repo's folder name, lower-cased (--name overrides it). Ask questions from the terminal with node eb.mjs q "save report" --in <name>, and rebuild after your code changes with node eb.mjs build --in <name>. Run from this folder, open also needs --in <name>.

Connect an agent (explicit opt-in)

Nothing is installed behind your back: no hooks and no global instructions. agent-setup writes the instructions, with this toolkit's real path filled in, into a file you name. Preview first:

node eb.mjs agent-setup --in <name> --for codex --file <path-to>/AGENTS.md --dry-run
node eb.mjs agent-setup --in <name> --for codex --file <path-to>/AGENTS.md

Use --for claude with a .claude/skills/<folder>/SKILL.md path for a Claude Code skill, or --for any for a generic block. A rerun changes nothing. Your own text in the file stays byte for byte. To remove it:

node eb.mjs agent-setup --in <name> --for codex --file <path-to>/AGENTS.md --remove

It refuses to overwrite a file it did not write and any path that goes through a link. Whether an agent then follows the instructions is up to the agent. The routine the instructions describe is in AGENT-CONTRACT.md.

More

License

MIT. v0.1, a pilot: expect rough edges.

About

SourceCompass: see how your codebase fits together. A local, evidence-backed map of screens, code, data paths and potentially affected tests, for people and coding agents.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages