Skip to content
CodeBook

System Map

What CodeBook knows about the system behind your repositories and the work that touches it — five list views, an Ask tab and a Docs tab, a node sheet with citations, the analysis that runs when a repository is connected, runtime nodes and production incidents, incremental updates on push and merge, very large repositories and monorepos, and what the map does not claim.

The System Map is what CodeBook knows about your system as typed rows: the repositories' modules, services, endpoints, data entities, outside systems, tests and patterns; the factories, workflows, stations, workers, cards, work orders and pull requests that change them; and the organization's own products, requirements and decisions. Every node names a real thing, and every edge between two nodes says how certain it is and where the evidence is.

The map is built by written rules over the static code graph CodeBook already keeps, the repository's deployment files, and the incidents and deploys that production monitoring reports. A model writes two things — the purpose summary of a repository, module or service, and the prose paragraphs of the generated docs — and both are always labelled as the model's, with the facts it was given listed beside them. No rule reads a model's text.

What the System Map does not do yet is listed in the implementation status.

Where it is

System Map is in the sidebar twice: in the organization group, before Settings, and in the workspace group, after the agent marketplace. Both pages show the same thing — the map of the organization that owns the workspace.

At the top of the page a scope picker chooses the organization (every repository's code nodes, plus the organization's own nodes) or one repository. With a repository chosen, a version picker lists its map versions; choosing one shows the counts that version recorded when it finished, while the lists below always show the current map.

The organization's own nodes — company, products, principles, customers, requirements, decisions — are written by organization administrators in an editor on the organization's System Map page, which also shows the feeds from linked products (see below).

The five views

There is no giant graph canvas. Each view is a set of lists you drill into — a row opens along its edges — and every row opens the same node sheet.

View What it lists
Architecture API endpoints, services, modules, data entities, external systems and queues, the patterns recognised in the repository, its Runtimes, and the organization's Production incidents
Dependencies Services and modules, and what they depend on, import and use
Product The organization's company, products, features, requirements, and decisions and incidents
Data API endpoints, services and data entities, with each row's personal-data, secret, payment and authentication flags
Work Stories, work orders, cards, pull requests, and the factories, workflows, stations and workers they run through

Two more tabs sit beside them. Ask is a read-only chat over the map; see Ask your system. Docs, shown when a repository is chosen, is the repository's documentation generated from the map; see Generated docs.

Lists are paged and searchable by name or path, with a filter by kind. In a monorepo, a package picker (searched on the server, 50 at a time) narrows every code tab to the nodes inside one workspace package; see monorepos. A node that stands for a factory or workspace row you may not open is not shown, and the list heading says how many rows it hid rather than pretending the list is complete.

What is in the map

Nodes have a closed list of kinds. Organization kinds: company, product, principle, customer, need, feature, requirement, decision, incident. Factory kinds: factory, workflow, station, worker, work order, story, card, pull request. Repository kinds: repository, module, service, API endpoint, data entity, queue, external system, pattern, file, symbol, test, runtime. Runtime nodes are read from the repository's deployment descriptors, and incident nodes also come from connected monitoring sources; see Production monitoring.

Edges have a closed list too — contains, depends on, imports, exposes, handles, reads, writes, publishes, consumes, uses external, tests, implements, modifies, owns, requires, part of, decided by, affected by, evidenced by, deployed to, runs, affects — and each is certain or possible. A static import is certain; a dynamic import whose target the parser could only narrow to candidates is possible, exactly as in the repository graph.

Every node and edge records where it came from: a rule, a person, a peer product or runtime. Rules produce the repository structure, the runtime nodes and the factory objects. People produce the organization's own nodes. Peers — a linked OpenBook or MadeBook workspace — produce product and governance nodes, covered below. Runtime marks what production reported: a monitoring source's incident or a deploy.

Flags are the work of rules, and each carries its evidence. A data entity's fields are checked against a closed list of column names and flagged pii, secret or payment when they match: a field named ssn or email is flagged, a field named notes is not, whatever it holds. An external system from the catalogue is flagged payment (Stripe, Braintree, PayPal) or auth (Firebase, Auth0, Okta).

Node detail

