@dogfood-lab/atlas

中文文档
1.26.0发布于 2026/10/01MITES Module构建来源已验证近 30 天下载 2760

Read a repository and write the page that says how it works: check the map in CI, answer agents from it over MCP, and say what will break a workflow before it runs.

原始使用文档
文档目录7 节
  1. Use
  2. For agents: atlas mcp
  3. What it reads
  4. What it cannot see
  5. Errors
  6. Private repositories
  7. Part of testing-os

@dogfood-lab/atlas

An isometric blueprint on a dark drafting sheet: a door on the left where work enters, conveyors and rollers carrying it through a machine, and shelves of boxes on the right where it is kept.

Atlas reads a git repository and writes a page that says how it works: what comes in, what runs, where it lands, who reads it, what breaks what, and where to start reading. Nothing in the page is written by a person. It is derived from the workflows, the manifests, the imports, the writes and reads in the code, and the git history, and it is regenerated whenever the repository changes.

The page is for anyone who has to understand a repository they did not write: a new contributor, a reviewer, an operator, or a model.

Use

npx --yes @dogfood-lab/atlas init
npx --yes @dogfood-lab/atlas map
npx --yes @dogfood-lab/atlas check [--strict]
npx --yes @dogfood-lab/atlas explain <path-or-part> [--ref <ref>]
npx --yes @dogfood-lab/atlas gaps [path-or-part] [--ref <ref>]
npx --yes @dogfood-lab/atlas mcp

init proposes atlas/boundaries.yaml: the named parts of the repository and the globs that own them. The proposal leaves no tracked file in no part: one part per project (a workspace member, or a directory with a manifest, .csproj and go.mod included) and a part for what each directory's projects leave. Edit the names and globs if the proposal is wrong. The one line a person may add is summary. init also adds atlas/** to an existing .vscodeignore, atlas/ to an existing .npmignore when the manifest has no files list, and atlas/ to .prettierignore when prettier is used, and says what it added.

check fails when the committed map no longer matches the tree. When that happens after a change you meant to make, run map and commit the regenerated atlas/ files with the change; never edit the page by hand, and never change the code to satisfy the map.

map writes four files under atlas/:

FileWhat it is
README.mdThe page. GitHub renders it when anyone opens the folder.
page.jsonThe same sections as data, for sites and tools.
structure.jsonEvery tracked file in its part, the import edges between parts, the doors, the landing places and their readers (each writer and reader with how it was found: ast, config, text or weak), and the order of calls inside the files the doors run. For tests: each workflow's test runs (the runner, the scripts and targets that reach it, and whether it collects coverage or writes JUnit results), the runners whose tests reach each part, the test files no workflow runs and those a runner's configuration leaves out, the framework each test file is written for, the files a test runs or spells the name of, and the failure paths in each code file. Byte-deterministic.
statistics.jsonWhat changes together over the last 180 days, dated.

Each file records the Atlas version that made it (engine), and the page's dated line names it: "Mapped at from commit by Atlas ."

check compares the committed map with the working tree and fails when a part gains or loses a dependency, a file changes part, a new file belongs to no part, a named part matches nothing, or a file belongs to two parts. Run it in the test job so the map moves with the code. A repository with no atlas/ directory is a notice and exit 0, so adopting Atlas reddens nothing.

check also prints notices: facts that leave the exit code alone. Two are about a workflow. ATLAS_DOOR_TOOLCHAIN: a job pins a Node version that the tool a step runs does not accept, read from the pin and from the tool's engines in the lockfile of the step's directory ("Deploy site pins Node 20 and runs astro build; astro 7.3.3 requires Node >=22.12.0 and refuses to start."). ATLAS_DOOR_LOCKFILE_PLATFORM: a job runs npm ci on a platform for which the lockfile holds no native binding, the mark of a lock written on another system. A third, ATLAS_MAP_ENGINE_OLDER, says the committed map was made by an older Atlas than the one running. Each names the lines it was read from and what to do, and check --strict exits 1 when there is any notice. The door checks read committed files only and never predict a run; what they could not judge (no setup step, a version only a run can know, a self-hosted or container runner, a lock they cannot read) is said as not judged, never as a finding.

gaps says what no test reaches and what should reach it, for the repository, a part, a directory or a file:

  • what CI runs, and the runner behind each run;
  • which parts and files tests reach, and how: a test imports the file, runs it, holds tests a runner finds in it, or spells its name in a string Atlas cannot follow;
  • the code gaps, ranked (on the path of a door that ships or runs in CI first, then fan-in, changes and failure paths), five shown with a count of the rest;
  • apart from them, the test files no workflow runs, coverage CI does not collect, and the installed commands nothing runs.

