@inixiative/atlas
v0.1.0
Published
The map of the codebase — @atlas code annotations + a seam registry + a drift-proof MAP.md. A map that can only assert what is mechanically true.
Maintainers
Readme
atlas
The map of the codebase. atlas reads @atlas annotations declared at the top of each file,
validates them against a repo-owned concept registry, and generates a MAP.md that cannot drift
on the structural facts — because atlas only ever asserts what is mechanically true (what exists,
how it connects), never maturity or correctness.
It's a Biome-shaped tool: a small CLI plus a .atlas/ config folder. The tool is generic; your
repo defines its own vocabulary.
/**
* @atlas
* @kind controller
* @partOf feature:tenancy
* @uses primitive:authz, infrastructure:redis
*/Why
Hand-maintained maps (FEATURES.md, docs, prose) drift from the code. atlas makes the map a projection of the code: every file declares traversable concepts — what it is, what it's part of, what it uses — so the repo is explorable by concept instead of by crawling folders. "Show me everything that touches caching" becomes one traversal.
The core discipline: meaning emerges from the intersection of several true edges, not from one hyper-specific label. Keep the vocabulary broad but closed; apply it liberally.
Install
bun add -d @inixiative/atlasatlas is Bun-native (it imports your .atlas/*.ts config directly).
Configure
A consuming repo gets a .atlas/ folder. atlas ships a sensible default kinds vocab; the
repo owns its concept registry.
.atlas/
config.ts // stamp rules (path → tags) + ignore + reference resolvers
kinds.ts // @kind vocab — extends atlas's defaults
concepts.ts // the concept registry — repo-OWNED, structure only// .atlas/concepts.ts — structure only, no status/note. YOU define the concept classes
// (feature/primitive/…) and the constituent categories (module/package/…).
import type { ConceptRegistry } from '@inixiative/atlas';
export const CONCEPTS: ConceptRegistry = {
'feature:tenancy': { module: ['organization', 'space'], docs: ['AUTH.md'] },
'infrastructure:redis': { docs: ['REDIS.md'] },
};// .atlas/config.ts — stamp rules compose; explicit always wins.
import { defineConfig, partOfFor } from '@inixiative/atlas/config';
export default defineConfig({
include: ['apps/**/*.ts', 'packages/**/*.ts'],
ignore: ['**/*.test.ts', '**/index.ts'],
stamp: [
{ include: '**/controllers/**', kind: 'controller' }, // @kind from a structural glob
{ include: 'apps/api/src/modules/$1/**', partOf: partOfFor('module', '$1') }, // @partOf from a capture
],
references: { docs: (v) => `docs/${v}` }, // for reference-existence checks
});A complete, commented set you can copy into your repo's .atlas/ is in
examples/atlas-config/ (kinds.ts, concepts.ts, config.ts).
CLI
atlas graph # reverse indexes: concept → files, file → concepts, doc → concepts
atlas check # presence + vocab existence + reference existence (the CI command)
atlas coverage # unannotated files; @uses curation buckets; unresolved memberships
atlas generate # write MAP.md from the annotated tree
atlas report # coverage gaps + concept graph → COVERAGE.md (Mermaid) and atlas.html (Cytoscape)
atlas stamp [dir] # write/refresh @atlas blocks from the rules (the patcher; dry-run by default)Common flags: --root <dir>, --json, generate --stdout, stamp --write, stamp --overwrite,
coverage --min/--ratchet, report --out <dir>/--md/--html.
For AI agents
atlas exists largely so agents stop grab-bagging files and answering from stale labels. Drop this
line into your agent's system prompt / CLAUDE.md / AGENTS.md so it navigates by concept
instead of crawling folders:
This repo is mapped by atlas. To find code by concept instead of by filename: read
MAP.mdfor the concept overview; runbunx atlas graph --jsonfor the reverse indexes (concept → files via@partOf, concept → consumers via@uses); and read a file's top-of-file@atlasblock (@kind/@partOf/@uses) before its body. Prefer these overgrepfor "what touches X" / "what's part of Y" questions.
Why it helps: the agent gets the high-altitude map without reading the tree, answers "everything
that touches caching" in one graph --json call, and learns a file's role/edges from its block
before opening it. In an A/B test on a repo with a transitive dependency, agents given this line
used atlas graph and solved a "what reaches redis (directly or transitively)" question in ~2 tool
calls; agents left to grep took 2–3× as many and risk missing the transitive edge entirely.
Visualize
atlas report emits two artifacts:
COVERAGE.md— diffable, GitHub-native: a totals table, a Mermaid coverage pie, a per-category gap table (required@kind/@partOfgaps split from the@usescuration buckets), and a Mermaid concept-dependency graph. Categories group by effective concept — a file's declared@partOf, or the rules' predicted concept when unannotated — so you get a per-concept work plan even at 0% coverage.atlas.html— a self-contained interactive graph (Cytoscape.js): concepts grouped by class (compound nodes), coloured by coverage; click a concept to drill into its file list, click to highlight its dependencies (traverse). No build step — open it in a browser.
The annotation model
| Question | Tag | Value | Notes |
|----------|-----|-------|-------|
| What is this? | @kind | closed enum | 1+, e.g. entrypoint, route (a role, not a layer) |
| What is it part of? | @partOf | class:name concept(s) | membership; multi is normal |
| What does it use? | @uses | class:name concept(s) | dependency, load-bearing only |
| What does it build? | @constructs | factory output | constructors only |
All axes are multi-valued (comma-separated on one line). @atlas opens the block.
Writing a block (for agents & humans)
A top-of-file JSDoc block, above the imports (below a shebang if present):
/**
* @atlas
* @kind controller
* @partOf feature:billing, superadmin
* @uses primitive:authz, infrastructure:redis
*/Rules of thumb:
@kindis a ROLE, never a layer. Use the file's role(s) from the vocab. Never putfeature/primitive/infrastructurein@kind— those are concept classes, expressed via@partOf. A file can hold several roles (constructor, registry).@partOfis membership — the concept(s) this file composes (remove it and the concept breaks). Multiple is normal and expected: a feature has many controllers/routes/entrypoints; a file can be part of a feature and a cross-cutting tag (feature:inquiry, superadmin). The reusable helpers that build something belong to it — e.g.makeControllerand the route-template helper services are all@partOf primitive:routeTemplates.@usesis dependency, LOAD-BEARING only — a concept this file depends on but isn't part of, where someone reasoning about that concept's blast radius needs this file. Not every import. Skip incidental touches (onedb.x.update()through the request context is not "using" the database). Write@uses noneonly after a human/agent looked and it genuinely uses nothing load-bearing; otherwise omit the line (= uncurated).- Validate names against the repo's
.atlas/—@kind∈kinds.ts;@partOf/@usesmust name a concept that exists inconcepts.ts. - Prefer several broad-true tags over one narrow tag — meaning emerges from the intersection of true edges, not from one hyper-specific label.
@uses is never auto-stamped
Absence is meaningful, so atlas leaves @uses out of stamping entirely:
- no
@usesline = uncurated (nobody filled it in) @uses none= curated-empty (a human looked; it uses nothing load-bearing)@uses? x= proposed (a patcher suggestion awaiting acceptance)
coverage reports these as distinct buckets.
The patcher: atlas stamp
Blanks are fillable on demand — the eslint --fix shape. Always dry-run by default; pass
--write to apply.
- Targeting —
all(default), a folder, or a single file. - Additive (default) — fill only what's absent; never modify an existing tag; never touch
@uses. - Overwrite (
--overwrite) — resync the derivable axes (@kind/@partOf) to the current rules; never overwrites curated@uses. A@atlas pinblock is exempt.
CI
atlas check is the CI primitive — it exits non-zero on any problem, so wiring it in is just
running it in a workflow (no separate package needed). Copy-paste examples live in
examples/ci/: a full-repo GitHub Actions workflow with a MAP.md freshness
gate, an incremental PR variant, and a pre-commit hook. The recommended rollout on an existing
codebase is warn-only → incremental enforcing → fully enforcing:
atlas check --warn-only # prints problems, never fails CI (rollout start)
atlas check <path> # enforce only changed paths (skips registry-wide reference checks)
atlas check # enforce the whole repoGate coverage the same way — a percentage floor or a ratchet that forbids regressions (ideal for a repo starting near 0%):
atlas coverage --min 80 # fail below 80% annotated
atlas coverage --ratchet # fail if unannotated count exceeds .atlas/coverage-baseline.json
atlas coverage --update-baseline # record the current count (commit the baseline)Enforcement: existence, NOT correctness
atlas check verifies annotations exist and use valid vocabulary — presence of a block, that
@kind is in the vocab, that @partOf/@uses name a concept that exists, and that a
concept's doc references resolve. It explicitly does not reconcile the import graph, judge
whether a @partOf is "really true," or derive any status. Those are fool's errands that trade a
clear structural guarantee for a fragile proxy.
License
MIT