Selecting any node opens a sheet on the right, the way a card opens. It shows the node's kind, flags, provenance and its file and line, linked to the file on GitHub or GitLab. Then:

  • Purpose — for a repository, module or service with a summary, the model's text under the notice written by a model from N facts, with those facts listed: the rule's rows — endpoints, entities, dependencies, tests — that were the model's whole input. It is rewritten only when the facts change. A node with no model summary shows the rule's own sentence, labelled as such.
  • Used by, services and modules, APIs, data, external systems and queues, tests, recent pull requests, incidents, related requirements, work and code — the node's neighbours, grouped by what the other end is, each with its direction, whether it is possible, and the file and line it was read from.
  • Production — for a runtime, the commit it is Running per environment and since when; for a service or module, the runtimes it Runs in; for an incident, what it is linked to and the deploy running when it started; and Known incidents with severity, status and the provider's link. A card's node lists the incidents on components the card touches.
  • Citations — the node's own citation, K<source>:L<line> when it was read from a file and N<id> otherwise, and a K<source>:L<line> citation for every edge read from a file.

A neighbour opens in the same sheet, with Back. When a node has more edges than the sheet lists, or neighbours you may not see, the sheet says how many. Nothing is summarised away silently.

Connect a repository and the analysis starts

Connecting a repository queues a full analysis of it; attaching a repository that is already connected to another workflow queues one only if it has never been analysed. The progress is shown on the workflow's repository panel, at the top of the System Map page, and as a one-line status at the end of a card's Development panel. It shows the phase the job is in; files listed, mapped and skipped (by reason), and directories skipped without being listed; files read of the files to read, and what remains; anything the provider refused; provider requests used against the budget and the rule the budget follows; a wait for a provider's rate limit, with its reason; and counts of files, modules, services, endpoints, data entities, queues, external systems, tests, runtimes and patterns. Every count is read from the rows written so far. The one estimate is the time left, computed from the phase's observed rate and labelled an estimate from N done in S s; there is no progress bar unless both file numbers are known.

The phases, in order:

  1. Tree — the repository's file list at the default branch's head, through the same connection an agent's run reads with, kept as a mirror of directories and files so a restart resumes and a later build lists only what changed. Paths no analysis should read are skipped by rule — see what is skipped by default — and a directory skipped by rule is never listed at all. An organization administrator can add exclude patterns, up to 50 per repository.
  2. Files — each source file is read in batches (50 files a request on GitHub and GitLab) and its declarations and imports are indexed; documents are split into passages. A file whose blob hash has not changed since the last analysis is not read again. Deployment descriptors and monorepo workspace declarations are read; other manifests are listed, not read — their existence is the fact.
  3. Symbols, services, endpoints, data, external, tests, runtime, patterns — the rules below run over the indexed files. The runtime phase places a runtime node for each deployable a descriptor declares; see Production monitoring.
  4. Summary — purpose summaries for the repository, its modules and its services, only where the facts changed. Skipped, not failed, when summaries are switched off or the organization has no model.
  5. Embeddings — documents (READMEs, ADRs and other docs) are embedded for retrieval by meaning, with the embedding model named in the organization's System Map settings. Skipped when none is named. Code is not embedded.
  6. Ready. A ready or limited version then queues its generated docs.

The job is bounded and resumable. A scheduler tick works one job for about eight seconds and hands the turn back, its phase and position are written down as it goes, and a restart continues where it stopped rather than beginning again. How builds share the scheduler and the provider's rate limits is under large repositories.

Ready, or limited

The status reads SYSTEM MAP READY only when the analysis covered the whole tree. There is no cap on files and no fixed request budget of CodeBook's own. A version ends limited — shown as Built with limits — only for a written reason, read from the rows at the end of the build:

  • the provider refused a directory listing or a file read, each named;
  • a cap an organization administrator set was reached — files read per build or provider requests per build, under settings — and the sentence names the cap;
  • the tree is binary-only.

The status says in a sentence what was not covered — never a partial map presented as complete. A limited map is still a map: its views, node sheet and impact analysis work over what was indexed. An organization administrator can Rebuild at any time.

A file that cannot be read is marked with the reason and the build goes on. A build that fails outright — a revoked connection, a branch with no head — is an error with its sentence, and the previous ready or limited version stays the one the pages answer from; the status says Last analysis failed · showing version N.

How the map is derived

Each node kind comes from a written rule over the indexed files, and a rule that finds nothing emits nothing.

