codebase-snapshot 0.9.1 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -21,6 +21,225 @@ Two versions exist on the registry that are not releases, and both are deprecate
21
21
  Deleting them requires account-level rights that the release pipeline does not have, so they are
22
22
  deprecated with an explanatory message instead. `latest` has pointed at 0.9.0 since it existed.
23
23
 
24
+ ## 0.9.5
25
+
26
+ ### Every question in the wizard is reversible
27
+
28
+ The first run asked five questions and accepted one answer each. Reaching the part-size question and
29
+ changing your mind meant killing the process and starting again — and at the review screen,
30
+ answering **No** to "Write this and continue?" threw the same cancellation Ctrl+C does, so "that is
31
+ not what I meant" ended the run instead of correcting it.
32
+
33
+ - **`←` goes back** on any list or text field, `b` on any list or confirmation. Each footer names
34
+ the keys that question actually accepts: `text` takes `←` alone (`b` there is a character you are
35
+ typing) and `confirm` takes `b` alone (`←`/`→` already mean yes/no).
36
+ - **Back is a step, not a restart.** The five questions are now steps — scope → part size →
37
+ artifacts → credentials → review. Going back re-asks the previous one with your earlier answer
38
+ still selected, and back from the first step returns to *"How should I set this up?"* rather than
39
+ out of the wizard.
40
+ - **`No` at the review steps back.** It used to abort. Ctrl+C is still how you say stop.
41
+ - **Answers are rebuilt, not mutated.** Re-entering the scope step clears the globs it added, so
42
+ choosing "skip tests", going back, and choosing "everything" no longer leaves `**/*.test.*` in
43
+ the written config.
44
+
45
+ Four new tests drive real keypress events through a fake TTY, alongside the four that already
46
+ covered the forward path.
47
+
48
+ ### A clean first run
49
+
50
+ Setup printed a Node `DEP0190` deprecation warning after installing dependencies: `spawnSync` was
51
+ given an args array *and* `shell: true`, which Node deprecated because the arguments are
52
+ concatenated rather than escaped. The Windows path now hands the shell one pre-formed command
53
+ string — both halves are fixed literals from `detectPackageManager` — and every other platform
54
+ spawns with no shell at all.
55
+
56
+ ### Still untested here
57
+
58
+ The MCP server has not been run against a real client. Its protocol is exercised against the built
59
+ binary, but a client's own configuration, timeouts and approval prompts are theirs. That is the next
60
+ thing to check, not something this release proves.
61
+
62
+ ## 0.9.4
63
+
64
+ ### The snapshot is now something an agent can ask for
65
+
66
+ `codebase-snapshot mcp` serves the repository over the Model Context Protocol on stdio. Seven
67
+ tools, each answering one question an agent actually asks, and nothing that only looks useful:
68
+
69
+ | Tool | Question |
70
+ | :-- | :-- |
71
+ | `snapshot_status` | Is there a snapshot here, and what does it cover? |
72
+ | `snapshot_plan` | What *would* a generate at this budget include, and what would it drop? |
73
+ | `snapshot_generate` | Build it. The only tool that writes. |
74
+ | `snapshot_validate` | Is the context I was given still current? |
75
+ | `snapshot_locate` | Which part holds this symbol, route or file? |
76
+ | `snapshot_read` | Give me this window of this file. |
77
+ | `snapshot_explain` | Why is this path missing? |
78
+
79
+ Six are marked `readOnlyHint`, so clients can run them without a prompt; `snapshot_generate` is the
80
+ only one that asks.
81
+
82
+ ### Both protocol eras, because they are not the same protocol
83
+
84
+ Revision `2026-07-28` removed the `initialize` handshake: requests carry their protocol version and
85
+ client capabilities in `_meta`, `server/discover` is mandatory, every result carries `resultType`,
86
+ and `ping` no longer exists. Every client shipping today speaks the older handshake. The server
87
+ answers whichever arrives first and never mixes them.
88
+
89
+ The eras also disagree about an unsupported version, and getting it backwards breaks one while
90
+ looking correct in the other: **legacy negotiates down** (the server answers with a revision it does
91
+ speak), **modern rejects with `-32022`** and lists what it supports so the client can retry. Both
92
+ paths have their own tests.
93
+
94
+ ### Zero dependencies, including the protocol
95
+
96
+ `@modelcontextprotocol/sdk` is 4.5 MB unpacked with Express, Hono, Ajv, JOSE and Zod behind it. The
97
+ transport here is newline-delimited JSON-RPC in about 400 readable lines, which keeps the package's
98
+ single-dependency property intact and means the whole server can be audited in one sitting.
99
+
100
+ ### Reads come from the snapshot, never from the working tree
101
+
102
+ `snapshot_read` extracts a file's section from the emitted part. That is why an excluded `.env`
103
+ cannot be read back, a redacted credential stays redacted, and a large file returns the bounded
104
+ preview the snapshot actually contains. The test asserts the strongest available property: the
105
+ secret value appears in no artifact the server serves.
106
+
107
+ ### The contract does not lie about the server either
108
+
109
+ `describe --format json` gained an `mcp` block — tools, arguments, prompts, resources, protocol
110
+ versions — generated from the same objects the server serves. A test opens a live session, calls
111
+ `tools/list`, and compares it against the CLI's output, so a tool that exists on one side and not the
112
+ other fails the build.
113
+
114
+ ### Known limitation, measured rather than assumed
115
+
116
+ Generation is synchronous. On this repository a `generate` takes **1.1 s**; on a synthetic
117
+ 3,000-file tree it takes **7.5 s**, during which the server answers nothing else. That is under every
118
+ client's request timeout and well under a real monorepo's worth of files, so 0.9.4 runs it inline.
119
+ The number is in the docs, and a worker thread is the next change if reports come back that clients
120
+ time out.
121
+
122
+ ### Ships alongside
123
+
124
+ - The README was cut from 2,311 to 1,814 tokens (measured by `readme-lint`, which counts URLs and
125
+ code blocks too). The narrative lost about a third of its length; the command table, the preset
126
+ names and the links stayed, because they are what a reader scans for.
127
+ - A `codebase-snapshot/mcp` subpath so another tool can mount the server in-process.
128
+ - `snapshot://` resources: the manifest, each part, the three reports, the contract and the skill,
129
+ plus `snapshot://parts/{index}` as a template.
130
+ - Two prompts, `orient` and `keep-current`, both about order of operations rather than features.
131
+ - `--cwd` is the only directory the server may read; a `root` argument can name a sub-directory of
132
+ it and nothing outside. `includeSensitiveFiles` is deliberately not a tool argument.
133
+
134
+ It does not install packages, write a config file, speak HTTP, or fetch a remote repository.
135
+
136
+ ## 0.9.3
137
+
138
+ ### The project now says what it is
139
+
140
+ Everything here already worked; none of it was visible. The pitch was "turn a repository into
141
+ an LLM-ready snapshot", which is the pitch every packer uses, so the one thing that is actually
142
+ ours — you can check the result — was buried in the fourth bullet of the second section.
143
+
144
+ The line is now **a snapshot you can prove is current**, and the mark is a frame closing on a
145
+ fingerprint. Both are consequences of the same idea rather than decoration: the artefact is
146
+ bounded, it is identifiable, and it can be compared later.
147
+
148
+ - **README**: a centred hero with the mark and the line, five badges, one command, and a
149
+ diagram that draws the argument — a dump that was silently truncated beside a snapshot with a
150
+ manifest and a validator. Nav links under the fold; the CLI reference moved to the site.
151
+ - **Brand assets** in `docs/assets/`: mark in light and dark ink, a favicon that carries its own
152
+ plate so it survives both colour schemes, an iOS touch icon, and a 1200×630 social card. The
153
+ design tokens and the reason each variant exists are written down beside them.
154
+ - **Two new pages**, both about problems we can name precisely: [stale LLM context is a
155
+ bug](docs/stale-context-is-your-bug.md) and [how many tokens a codebase
156
+ is](docs/codebase-token-budget.md).
157
+
158
+ ### The site stopped being invisible when shared
159
+
160
+ Measured before the fix: twelve pages, every one declaring `twitter:card=summary_large_image`
161
+ with **no `og:image` at all** — so every share on X, LinkedIn, Reddit, Slack or Discord rendered
162
+ as a blank card — and no favicon anywhere.
163
+
164
+ - `og:image`, `og:image:alt`, dimensions, `og:site_name`, `twitter:image`, an author, a theme
165
+ colour and a favicon set on every page.
166
+ - Titles rewritten query-first instead of `<heading> — codebase-snapshot`, which spent the part
167
+ of a result a reader actually scans on a brand nobody is searching for yet.
168
+ - Descriptions written by hand at 90–165 characters; they used to be the page's first sentence
169
+ cut mid-word at 158.
170
+ - JSON-LD gains `BreadcrumbList` everywhere, `author` on every node, `sameAs` to npm and the
171
+ author's site, and an `image`.
172
+ - `llms-full.txt`: every page in one file, one fetch for a crawler that wants the corpus.
173
+ - The author's own site is now linked from every page (`rel="author"`), so the project hangs off
174
+ a person rather than a repository.
175
+
176
+ ### Two gates, because these defects survive builds
177
+
178
+ `npm run verify` now fails if either is violated:
179
+
180
+ - **`scripts/audit-site.mjs`** — title and description lengths, canonical identity, `og:image`
181
+ present *and* the file it names exists at 1200×630, twitter card, exactly one `<h1>`, alt text
182
+ on every image, parseable JSON-LD with a breadcrumb, favicon, sitemap coverage, and no page
183
+ that renders `undefined`.
184
+ - **`scripts/readme-lint.mjs`** — a hero in the first lines, at least five badges, in-page
185
+ navigation, alt text, and every relative link resolving to a real file.
186
+
187
+ ### `snapshot` is the command now, and a first run sets the project up
188
+
189
+ *(Prepared as 0.9.2, which was never published — everything in it ships here.)*
190
+
191
+ Installing globally used to give `codebase-snapshot` plus a `snap` alias — a word that
192
+ collides with Ubuntu's snapd and with an npm package of the same name. `snap` is gone and
193
+ **`snapshot`** replaces it, pointing at the same file. The long name stays the canonical one, and
194
+ the bare word is what a global install puts on `PATH`.
195
+
196
+ The bare command is no longer a synonym for `generate`. In a project with no configuration it now
197
+ recognises the project, says **what it keyed on** — `Detected nextjs` / `Because next.config.ts` —
198
+ and offers the recommended setup in one keystroke: config, `.gitignore`, npm scripts,
199
+ devDependency, install, generate. Or it walks through every setting, with each question starting
200
+ on its answer, so pressing enter through the lot is the recommended setup spelled out. When
201
+ nothing matches, it lists the manifests it looked for and asks which preset is closest.
202
+
203
+ A project that already has a config, or that this tool generated before, skips all of it and just
204
+ generates — nobody is walked through setup twice.
205
+
206
+ **A first run never guesses.** With no terminal and no `--autopilot`, it exits `2` and names the
207
+ three ways forward instead of generating with defaults nobody chose.
208
+
209
+ ```bash
210
+ snapshot # guided first run, then generate
211
+ snapshot --autopilot # same, no questions
212
+ npx codebase-snapshot # same, from a project dependency
213
+ ```
214
+
215
+ ### New: `--autopilot`
216
+
217
+ The whole setup with no prompts, from the default command: detect the preset, write the config and
218
+ `.gitignore`, add the npm scripts and devDependency, install with the project's own package
219
+ manager, then generate. It keeps an existing config, `--no-install` skips the install, and it
220
+ refuses an empty directory (there is nothing to snapshot and nothing to install into).
221
+
222
+ `--autopilot` and `setup` are one implementation with two entry points, so they cannot drift.
223
+ `--autopilot --no-config` is a usage error: one writes a config, the other promises to ignore one.
224
+
225
+ ### Detection reports its evidence
226
+
227
+ `detect()` returns the signal that fired instead of a boolean, so every preset can say why it
228
+ matched — a filename, a dependency, a manifest line — and the setup prints it. A detection you
229
+ cannot check is a detection you have to take on faith. The fallback preset is now explicit
230
+ (`fallback: true`) rather than a detector that always returns true, which is what makes "I could
231
+ not tell what this is" a state the tool can be in and report.
232
+
233
+ ### Other
234
+
235
+ - `naming the command still means exactly that`: `snapshot generate` runs on the documented
236
+ defaults and writes nothing but the snapshot, as it always has.
237
+ - The wizard's part-size question now starts on the preset's recommended budget instead of a fixed
238
+ 120 KB, so a Next.js project no longer silently gets a third of the budget it was detected for.
239
+ - `describe` and the bundled skill state the non-interactive rule, the two bin names, and that
240
+ `--autopilot` is the unattended path.
241
+
242
+ ---
24
243
  ## 0.9.1
