codebase-snapshot

6 min read · by

Using this with an AI agent

The package ships two things that make it usable by an agent that has never heard of it: a machine-readable contract and a bundled skill.

Nothing needs to be installed globally and no prior knowledge of the tool is required.

The three commands an agent needs

# 1. Read the contract. This is the machine-readable replacement for --help.
npx codebase-snapshot describe --format json

# 2. Write a commented config that lists every setting (non-interactive).
npx codebase-snapshot init --yes

# 3. Generate and verify.
npx codebase-snapshot generate
npx codebase-snapshot validate

The bare package name works; pin an exact version (npx codebase-snapshot --version prints the current one) when the same version must run on every machine.

One command instead of three

npx codebase-snapshot --autopilot

Sets the project up — config, npm scripts, devDependency, .gitignore, install — and generates, with no prompts. It keeps an existing config, and --no-install avoids touching the lockfile. setup is the same operation as a command word.

Do not rely on the bare command

npx codebase-snapshot          # ❌ in an unconfigured project this exits 2

An agent has no terminal, so the guided first run cannot ask its question and refuses instead of generating with settings nobody chose. That exit 2 is the tool being honest, not broken: say which setup you want — --autopilot, init --yes, or generate on the documented defaults.

The contract

describe --format json returns the whole tool as data on stdout:

Field Contents
invocation The supported one-shot and installed commands, and the bin names.
workflow An ordered six-step procedure: verify → understand → configure → generate → verify output → consume.
commands Every command with what it does, its positionals and its exit codes.
options Every option with its type, default, which commands it applies to, and a summary.
exitCodes 0 success, 1 drift or refused generation, 2 usage error.
presets All 25, with priority, recommended budget and ecosystem ignores.
artifacts Each artifact with its on/off default and what it contains.
config Every config filename and every setting with its default.
output The directory layout and how to read manifest.json.
safety What is excluded or redacted, and which directories are refused.
troubleshooting Symptom → cause → fix.

It is generated from the same code the CLI runs — presets, artifact names and versions are read directly — and a test compares its documented defaults against a real generate --dry-run manifest. If a default changes, the test fails rather than the contract silently misleading an agent.

describe with no --format renders the same content for a human.

The skill

npx codebase-snapshot skill            # print it (stdout)
npx codebase-snapshot skill --install  # write it into the repository

Printing goes to stdout deliberately, so it can be redirected:

npx codebase-snapshot skill > SKILL.md

--install writes the same skill into the registries agent tools read by name:

Target Path Read by
claude .claude/skills/codebase-snapshot/SKILL.md Claude Code auto-discovery
cursor .cursor/rules/codebase-snapshot.mdc Cursor rules
npx codebase-snapshot skill --install --target claude   # one registry
npx codebase-snapshot skill --install                   # both (default)

Both are registries keyed by skill name: the path carries codebase-snapshot, so the file cannot be mistaken for your project's own documentation, and two skills cannot collide.

It never writes AGENTS.md. That file is the repository's own agent contract — build commands, conventions, house rules — and an install that creates or edits it puts a tool's marketing where the project's rules belong. If you want the skill in there, print it and paste it, so the diff and the commit are yours:

npx codebase-snapshot skill >> AGENTS.md

The install is idempotent, and whatever it creates is appended to .gitignore in the same run — these are a tool's files written into your repository, and git status should not turn that into a decision about what to commit. A file that already existed is never ignored. --format json reports what was created, updated or unchanged, and which ignore entries were added.

codebase-snapshot init does none of this: it writes the config, the npm scripts, the devDependency and the .gitignore entries for the snapshot directory, and nothing else.

When the client speaks MCP

codebase-snapshot mcp serves the repository to a Model Context Protocol client over stdio: seven tools, snapshot:// resources and two prompts. Prefer it over shelling out when the agent already has an MCP connection, for two reasons that are properties of the design rather than of the wiring:

The tools are listed in the MCP guide and in the mcp block of describe --format json. A root argument may name a sub-directory of the directory the server was started for, and nothing outside it.

Why both a contract and a skill

The contract is for doing — the data an agent needs to pick correct commands and options. The skill is for knowing when to act — it carries the trigger conditions, the ordered workflow, and the surprises an agent cannot infer from a schema: sensitive files excluded by default, secrets redacted, the output directory being tool-owned.

What an agent should avoid

Verifying an agent can drive it

tests/agent-simulation.test.js runs the published instructions as an agent would: read --help, discover describe, then execute the six workflow steps in order against an 8-file Django fixture.

It asserts what the contract promises at each step: --version prints a version, every published option states where it applies, init --yes writes a config naming every setting the contract lists, generate --format json exits 0 with validation.status: "passed" and the preset python-django, every fixture file is either in manifest.files[] or explained in manifest.skipped[], each files[] entry carries its classification and hash, and validate then exits 0. If an agent following the published words would fail, that test fails.

When you parse the manifest, remember what is conditional: manifest.files[] carries relativePath, layer, kind, language, part, inclusionMode and hashSha256 for every included file, but summary and summaryQuality only for a language the tool can analyse. A .gitignore or plain-text entry has neither key, and a file whose summary was too large for its part carries summaryOmitted: true instead of a summary. encoding appears only when a file was not plain UTF-8: utf-16le/utf-16be were transcoded, and utf-8-lossy means the body you are reading contains U+FFFD where undecodable bytes were.