Node The rule
Module One per directory holding a package manifest or a declared module root, and one per top-level directory with at least five indexed files. A file belongs to the deepest module containing it
Service A module that declares API routes (a Next.js page or layout does not count), has a main entry file such as main, server, index or app, or has its own Dockerfile
API endpoint Every framework route the code graph records (Next.js, Express/Koa, MasterController, FastAPI/Flask, Django, Spring, Laravel), with a handles edge to its handler symbol (or to its file when the handler cannot be found) and an exposes edge from its service or module. A MasterController endpoint also reads and writes the data entities its controller action names — see below
Data entity A model recognised by its ORM: masterrecord, TypeORM, Sequelize and Mongoose; JPA; Django and SQLAlchemy; GORM, sqlx and the MongoDB Go driver; Diesel; Eloquent; Prisma schemas; and SQL CREATE TABLE. Its fields and relations come from the declaration. A file that imports the entity's file gets a reads edge marked possible — the import proves reach, not a read
External system and queue An import that matches a catalogue written in the code — payments, email and SMS, cloud SDKs, message brokers, caches, databases, search, model providers, error tracking, identity providers. A queue import in a file whose names say publish or consume adds a possible publishes or consumes edge
Test A file matching test path patterns or importing a test framework. Its tests edges follow resolved imports up to three hops: one hop is certain, two or three are possible, never through another test file
Pattern Only past a threshold written in the code: layered when at least 70% of route-handler files (and at least two) reach a data file through a service file; event-driven when files both publish to and consume from a queue; monorepo at two or more package roots; frontend/API split when a module with UI files or pages sits beside a module with API routes; microservices at two or more services with their own Dockerfiles. Below the threshold no pattern is emitted

The languages are the code graph's: JavaScript and TypeScript, Python, Go, Java, Rust and PHP, plus two small grammars for Prisma schemas and SQL. C# and Ruby are not supported.

MasterController routes

MasterController is the Node framework CodeBook, OpenBook, MadeBook and Bookbag SSO are built on, and the map reads its routes. A routes file is config/routes.js, either at the application root or in a component (components/<name>/config/routes.js). The map reads:

  • router.route(path, "controller#action", verb), where the path may hold :params;
  • router.resources(name), which declares the seven RESTful routes;
  • router.group(prefix, …), with its prefix applied;
  • master.map.get(…) and the other minimal API routes.

It reads a route only from a file that imports mastercontroller.

  • The handler is found the way the framework finds it: the method <action> of <root>/app/controllers/<controller>Controller.js. The endpoint cites the route's line and the handler cites the method's line. When the controller file or the method is not there, the endpoint is kept, its summary says which file was looked for, and no handler is invented.

  • What the action does. The endpoint's summary states what the static read found:

    • whether the action calls authorizationService.guard, directly or through a helper method of its own class;
    • which beforeAction filter runs before it;
    • which models it reads through a data context, and which it adds or removes.

    Those models become reads and writes edges to the data entities. The API reference page and impact analysis use those edges.

  • Nothing is guessed. A route declared in a loop over a literal list, like SSO's for (const action of [ … ]), becomes one endpoint per value, marked possible. A route is left out rather than invented, and the module's facts count it with its line and the reason, when:

    • its path or verb is built at run time;
    • it has no verb (MasterController has no default verb);
    • the framework would refuse it at startup.
  • Measured on Bookbag's own repositories: codebook-app 607 backend routes, OpenBook 801, MadeBook 331, all with their handler found. SSO has 260 (94 of them from loops); 251 have their handler found, and 9 do not, each with the reason in its summary.

Organization nodes and linked products

The map's upper layers come from people and from your linked products, not from the code.

What a person writes. Organization administrators add, edit and remove the organization's own nodes and the edges between them — part of, requires, implements, decided by, affected by — in the editor on the organization's System Map page, and can cite a knowledge source and line as evidence. One end of an edge may be a repository node, so a module can implement a requirement. Members read. A node a rule derived or a peer sent is not editable here; the editor says where to change it.

Factory objects. Factories, workflows, stations, workers, work orders, stories, cards and pull requests are placed by rule from the rows themselves — factory contains workflow contains station contains card, a worker owns its station, a work order contains its cards, a card implements its story, a pull request implements its card and modifies the files and modules it changed. The scheduler brings a few factories up to date each minute, and nothing here is typed in.

From OpenBook. A linked space sends its product hierarchy: the space becomes a product node, its epics feature nodes, its stories requirement nodes, and the customers and posts from its feedback customer and need nodes. A card made from an OpenBook story implements that requirement.

From MadeBook. A linked workspace sends its governance: policies, their rules and constitution rules become principle nodes, decisions become decision nodes, and policy violations become incident nodes. A decision scoped to a path is joined to the modules and services under it with a possible decided by edge, and a MadeBook architecture map, when the workspace has one, adds service, data, external and queue nodes.