25
244
 
26
245
  ### The documentation now derives its version from `package.json`
package/README.md CHANGED
@@ -1,99 +1,114 @@
1
- # codebase-snapshot
1
+ <div align="center">
2
+ <img src="https://raw.githubusercontent.com/ankurhalder/codebase-snapshot/main/docs/assets/favicon.svg" width="64" height="64" alt="codebase-snapshot">
2
3
 
3
- **Turn any repository into an LLM-ready snapshot: code packed into size-budgeted markdown
4
- parts, indexed by a JSON manifest, with a secret audit — in one command.**
4
+ <h1>codebase-snapshot</h1>
5
5
 
6
- [![npm version](https://img.shields.io/npm/v/codebase-snapshot.svg)](https://www.npmjs.com/package/codebase-snapshot)
7
- [![npm downloads](https://img.shields.io/npm/dw/codebase-snapshot.svg)](https://www.npmjs.com/package/codebase-snapshot)
8
- [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ankurhalder/codebase-snapshot/blob/main/LICENSE)
9
- [![node](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org)
6
+ <p><b>A snapshot you can prove is current.</b><br>
7
+ Plain-text parts under a hard byte budget, an index of every file and every skipped<br>
8
+ file with the reason, and a <code>validate</code> command that fails when the code moves.</p>
9
+
10
+ <p>
11
+ <a href="https://www.npmjs.com/package/codebase-snapshot"><img alt="npm version" src="https://img.shields.io/npm/v/codebase-snapshot.svg"></a>
12
+ <a href="https://www.npmjs.com/package/codebase-snapshot"><img alt="weekly downloads" src="https://img.shields.io/npm/dw/codebase-snapshot.svg"></a>
13
+ <a href="#license"><img alt="license: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
14
+ <a href="https://nodejs.org"><img alt="node: 18 or newer" src="https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg"></a>
15
+ <a href="https://ankurhalder.github.io/codebase-snapshot/"><img alt="documentation" src="https://img.shields.io/badge/docs-read-1a7f37"></a>
16
+ </p>
17
+ </div>
10
18
 
11
19
  ```bash
12
- npx codebase-snapshot generate
20
+ snapshot # detects the project, sets it up, generates
21
+ npx codebase-snapshot generate # or no install at all, straight to the snapshot
13
22
  ```
14
23
 
15
- That writes `./snapshot/` — a directory you can drop into a chat, a prompt, a RAG pipeline or
16
- a repository review. It works on TypeScript and JavaScript projects, and on Python, Go, Rust,
17
- Java/Kotlin, C#/.NET, PHP, Ruby, C/C++, Vue, Svelte and Astro, without configuration.
24
+ That writes `./snapshot/` — a directory you can drop into a chat, a prompt, a RAG pipeline or a
25
+ repository review. TypeScript and JavaScript first, but also Python, Go, Rust, Java/Kotlin,
26
+ C#/.NET, PHP, Ruby, C/C++, Vue, Svelte and Astro, without configuration.
27
+
28
+ ![Two ways to give a repository to a model: a dump that was silently truncated, and a snapshot
29
+ with a manifest and a validator](https://raw.githubusercontent.com/ankurhalder/codebase-snapshot/main/docs/assets/how-it-works.svg)
18
30
 
19
- ![How it works](https://raw.githubusercontent.com/ankurhalder/codebase-snapshot/main/docs/how-it-works.svg)
31
+ <p align="center">
32
+ <a href="#install">Install</a> ·
33
+ <a href="#quick-start">Quick start</a> ·
34
+ <a href="#built-to-be-trusted">Trust</a> ·
35
+ <a href="#for-ai-agents">AI agents</a> ·
36
+ <a href="#documentation">Docs</a> ·
37
+ <a href="https://ankurhalder.github.io/codebase-snapshot/">Site</a>
38
+ </p>
20
39
 
21
40
  ---
22
41
 
23
42
  ## Why
24
43
 
25
- Feeding a real repository to a model is awkward: files are too big, context windows are too
26
- small, and picking what matters by hand does not scale or repeat. `codebase-snapshot` does it
27
- deterministically:
44
+ Feeding a real repository to a model is awkward: files are too big, context windows are too small,
45
+ and choosing what matters by hand neither scales nor repeats. This does it deterministically.
28
46
 
29
- - **One file per part, never over budget.** `maxPartBytes` is a hard ceiling. A file bigger
30
- than the budget is truncated with an explicit omission marker naming the budget rather than
31
- blowing the limit — and above `largeFileBytes` it becomes a head/tail excerpt instead.
47
+ - **A hard ceiling, not a target.** `maxPartBytes` is a limit. A file bigger than the budget is cut
48
+ with an explicit omission marker naming the budget, and above `largeFileBytes` it becomes a
49
+ head/tail excerpt instead — nothing silently overflows the window you sized.
32
50
  - **An index, not just text.** `manifest.json` lists every included file with its layer, kind,
33
- language, part, hash and a structural summary — and every *excluded* file with the reason.
34
- - **Provably current.** `validate` re-hashes the repository against the snapshot and exits
35
- non-zero on any drift, so a pipeline can gate on context being fresh.
36
- - **Deterministic where it matters.** Two runs over unchanged input give byte-identical
37
- `parts/`, `reports/navigation.md` and `reports/project-tree.md`, and the same
38
- `manifest.fingerprint`. Only `manifest.json`, the snapshot's `README.md`,
39
- `reports/audit.md` and `.codebase-snapshot` change between runs, because they carry
40
- timestamps, a run id and a pid.
41
- - **Safe by default.** Credential files are skipped unless asked for, secret-shaped strings are
42
- redacted, and a mistyped output directory cannot delete source code.
43
- - **Usable by agents, not just humans.** A machine-readable contract and an installable skill
44
- let an agent with no prior knowledge drive the whole thing.
51
+ language, part, hash and a structural summary, and every *excluded* file with the reason.
52
+ - **Provably current.** `validate` re-hashes the repository against the snapshot and exits non-zero
53
+ on any drift, so a pipeline can gate on the context being fresh.
54
+ - **Repeatable.** Two runs over unchanged input give byte-identical parts and the same
55
+ `manifest.fingerprint`; only the artifacts that carry a timestamp, run id or pid differ.
45
56
 
46
57
  ## Install
47
58
 
48
59
  ```bash
49
- npx codebase-snapshot generate # no install, one-off
50
- npm install -D codebase-snapshot # or add it to a project
60
+ npm install -g codebase-snapshot # puts `snapshot` on your PATH
61
+ npx codebase-snapshot generate # or no install at all, one-off
62
+ npm install -D codebase-snapshot # or add it to a project
51
63
  ```
52
64
 
53
- This is a **<!--@major-->0<!--/@major-->.x** release. Version numbers follow semver's 0.x conventions, so the CLI surface may change in a minor release until 1.0.0 — pin an exact version if you need a fixed surface today.`n`nAny npm-compatible client works — npm, yarn (classic and Berry with strict PnP), pnpm and bun —
54
- each verified against the packed tarball before release. Requires **Node.js 18+**.
65
+ `codebase-snapshot` is the canonical name to script against; `snapshot` is the short command a
66
+ global install provides, and from a project dependency the same binary is `npx snapshot` or the
67
+ `npm run snapshot` script `init` writes.
55
68
 
56
- Published from GitHub Actions with [build provenance](https://docs.npmjs.com/generating-provenance-statements): npm shows the tarball was built from this repository at a tagged commit, and `npm audit signatures` verifies it.
69
+ Requires **Node.js 18+**. Any npm client works — npm, yarn (classic and Berry with strict PnP), pnpm
70
+ and bun. Published from GitHub Actions with [build
71
+ provenance](https://docs.npmjs.com/generating-provenance-statements), so `npm audit signatures`
72
+ verifies the tarball came from this repository at a tagged commit.
73
+
74
+ This is a **<!--@major-->0<!--/@major-->.x** release: the CLI surface may still change in a minor
75
+ release until 1.0.0, so pin an exact version if you need a fixed surface today.
57
76
 
58
77
  → [Installation guide](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/install.md)
59
78
 
60
79
  ## Quick start
61
80
 
62
- One command does the whole first run — detects the project, writes a commented config, adds the
63
- npm scripts and the devDependency, installs it, and generates the snapshot:
81
+ Type it. That is the whole first run.
64
82
 
65
83
  ```bash
66
- npx codebase-snapshot setup
84
+ snapshot
67
85
  ```
68
86
 
87
+ It recognises the project and says what it keyed on — `Detected nextjs` / `Because next.config.ts`
88
+ — then offers the recommended setup in one keystroke, or a walk through every setting with each
89
+ question starting on its default. Either way it writes the config, adds the npm scripts and the
90
+ devDependency, installs with your package manager, and generates. A project that already has a
91
+ config just generates.
92
+
93
+ Nothing to press — CI, a container, an agent:
94
+
69
95
  ```bash
70
- # Or step by step, if you want to see each stage:
71
- npx codebase-snapshot init --yes # config + scripts + devDependency + .gitignore
72
- npm install # the package, into node_modules
73
- npm run snapshot # generate
74
- npm run snapshot:validate # exit 0 = current with disk
96
+ npx codebase-snapshot --autopilot
75
97
  ```
76
98
 
77
- `setup` keeps a config the repository already has, and `setup --no-install` skips the install
78
- (CI, offline, or a lockfile you would rather not touch).
99
+ **A first run never guesses.** With no terminal and no `--autopilot` it exits `2` and names the
100
+ three ways forward, because a snapshot built from settings nobody chose is a snapshot nobody can
101
+ check.
79
102
 
80
- ```
81
- 📸 Generating snapshot for: /Users/you/project
82
- Branch: main | Part budget: 300 KB
83
-
84
- ✅ Snapshot generated in 0.14s:
85
- - Tracked files: 128
86
- - Total lines: 9,431
87
- - Total size: 0.41 MB
88
- - Parts written: 3 under snapshot/parts/
89
- - Reports: snapshot/reports/ (project-tree, navigation, audit)
90
- - Manifest: snapshot/manifest.json
91
- - Fingerprint: e4607b570268c8def0911babbace97e4a0196d9eaf2cac22c8847500883d70aa
92
- - Integrity: passed
103
+ ```bash
104
+ npx codebase-snapshot init --yes # config + scripts + devDependency + .gitignore
105
+ npm install # the package, into node_modules
106
+ npm run snapshot # generate
107
+ npm run snapshot:validate # exit 0 = current with disk
93
108
  ```
94
109
 
95
- The fingerprint is printed in full — all 64 hex characters, never elided — and it is the same
96
- value as `manifest.fingerprint`.
110
+ The fingerprint is printed in full — all 64 hex characters, never elided — and it is the same value
111
+ as `manifest.fingerprint`.
97
112
 
98
113
  ## What you get
99
114
 
@@ -114,34 +129,29 @@ Every artifact can be turned off (`--skip-artifacts`, `--only-artifacts`, or the
114
129
 
115
130
  ## Built to be trusted with a whole repository
116
131
 
117
- A snapshot is only useful if you can believe it, so the tool is explicit about everything it does
118
- *not* contain:
132
+ A snapshot is only useful if you can believe it, so the tool is explicit about what it does *not*
133
+ contain.
119
134
 
120
135
  - **Nothing is dropped silently.** Every excluded path is recorded in `manifest.skipped[]` with a
121
- reason — `binary`, `gitignore`, `default-ignore`, `sensitive-file`, `sensitive-path`, `symlink`,
122
- `outside-root`, `read-error`, `not-file`, `nested-repository`, `excluded` — and `explain <path>`
123
- answers the same question for any single path.
124
- - **Encoding is stated, not guessed.** UTF-16 files are transcoded instead of vanishing as
125
- "binary"; a file that is not valid UTF-8 is kept but labelled `utf-8-lossy` with the count of
126
- undecodable bytes, so you never mistake mojibake for source.
136
+ reason — `binary`, `gitignore`, `sensitive-file`, `symlink`, `read-error`, `excluded` and the
137
+ rest — and `explain <path>` answers the same question for any single file.
127
138
  - **Counts describe what was emitted.** `includedBytes` and `includedLines` are measured from the
128
- block in the part, not from the file on disk.
139
+ block in the part, not from the file on disk. A file that is not valid UTF-8 is kept and labelled
140
+ `utf-8-lossy` rather than vanishing as "binary".
129
141
  - **Drift is checked, not assumed.** `validate` compares every file's hash *and* a digest of the
130
- settings the snapshot was generated with, so a changed budget, layer rule or secret pattern is
131
- drift rather than silence.
132
- - **Memory is bounded.** Files above 2 MB are not parsed for a structural summary (that is where a 50 MB file
133
- used to reach 3 GB of resident memory), and 130 000 files in one directory or a 3 000-level path
134
- scan without crashing.
135
- - **`diff` compares payloads, not just paths.** Two snapshots of identical sources with different
136
- settings say so instead of reporting "0 changed".
137
- - **When git cannot list files** — an interrupted clone, a dehydrated `.git`, `safe.directory` —
138
- the run refuses rather than quietly scanning something different, and `--discovery walk` is the
139
- documented escape hatch.
142
+ settings the snapshot was generated with, so a changed budget or secret pattern is drift rather
143
+ than silence.
144
+ - **The output directory is the tool's.** Each run is written to a scratch directory and swapped in
145
+ atomically, and it refuses to replace a directory it did not create — `--out-dir src` cannot
146
+ destroy source code.
147
+ - **Credential files are excluded by default** — `.env`, `*.pem`, `.npmrc`, `id_rsa`, `*.tfstate`
148
+ and more — and secret-shaped strings inside ordinary files are redacted by masking only the
149
+ matched span, never the whole line.
140
150
 
141
151
  ## Supported projects
142
152
 
143
- 25 presets, detected automatically from the repository — each contributing layers, kinds,
144
- ecosystem ignore patterns and a recommended part budget.
153
+ 25 presets, detected from the repository — each contributing layers, kinds, ecosystem ignore
154
+ patterns and a recommended part budget.
145
155
 
146
156
  | | | | |
147
157
  | :--- | :--- | :--- | :--- |
@@ -153,11 +163,9 @@ ecosystem ignore patterns and a recommended part budget.
153
163
  | Laravel (PHP) | Rails (Ruby) | Terraform / Docker infra | Docs-only |
154
164
  | generic fallback | | | |
155
165
 
156
- Non-TypeScript languages get import/export/class/function summaries rather than being treated
157
- as opaque text. Vue, Svelte and Astro script blocks go through the real TypeScript compiler.
158
- Every summary is labelled `ast`, `structural` or `heuristic` so you know how much to trust it —
159
- Python, for example, is a line-scan `heuristic`, while JSON and Markdown get `structural`
160
- shapes.
166
+ Non-TypeScript languages get import/export/class/function summaries rather than being treated as
167
+ opaque text, and every summary is labelled `ast`, `structural` or `heuristic` so you know how much
168
+ to trust it.
161
169
 
162
170
  → [Preset table and detection rules](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/configuration.md#project-presets)
163
171
 
@@ -165,7 +173,9 @@ shapes.
165
173
 
166
174
  | Command | Does |
167
175
  | :--- | :--- |
168
- | `generate` *(default)* | Write the snapshot. |
176
+ | *(none)* | The guided first run. Asks once when the project has no config; generates otherwise. |
177
+ | `generate` *(default)* | Write the snapshot. `--autopilot` sets the project up first, unasked. |
178
+ | `setup` | Config, npm scripts, devDependency, install and generate, in one command. |
169
179
  | `validate` / `check` | Compare the snapshot with the repository; exit `1` on drift. |
170
180
  | `report` | Snapshot health, layer metrics, secret audit. |
171
181
  | `init` | Interactive (or `--yes`) setup that writes a self-documenting config. |
@@ -173,35 +183,39 @@ shapes.
173
183
  | `diff <a> <b>` | Compare two snapshots. |
174
184
  | `describe` | The machine-readable contract (`--format json`). |
175
185
  | `skill` | Print or install the agent skill. |
186
+ | `mcp` | Serve the repository to an MCP client over stdio. |
176
187
 
177
- Exit codes: `0` success · `1` drift or refused generation · `2` usage error.
188
+ Exit codes: `0` success · `1` drift, refused generation, or nothing to snapshot · `2` usage error,
189
+ or a first run with no terminal and no `--autopilot`.
178
190
 
179
191
  → [Full CLI reference](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/cli.md)
180
192
 
181
193
  ## For AI agents
182
194
 
183
- Everything an agent needs is available as data, and the tool can install its own skill:
195
+ Everything an agent needs is available as data, and the tool can install its own skill.
184
196
 
185
197
  ```bash
186
- # The contract: workflow, every option and default, exit codes, presets, safety rules
187
- npx codebase-snapshot describe --format json
188
-
189
- # Install the skill into the registries agent tools read: .claude/skills/, .cursor/rules/
190
- # (it adds those files to .gitignore, and never touches your own AGENTS.md)
191
- npx codebase-snapshot skill --install
198
+ npx codebase-snapshot describe --format json # contract: workflow, options, exit codes
199
+ npx codebase-snapshot skill --install # into .claude/skills + .cursor/rules
200
+ npx -y codebase-snapshot@0.9.5 mcp # or serve it over MCP
192
201
  ```
193
202
 
194
- An agent told only "use `npx codebase-snapshot`" can read the contract, follow its
195
- ordered workflow, and produce a validated snapshot unaided — that path is covered by a test.
203
+ An agent told only "use `npx codebase-snapshot`" can read the contract, follow its ordered
204
+ workflow, and produce a validated snapshot unaided — that path is covered by a test.
196
205
 
197
- → [Using this with an AI agent](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/agent.md) · [AGENTS.md](https://github.com/ankurhalder/codebase-snapshot/blob/main/AGENTS.md) · [llms.txt](https://github.com/ankurhalder/codebase-snapshot/blob/main/llms.txt)
206
+ The MCP server exposes seven tools — status, plan, generate, validate, locate, read, explain — plus
207
+ `snapshot://` resources and two prompts. Its reads come from the snapshot rather than the working
208
+ tree, so an excluded file stays excluded and a redacted value stays redacted, and
209
+ `snapshot_validate` answers the question an agent otherwise cannot ask: is the context I was given
210
+ still true?
211
+
212
+ → [Using this with an AI agent](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/agent.md) · [MCP server](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/mcp.md) · [AGENTS.md](https://github.com/ankurhalder/codebase-snapshot/blob/main/AGENTS.md) · [llms.txt](https://github.com/ankurhalder/codebase-snapshot/blob/main/llms.txt)
198
213
 
199
214
  ## Configuration
200
215
 
201
- `snapshot.config.ts` (or `.mjs`) is written by `init` with **every** setting at its current
202
- value, commented and grouped, so it doubles as the reference. Deleting any line is safe: the
203
- defaults are real. The object is exported through a name — `export default { … }` is
204
- `import/no-anonymous-default-export`, on by default in `eslint-config-next`.
216
+ `snapshot.config.ts` (or `.mjs`) is written by `init` with **every** setting at its current value,
217
+ commented and grouped, so it doubles as the reference. Deleting any line is safe: the defaults are
218
+ real.
205
219
 
206
220
  ```js
207
221
  const config = {
@@ -230,8 +244,9 @@ const manifest = generateSnapshot(config);
230
244
  const validation = validateSnapshot(config);
231
245
  ```
232
246
 
233
- CommonJS works too (`require("codebase-snapshot")`), with type definitions for
234
- both. The CLI and the API share one implementation, so anything the CLI does is available here.
247
+ CommonJS works too (`require("codebase-snapshot")`), with type definitions for both. The CLI, the
248
+ API and the MCP server share one implementation, so anything one of them does is available in the
249
+ others.
235
250
 
236
251
  ## Documentation
237
252
 
@@ -242,36 +257,35 @@ both. The CLI and the API share one implementation, so anything the CLI does is
242
257
  | [Configuration](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/configuration.md) | Every setting, all 25 presets, budgets, hooks, secrets |
243
258
  | [Snapshot output](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/output.md) | Directory layout and the full manifest schema |
244
259
  | [AI agents](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/agent.md) | The contract, the skill, what an agent should avoid |
260
+ | [MCP server](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/mcp.md) | Seven tools, resources, both protocol eras |
245
261
  | [Troubleshooting](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/troubleshooting.md) | Every message and what to do about it |
246
262
  | [Changelog](https://github.com/ankurhalder/codebase-snapshot/blob/main/CHANGELOG.md) | Release history and breaking changes |
247
263
 
248
- ## Guides
249
-
250
- | | |
251
- | :--- | :--- |
252
- | [Feeding a codebase to ChatGPT, Claude or Cursor](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/how-to-feed-a-repo-to-claude.md) | The full recipe, including the parts most guides skip |
253
- | [Budgeting LLM context](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/how-to-context-budget.md) | Choosing the numbers from the destination, not from taste |
254
- | [vs repomix](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/vs-repomix.md) | Including where repomix is the better choice |
255
- | [vs gitingest](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/vs-gitingest.md) | Including where gitingest is the better choice |
256
- | [vs code2prompt](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/vs-code2prompt.md) | Including where code2prompt is the better choice |
257
-
258
- ## Safety
259
-
260
- - **Credential files are excluded by default** — `.env`, `*.pem`, `*.key`, `.npmrc`, `.netrc`,
261
- `.git-credentials`, `id_rsa`, `.kube/config`, `*.tfstate` — and listed in
262
- `manifest.skipped[]` with the reason.
263
- - **Secrets are redacted** inside ordinary files: only the matched span is masked, never the
264
- whole line, and no excerpt reaches any artifact.
265
- - **The output directory is owned by the tool.** Each run is written to a scratch directory and
266
- swapped in atomically; the previous snapshot survives a failure.
267
- - **It refuses to replace a directory it did not create**, so `--out-dir src` cannot destroy
268
- source code.
264
+ Guides: [feeding a codebase to ChatGPT, Claude or
265
+ Cursor](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/how-to-feed-a-repo-to-claude.md)
266
+ · [stale LLM context is a
267
+ bug](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/stale-context-is-your-bug.md) ·
268
+ [how many tokens a codebase
269
+ is](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/codebase-token-budget.md) ·
270
+ [budgeting a context
271
+ window](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/how-to-context-budget.md) ·
272
+ [vs repomix](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/vs-repomix.md) · [vs
273
+ gitingest](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/vs-gitingest.md) · [vs
274
+ code2prompt](https://github.com/ankurhalder/codebase-snapshot/blob/main/docs/vs-code2prompt.md)
269
275
 
270
276
  ## Contributing
271
277
 
272
- Issues and pull requests are welcome — see [CONTRIBUTING.md](https://github.com/ankurhalder/codebase-snapshot/blob/main/CONTRIBUTING.md) and the
273
- [code of conduct](https://github.com/ankurhalder/codebase-snapshot/blob/main/CODE_OF_CONDUCT.md). Security reports: [SECURITY.md](https://github.com/ankurhalder/codebase-snapshot/blob/main/SECURITY.md).
278
+ Issues and pull requests are welcome — see
279
+ [CONTRIBUTING.md](https://github.com/ankurhalder/codebase-snapshot/blob/main/CONTRIBUTING.md) and the
280
+ [code of conduct](https://github.com/ankurhalder/codebase-snapshot/blob/main/CODE_OF_CONDUCT.md).
281
+ Security reports: [SECURITY.md](https://github.com/ankurhalder/codebase-snapshot/blob/main/SECURITY.md).
274
282
 
275
283
  ## License
276
284
 
277
285
  [MIT](https://github.com/ankurhalder/codebase-snapshot/blob/main/LICENSE) © Ankur Halder
286
+
287
+ <p align="center">
288
+ <sub>Built by <a href="https://ankurhalder.com" rel="author">Ankur Halder</a> ·
289
+ <a href="https://ankurhalder.github.io/codebase-snapshot/">documentation</a> ·
290
+ <a href="https://www.npmjs.com/package/codebase-snapshot">npm</a></sub>
291
+ </p>