Facts come first. Each suggestion after them names its rule (G1 to G6 in testing-os's docs/atlas-test-gaps.spec.md), the facts that triggered it and the source of what it suggests: the house standard first, then what the fleet does, then outside documentation. Reach is not proof a test exercises a file, so Atlas says "no test imports or runs this", never "untested". It reads the committed map, or with --ref <ref> the map at a ref the clone already holds, never maps, writes nothing and makes no network call; --json prints the same answer as fields. Every rule was held to a precision bar over 79 repositories before it shipped (docs/atlas-test-gaps.fleet-check.md in testing-os).

explain says what a file, a directory or a part is in the system, for a person about to edit it or an agent in a coding session: its part, the door that runs it or passes through its part, what its part imports and who imports it, where it writes and who reads that, the order of work inside it, and what it changes with. Given a place that code writes or reads, it also says who writes it and who reads it. It reads the committed map and never maps again, so it answers at once and names the commit it answers from. --json prints the same facts for a machine. Given a workflow file, it prints the door: what triggers it, each job with its runner, environment and pinned versions, its steps and the programs they run, what it sends, what it reaches, the permissions it asks for by name, and any finding on it.

With --ref <ref>, explain and gaps answer from the map at a ref the clone already holds, such as origin/main: files are read at that ref, nothing is fetched, and the last line says which ref answered and how far it is from the checkout. When the checkout has no map and its fetched upstream holds one, the message names that ref first. In a directory that is not a git repository but holds atlas/, both answer and say "an exported tree: history and freshness not checked".

For agents: atlas mcp

atlas mcp lets an agent ask the committed map questions during a session, over the Model Context Protocol. The agent's client starts it and talks to it on stdio. It answers for the git repository of the first root the client offers, or else of the directory it was started in. With Claude Code:

npm i -g @dogfood-lab/atlas
claude mcp add --scope user atlas -- atlas mcp

Any other client starts the same command, atlas with the argument mcp. On Windows a global npm command is a .cmd file, which a client cannot start directly, so give the client cmd /c atlas mcp, or node with the package's cli.js and mcp.

ToolWhat it answers
atlas_overviewThe repository: its parts, every door with its trigger, what it runs and sends and how far it reaches, the runtime of its jobs and any finding on it, the main flow, and where to start reading.
atlas_explainOne file, directory or part, as atlas explain answers it, including who writes and who reads a place. A workflow file is answered as its door.
atlas_reachWhat a change to given files reaches: the doors that run them or pass through their part, and the files and parts that import them or read what they write, production and tests apart.
atlas_changesWhat changed structurally between the map committed at a commit and the map it answers from: imports between parts (a new cycle first), doors, writers and readers of places, parts, and new files in no part.
atlas_check_changeWhat a change does before it is committed: the tests that reach the changed files, the doors that run them, imports between parts gained or lost, files in no part, and whether the map must be regenerated. For each changed code file it says how tests reach it, or that none does and the failure paths it holds as it is now. It reads only the changed files again. A changed manifest, workflow, boundary file or configuration the engine reads, or a deleted file, gets "a full refresh is needed" instead. When a workflow, a package-lock.json or a package.json is among the changed files, it also gives the findings on the doors they touch, read from the tree: the moment before a push.
atlas_test_gapsWhat no test reaches and what should, as atlas gaps answers it: facts in groups of one basis, then the suggestions apart, each with its rule, the facts that triggered it and its source.
atlas_refreshMaps the checkout again in the background, into a cache outside the repository. Later answers use the new map once it is complete, and calling it again reports progress.

Every answer begins with where it came from: the map's commit, the Atlas version that made it, and any file it names that changed after the map. Every tool but atlas_refresh takes ref, a ref the clone already holds: the answer then comes from the map at that ref, files are read at it, and the provenance names the ref, its commit and how far it is from the checkout (atlas_check_change takes it only when the checkout holds the commit that map was made from). When the fetched upstream holds a different map and commits the checkout lacks, the provenance says so and names the ref to ask with; Atlas never switches by itself. In a directory that is not a git repository but holds atlas/, the tools that only read the map answer and say "an exported tree: history and freshness not checked". Every fact carries its basis (parsed, declared, text, weak, history, unresolved or outside), and every answer lists what Atlas cannot see for that question. An answer is at most 8 KB of JSON, or 64 KB with full: true, most important first. A list cut to fit says so, and a cut list carries a cursor for the rest, at the top of an answer and inside an entry too large to show whole. part keeps the entries in one part, and kind keeps one kind of fact. A failure is a tool error with the same fields the CLI prints: the code, one sentence, what changed and what to do.

The sidecar only reads. Git runs only read commands, with optional locks and the filesystem monitor off, so a question never writes into .git. Nothing goes over the network, and there is no model inside it: every sentence comes from the map. atlas_refresh writes only to its cache, %LOCALAPPDATA%/atlas on Windows and otherwise $XDG_CACHE_HOME/atlas or ~/.cache/atlas, and refuses a cache inside the repository. The server speaks MCP revision 2026-07-28, and 2025-11-25 and 2025-06-18 through initialize. It is a local process; the container does not run it.

What it reads

  • Doors. Every workflow under .github/workflows/: its triggers, the files its steps run (following npm run, pnpm and yarn scripts through root and workspace scripts, a build output back to the entry a bundler names, else to its tsconfig source, and a helper that hands literal command text to a shell) and the files they only check (linters, type-checkers), what it stages and pushes, here or in a clone of another repository, what it dispatches, publishes (npm, PyPI, crates.io, RubyGems, a container image, the VS Code Marketplace, Open VSX, the Hugging Face Hub, a Zenodo record), releases or deploys; a release that uploads what a build makes "builds X into MSI and NSIS installers and uploads them to the release", and softprops/action-gh-release on a release event uploads to that release and creates none; a git add is not a write, and a staged place no writer names is written by people. And every command a manifest installs (bin in package.json, [project.scripts] in pyproject.toml, [[bin]] and src/main.rs in Cargo.toml), a Tauri crate's bin as the desktop app people install, each Cargo example as a command people run with cargo run --example, and run/main_scene in project.godot as the game, as doors of their own; a bin nothing ships is "a command (or desktop app) built from , which nothing ships". A tracked file handed to any tool is a run (a checked one when the tool has no rule), astro build and vite build run the site, and a job gated to one event keeps its sends to that event. A container, wheel or binary build runs what it starts; a push to a branch for review is not a commit into the repository; a package entry is a published door only when a door publishes it, and a workspace member a workflow publishes by name, or through a for over a directory glob, is a package door of its own; a local reusable workflow or composite action is followed into its steps; turbo run, next build, and pnpm <tool> with no such script are read. A package whose every exported file starts a program as it loads is its entry and not a library; a private member's bin is a command bundled into the package that names its built path. cargo test, run and bench execute and build, check, clippy and fmt check, with Cargo's package selection, except that a binary a later step uploads or packages is built ("builds src/main.rs"); every cargo subcommand but fmt runs the crate's build script; cargo run --example executes the example; cargo tauri runs the crate after its beforeBuildCommand; godot --script, GUT and gdUnit4 execute, as do the tests a runner finds with DirAccess at run time, gdlint and gdformat check, and a Godot export is a send. A shipped action.yml is "an action other repositories use"; bins of published or worked-in manifests outside the workspace are doors; matrix and input working directories are expanded; dotnet, python -m unittest discover and npm run arguments are read; a private manifest publishes nothing. Each job's runtime is recorded: the runner labels and the platform they mean (a self-hosted or container runner is left unresolved), the environment by name, the versions actions/setup-node and actions/setup-python pin, a version file read where one is named, and the directory each command runs in. A tracked package-lock.json is read for the two door checks: the engines of the tool a step runs, and which native bindings the lock holds.
  • Parts and imports. JavaScript, TypeScript, TSX, Python, Rust and GDScript, parsed with tree-sitter; imports resolved with the same rules the runtime uses (setuptools source roots and a Python dependency known by its import name included), including workspace package exports (package.json workspaces and pnpm-workspace.yaml) without node_modules, so the map is the same on a clean clone, after an install and after a build. Every file is read as git stores it (CRLF as LF unless .gitattributes says otherwise), and a file the grammar rejects is parsed again after a byte-preserving rewrite of the constructs it rejects. Rust imports follow the module tree as rustc builds it, use through crate, self, super and path = dependencies; GDScript resolves res:// from the project root, with preload, extends, a scene's [ext_resource] lines, class_name and autoloads. Astro frontmatter, file: self-dependencies, pathToFileURL imports, sys.path inserts, namespace packages and lazy-import tables resolve.
  • Landing places and readers. The tracked paths that code writes to and reads from, found in call expressions and followed through joins and helpers; a written-out file name lands on that file, not its directory; raw GitHub URLs and quoted paths in files it does not parse, marked as found by text, never a path mentioned in Markdown prose. A path built from the directory the command is run in, the home directory, a temporary directory, a helper that returns one, an environment variable or an argument the caller passes is counted outside; a write to a place the repository does not track is counted, never placed, and the door names it ("writes to output/, which is not tracked"), even when git ignores it; Markdown links and packaging lists are not readers; imports, the site build and tests are. A configuration file naming a tracked path is its reader; a bootstrap write (only when the file is absent) is nobody's; a write under the working directory that spells a tracked place lands there, so said. A write behind a main guard is credited only to a door that runs the file; a for-of over literal values is read element by element. Rust fs writes and reads are followed through Path joins and CARGO_MANIFEST_DIR, through a struct field to the literals that set it and through a parameter to the calls that pass it; Tauri's app_data_dir() is the home directory; tauri_build::build() writes gen/schemas/; GDScript FileAccess, ResourceSaver and DirAccess on res:// land here, and user:// is the player's data directory, counted apart.
  • History. Files that change together, with a floor that falls when the history is thin, and the confidence stated on the page.

What it cannot see

Paths built at run time are counted, not named. Imports that do not resolve are counted with their reason, and so are imports of paths outside the repository, writes to untracked files, and writes to the caller's places, said by where they go: the directory the command is run in or the home directory, with the directory spelled under it, a temporary directory, or a path the caller passes (a write that spells a tracked place is then said); a claim that nothing writes or imports is qualified by the files the parser could not read; a package script's glob is expanded as the job's shell would and the test files left out of CI are listed; links over HTTP and unrun deploy files are named, and writes to the player's data directory (user://) are counted apart. The page ends with the list of what the map could not see for that repository, so a reader knows the edges of the picture. A door check that could not judge says so and makes no finding: a job with no setup step, a pin only a run can know (lts/*, latest, an expression), a self-hosted or container runner, a lockfile it cannot read. pnpm and yarn lockfiles are not read.

Errors

Every failure prints one shape: the code, one sentence, what changed, what to do, and the exit code. Exit 2 means the input was unusable and nothing was checked; exit 1 means the check ran and the tree disagrees with the committed map. A notice has the same shape without the exit line.

ATLAS_OVERLAP  A file belongs to more than one boundary.
  what changed:   shared/util.js: alpha, shared
  what to do:     narrow one boundary's globs, then atlas map
exit 1

Private repositories

templates/atlas-refresh.yml is a workflow that maps a private repository inside its own CI and commits the page there. Nothing leaves the repository.

A whole private fleet runs as a container with persistent memory: ghcr.io/dogfood-lab/atlas maps the repositories listed in its fleet.yml, keeps every render and its history on the /data volume, and serves the fleet list, each page and an index for agents (/llms.txt) on a port. The same image runs the CLI on a repository mounted at /repo. Run commands live in the repository's docker/README.md.

Part of testing-os

Atlas is one package of dogfood-lab/testing-os. The specification of the page, and the reasoning behind it, is docs/atlas-page.spec.md there. Licence: MIT.

版本与发布记录

@dogfood-lab/atlas 共发布 17 个版本,首次发布于 2026/09/23;过去 12 个月发布了 17 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.26.0latest2026/10/011 个月前
1.25.02026/10/011 个月前
1.24.02026/10/011 个月前
1.23.52026/09/301 个月前
1.23.42026/09/271 个月前
1.23.02026/09/261 个月前

关于 @dogfood-lab/atlas 的常见问题

@dogfood-lab/atlas 是什么?

Read a repository and write the page that says how it works: check the map in CI, answer agents from it over MCP, and say what will break a workflow before it runs.

如何安装 @dogfood-lab/atlas?

在项目目录运行 npm install @dogfood-lab/atlas,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 atlas、atlas-fleet,可以用 npx atlas 直接运行。

@dogfood-lab/atlas 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/dogfood-lab__atlas 是否存在。

@dogfood-lab/atlas 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@dogfood-lab/atlas 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@dogfood-lab/atlas 可以商用吗?

@dogfood-lab/atlas 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@dogfood-lab/atlas 的下载量有多少?

根据 npm 官方下载统计,@dogfood-lab/atlas 在 2026/10/13 – 2026/11/11 这 30 天内被下载 2,760 次,日均约 92 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@dogfood-lab/atlas 还在维护吗?

最新版本 1.26.0 发布于 2026/10/01(1 个月前);至今共发布 17 个版本,其中过去 12 个月发布了 17 个;首次发布于 2026/09/23。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。