Both feeds arrive as signed, idempotent peer messages, and CodeBook also asks each linked product for changes every 15 minutes and for a full snapshot once a day, which is what removes an item the peer deleted. The organization's System Map page lists each feed with when it was last read, and administrators can Read now. Peer nodes carry the peer provenance and belong to the link that sent them. When the link ends they disappear from every page and every run at once, because the link's status is checked each time a node is read. The OpenBook and MadeBook halves of these feeds ship with those products.

Incremental update

After the first analysis the map is not rebuilt from scratch on its own. A push to the map's branch — the repository's default branch — or a pull request that merges into it becomes an incremental update: only the files that changed are read again, the rules run again over the stored graph, and change rows are written only for what actually changed. Pushes to other branches, tags and branch deletions are acknowledged and ignored.

How the changed files are found, in order:

  1. The push's own list of paths, when it names 300 or fewer and was not forced. Nothing is listed.
  2. A comparison of the two commits, where the host can answer exactly: GitHub's compare on a fast-forward under its 300-file list, GitLab's compare under its diff cap. Nothing is listed.
  3. Otherwise a walk of the tree from the root, descending only into directories whose hash changed.

In every case only the changed files are read. The rule phases then read every page of the stored graph and write only what changed; on a very large repository that is most of an update's time (see measured).

A burst of pushes is one update. With an update already queued and not yet started, a new push is folded into it: the update moves to the newest commit, and the version it would have built is marked superseded, with a sentence saying a newer push arrived before the update started. Two jobs of one repository never run side by side, and an older commit can never finish after a newer one.

Each update is a new map version, keyed by the repository and the commit, chained to the version before it, with the added, changed and removed nodes and edges written down. The same commit arriving twice is one version. When a version is ready, the impacts of cards on workflows that follow the repository are marked stale, open cards are recomputed against the new map, and the repository's generated docs are refreshed.

The version picker lists versions newest first with their status — building, ready, limited, error, superseded — trigger, commit and recorded counts. Only Rebuild starts a full analysis again.

Pushes arrive through the repository's webhook, which CodeBook registers with the push event and repairs on hooks registered before it did; see push webhooks.

Large repositories

A build has no file cap. The limits are stated as they were measured.

What The rule
Files per build No cap. The measured ceiling is 250,000 indexable files: builds were run end to end at 200,000 files on SQLite and Postgres and at 250,000 on SQLite. Past it a build still runs; nothing stops it, and nothing past it has been measured
Requests per build No fixed budget. The budget grows with the repository: 200, plus one per directory listed a level at a time, one per file to read, one per summary and one per embedding batch, each added when its size is known. Batched reads spend about a fiftieth of the file allowance
An organization's own caps Files read per build and Provider requests per build, under Organization settings → System Map, set by organization administrators. Empty means none. A build that reaches one ends limited and names the cap
Time per tick A tick works one job for up to eight seconds and hands the scheduler back; a step that started before the deadline finishes first (the longest tick measured was 8.1 s)
The event loop The build runs inside CodeBook's API process and yields once 50 milliseconds have passed, so other requests are not held behind it for long (the longest hold measured at 200,000 files was 449 ms)
Provider rate limits Before every provider request the build reads what the host last said about its rate limit. When the host's remaining allowance falls to 10% (never fewer than 50 requests) it waits for the reset, keeping that reserve for pull-request sync and runs on the same token. A host that answers with a rate limit is waited out the same way. The wait and its reason show in the progress

Measured builds

Measured for the release on an Apple-silicon laptop, with a repository host that has since been removed from CodeBook and a synthetic monorepo of 200 workspace packages (1,000 JavaScript and TypeScript files each, with a vendored, a built and a binary file per package), then one commit changing 20 files; and the same shape at 250 packages.

Build Database Files read Time Provider requests
Full, 201,003 files listed Postgres 16 200,403 3.5 min 4,413
20 files changed Postgres 16 20 55 s 2
Full, 201,003 files listed SQLite 200,403 1.3 min 4,413
20 files changed SQLite 20 33 s 2
Full, 251,253 files listed SQLite 250,503 1.8 min 5,515
20 files changed SQLite 20 34 s 2

The same 200,000-file first build through GitHub would spend about 4,200 requests — one head, a handful of listings, about 4,000 GraphQL batches of 50 files — inside one hour of GitHub's 5,000-point GraphQL budget; that is a count of requests, not a timed build. The table is one synthetic repository on one machine, not a promise about yours.

Sharing the scheduler

  • One job per organization at a time. Claimable jobs are offered to the organization whose map work ran least recently, and at most one job of an organization runs at once across processes. One huge repository never starves another organization's small one.
  • Leases. A job is claimed onto a two-minute lease and released at the end of its tick; a lease a dead process held runs out and the job is taken up again.

