name: codebase-atlas description: >- Scan a repository into a graph with the atlas CLI, and author the .codebase-index/_story.json narrative the Codebase Atlas story view reads. Use when asked to map, scan, or visualize a codebase with Atlas, to write or update a repo's story file, or to explain a codebase to a non-programmer.
codebase-atlas
Codebase Atlas (~/dev/codebase-atlas) turns a repository into a graph and
draws it three ways: a story of how the code works, a 3D map of the
directory tree, and a flow diagram of imports. The CLI hands the same graph
to an agent as JSON.
The CLI
cargo install --locked --path ~/dev/codebase-atlas/src-tauri --bin atlas
atlas scan <repo> # RepositoryGraph JSON to stdout
atlas scan --pretty -o map.atlas.json <repo>
atlas serve [--port 7420] [--token CODE] <repo>...
atlas scan writes only graph JSON to stdout; diagnostics go to stderr, usage
errors exit 2, scan failures exit 1. Safe to pipe.
The graph carries nodes, containment and import edges, per-file declarations,
the bindings that cross each import, .codebase-index/ summaries as
node.description, and story when the repo has a story file.
Useful reads without opening the app:
atlas scan . | jq '.stats' # files, lines, languages
atlas scan . | jq -r '.warnings[]' # what the scan could not do
atlas scan . | jq '.story.actors[].name' # the narrative, if any
atlas serve exposes GET /v1/health (open), GET /v1/catalog and
POST /v1/scan (both Authorization: Bearer <pairing code>). Tokens normalize
— non-alphanumerics stripped, uppercased — so abcd-2345 == ABCD2345.
Requested paths must sit under a shared root.
The story file
.codebase-index/_story.json is what the story view draws. It is authored,
not derived: the parts that matter most to a reader — the person typing, the
chat service, the model being called — are not files, so no scan can invent
them. A story built only from in-repo modules is just the flow view with fewer
boxes; that is the failure to avoid.
{
"summary": "One paragraph a non-programmer can read.",
"actors": [
{ "id": "person", "name": "Someone in Discord", "role": "person",
"blurb": "Anyone chatting with the bot in a server or a DM." },
{ "id": "front-door", "name": "The front door", "role": "door",
"blurb": "Every request lands here first. It checks who is calling.",
"modules": ["apps/service/src/app.ts", "packages/api-client"] }
],
"flows": [
{ "from": "person", "to": "front-door",
"carries": "a message someone typed",
"returns": "the reply, posted back in the same place" }
],
"journeys": [
{ "name": "Someone asks a question", "blurb": "The ordinary path.",
"steps": ["person", "front-door", "person"] }
]
}
Rules the renderer depends on
roleis the column, in this order:person,surface,door,core,store,external. There are no coordinates — naming the role honestly is the layout. Unused roles collapse instead of leaving a gap.- Do not put sequential actors in the same role. Two things that hand work
to each other land in one column and draw as an awkward side-loop. Chat
bodies, a terminal, a phone relay are
surface; the single API boundary they all call isdoor. modulesare scan paths, and an actor is a role, not a directory — one actor can list several, and people and outside services list none.- One arrow carries both directions. Write
carriesand, when something comes back,returns. Never add a second flow for the reply; a round-trip journey would then double every arc. stepsare actor ids. Each consecutive pair needs a flow in one direction or the other. A step taken against a flow renders as itsreturns.
Writing the prose
Blurbs and carries text are the whole product. Aim at a reader who has never
opened a codebase.
- Name roles, not packages: "His Discord accounts", not "discord-bridge".
- Say what travels in words: "the message, and who sent it" — never a type name.
- Blurbs wrap to 5 lines and clip; keep them to one or two sentences.
- Journeys are what make it flow rather than another box diagram. Write 3–5, each following one piece of data all the way there and back.
Workflow
- Read
.codebase-index/_root.mdand the top-level*.mdentries for the repo's own account of itself. Fall back to READMEs and entry points. - Draft actors first, roles second, then flows, then journeys.
- Verify every
modulespath against the tree, not against the index..codebase-index/drifts from HEAD, so paths it names may be renamed or gone. - Scan and read the warnings — this is the real check:
atlas scan <repo> | jq -r '.warnings[]'
Unknown actor ids, stale module paths, and journey steps with no flow behind
them are dropped and reported here. The scan never fails on a bad story; it
renders the part that is still true, so silence in warnings is the pass.
- Eyeball it in the app when the story matters:
pnpm tauri devin~/dev/codebase-atlas, then Scan directory on the repo.
Notes
- The story file sits beside the markdown mirror the
codebase-indexskill maintains, but is a separate artifact with a separate consumer. Updating one does not update the other. - Whether
.codebase-index/is committed is the repo's call. Where it is gitignored, the story file stays local and does not travel with the repo — worth saying out loud when writing one. - Port 7420 is Atlas's default and a desktop Share session holds it. A
stale listener silently answers
atlas servecurls with a different pairing code, which reads as an auth bug; checklsof -ti:7420before debugging a 401. - Atlas is read-only: it reads metadata and bounded text files, and never sends file contents anywhere.
atlasis a snapshot:cargo installcopies the binary, so a change to the Rust scan side does not reachatlas scanuntil it is reinstalled. After touchingsrc-tauri/, run the install line again before regenerating a map, or you will debug output the new code never produced.- Clicking an import arc (3D map) or route (flow view) opens what crosses it — the named bindings, carried up through aggregation. Useful for answering "what does this dependency actually mean" without reading either file.