What is skipped by default

Each skip carries a code the tree records and a sentence the page shows:

  • vendored and installed dependencies — node_modules/, vendor/, third_party/, Pods/, virtual environments and the like;
  • build output — dist/, build/, target/, .next/, coverage/ and the like;
  • tool caches;
  • generated code — *.pb.go, *_pb2.py, *_pb.js, *.generated.*, *.g.dart, *.designer.cs, bundles and __generated__/;
  • lock and system files, minified files and binaries.

A directory skipped by default is recorded once and never listed, so a vendored tree costs no request and no row per file. Files over the 500,000-byte read limit, and files whose content turns out to be binary, are listed and never read.

Exclude patterns are set per repository beside the build status, up to 50, and apply on the next rebuild. A plain pattern excludes more (generated/, **/*.snap). A pattern that starts with ! takes a default skip back: !vendor/acme/** reads one vendored library. The editor lists everything skipped by default under What is skipped by default.

Monorepos

A repository's workspace declarations are read — every other manifest is only listed — and each declared package becomes a module, named by its package and marked as a workspace package in its summary and facts:

npm and Yarn workspaces, pnpm pnpm-workspace.yaml, Lerna packages, Nx (nx.json with each project.json, or workspace.json), Turborepo turbo.json, Rush projectFolder, go.work use, Cargo [workspace] members and excludes, Maven <modules>, Gradle include (Groovy and Kotlin), pyproject [project] name, Poetry, and uv [tool.uv.workspace].

A wildcard member must hold a manifest to count, except in Gradle. The directory that declares the workspace is its root, and the monorepo pattern counts workspace packages. The System Map page's package picker pages every code tab by package.

Settings

Under Organization settings → System Map, organization administrators choose whether summaries are written by a model (on unless switched off; they use the organization's model), name the embedding model for documents (empty skips the embeddings phase and the map is still built), and may set caps on one build — files read per build and provider requests per build, empty for none. Production monitoring is on the same page, below them; see Production monitoring. Members see the settings. Saving is revisioned: a stale form is refused and reloaded rather than overwriting somebody else's change. Exclude patterns are set per repository, beside the build status.

Repository nodes are read by every member of the organization that owns the repository. Nodes that stand for a factory, workflow, station, card, work order or worker are shown only to people who may open that factory or workspace, checked row by row.

Limits, and what is not claimed

  • CodeBook never runs the code. The map is built from static parsing of files read through the repository connection. Nothing is executed, imported, compiled or deployed, and a route in the map is a route in the syntax, not proof that it is mounted at runtime.
  • Outside systems come from imports only. Hostnames in string literals and environment variables are not read, so a service reached over plain HTTP with a URL from configuration does not appear.
  • Data reads are possible, and writes are not derived. A reads edge means a file imports the entity's file; no rule decides which code writes an entity.
  • Incidents are what a source sends. Incident nodes are MadeBook policy violations and the production incidents a connected monitoring source reports, linked by a mapping or an exact name and never guessed. Production issues and reverts reported through inbound triggers are read directly by impact analysis and the context pack, not placed as nodes. Runtime nodes come only from deployment descriptors in the repository.
  • Summaries and docs prose are a model's text. They are written only for repositories, modules and services and for the prose sections of the generated docs, labelled, shown with their facts, and nothing that decides anything reads them.
  • A push re-reads the whole stored graph. Only changed files are read, but the rule phases read every page of the stored graph on each update; on a very large repository that is most of the update's time.
  • Map files are not ambient knowledge. The analysis stores repository files as knowledge sources in a repository scope, but that scope is never part of a worker's default knowledge. Map items reach a run only through the context pack, ranked and cited, so connecting a large repository does not flood every station with its contents.
  • A limited map says so in its status, and an error keeps the previous version current.
  • Patterns need their thresholds. A repository with one service and no broker has no architecture pattern node, and that is correct.
  • The map is not an org chart. People, teams and their access come from SSO. A worker node is an installed worker; an owns edge is a fact from the rows, not a permission.
  • Peer nodes need their link. Requirements and decisions from OpenBook and MadeBook are as current as the last message received, and they leave pages and worker context when the link ends.

Next

System impact and risk routing — what the map is for once it exists: a blast radius on every card, and routes that change with it. Ask your system — questions answered from the map, with citations. Generated docs — the Docs tab. Production monitoring — incidents and deploys from production.