Two layers, one tool:
- **The notebook** (`coldstart kb`) — durable, agent-written notes about how _this_ codebase actually works: what a file is for, how a flow spans files, which invariants hold. Captured after real tasks, recalled when a later task matches, and kept honest by the index — every note is anchored to real files, and a note whose evidence drifted is flagged, not served as truth.
- **Navigation** (`coldstart find` / `coldstart gs`) — a fast static index over file paths, symbol names, exports, and the import/call graph. It answers "which files are relevant to this task?" in milliseconds, with checkable evidence instead of a similarity score.
No embeddings, no model to run, no service to babysit. Agents are already good at reading and reasoning about code; what they waste tokens on is _finding_ the right file and _re-deriving_ what the last session already figured out. coldstart does those two parts and gets out of the way.
---
## Install
Requires Node.js 18+.
```bash
npm install -g @cstart/coldstart
cd your-project
coldstart init # coldstart.md + client wiring + notebook + background index warm-up
```
A single `coldstart init` does everything — navigation **and** the notebook. It asks two things — the **experience** (`cli`, recommended, or `mcp`) and the **client** — then writes the agent-facing guidance into the client's own rules file (as an imported `coldstart.md` for Claude Code; inlined directly for Cursor and Codex, which don't resolve `@file` references), wires the client, and sets up the notebook (skeleton, git wiring, and — for Claude Code, Codex, and Cursor — the capture/recall hooks). Pass `--experience` / `--client` to skip the prompts. The client is never auto-detected; you always pick it.
- **Claude Code** → writes `coldstart.md` and ensures `CLAUDE.md` imports it via `@coldstart.md`, and registers both the find/gs search hooks (a PostToolUse nudge + a PreToolUse find-dedup guard) and the notebook recall/capture hooks (UserPromptSubmit + Stop/SubagentStop) in `.claude/settings.json` — merged into any existing settings, never overwriting them. The `mcp` experience also writes `.mcp.json`.
- **Codex** → embeds the full coldstart guidance inline in a marked block in `AGENTS.md` (Codex has no `@file` include, so there's no separate `coldstart.md`), refreshed in place on re-run, and registers Codex-specific navigation plus notebook hooks in `.codex/hooks.json`. The capture hook understands Codex rollout and subagent transcripts. The `mcp` experience also writes `[mcp_servers.coldstart]` into `.codex/config.toml`.
- **Cursor** → writes `.cursor/rules/coldstart.mdc` — an always-applied rule that carries the full coldstart guidance inline (Cursor doesn't reliably resolve `@file` references in rules), rewritten on every init — and registers Cursor-specific navigation plus notebook hooks in `.cursor/hooks.json` (a `preToolUse` find-dedup guard, a `postToolUse` nudge, `beforeSubmitPrompt` recall, and `stop`/`subagentStop` capture — merged into any existing hooks). The capture hook parses Cursor's own conversation transcript. The `mcp` experience also writes `.cursor/mcp.json`.
- **Other** → writes `coldstart.md` only, and prints the wiring directions (plus the MCP server entry for the `mcp` experience).
On every client, the `PostToolUse` hook also delivers the **"Edited together"** signal without waiting to be asked. Once an agent has edited two different files, it names the files that git history says keep changing alongside them — the sibling implementation, the test in another language, the doc that drifts. Agents don't reliably run `gs` before editing, so the signal only reached them if they went looking; this puts it in front of them at the edit. It's advisory: the message says outright that the relation is a habit rather than a code dependency, and asks the agent to check rather than to change anything. Each file is named at most once per task, and the list resets whenever you send a new message.
`init` then warms the index in the background, so your first lookup is instant. Re-running `init` is safe — it never duplicates entries.
### Upgrading
```bash
npm install -g @cstart/coldstart@latest
coldstart init # re-run in each project to refresh coldstart.md
```
A version stamp in the keeper's lockfile makes the old background keeper shut down on the next lookup; a fresh one spawns from the new binary. No manual restart needed.
> [!NOTE]
> **Migrating from `coldstart-mcp`:** the package was renamed `coldstart-mcp` → **`@cstart/coldstart`** at 2.0.0 (the CLI is now the primary surface). `coldstart-mcp` is deprecated but still installs; switch with `npm uninstall -g coldstart-mcp && npm install -g @cstart/coldstart && coldstart init`. The `coldstart-mcp` binary name is kept as an alias, so existing MCP configs keep working.
### Removing coldstart
`init` writes per-repo wiring that a global `npm uninstall` can't reach (npm fires no reliable uninstall hook, and it has no record of which repos you `init`'d). So — like husky — coldstart ships an explicit reverse:
```bash
coldstart unwire # strip coldstart's wiring from this repo (notebook kept)
coldstart unwire --purge # also delete .coldstart/notebook/ and its git plumbing
```
`unwire` removes **only** coldstart-owned markers from the files `init` touched — hook entries, the `@coldstart.md` import, the `AGENTS.md` block, the MCP server entry, and files coldstart fully owns (`coldstart.md`, `.cursor/rules/coldstart.mdc`) — never your own content in shared files. It sweeps all four clients, is idempotent (a second run reports everything already gone), and **keeps the notebook by default** since it's committed, shared data. Run it in each project first, then `npm uninstall -g @cstart/coldstart` to remove the package.
---
## The notebook
A repo-local knowledge base written and read by agents, in `.coldstart/notebook/`:
```bash
coldstart kb search tile save lifecycle # plain task words, symbols, or file names
coldstart kb lookup src/models.py Tile # everything known at one exact address
coldstart kb write spec.json # the write gate (two-phase dedup)
coldstart kb commit # publish notes to git, nothing else rides along
coldstart kb view # open a single-file HTML browser of the notebook
coldstart kb repair # worklist of notes that are written but unfindable
coldstart kb repair-aliases # worklist of aliases that may no longer be true
coldstart kb status / lint / render / init / migrate
```
**What a note is.** Three shapes: a **file note** (what a file is for — a single summary, or per-symbol facets for hub files), a **flow note** (a cross-file story: ordered steps, invariants), and a **lesson** (a trap, rule, bug-cause, rationale, or confirmed absence). Every note carries **anchors** — concrete file paths and symbols its claims rest on.
**Where notes reach the agent.** Three surfaces, no new habits required:
1. **`Summary:` lines on `find` results** — a past agent's verified overview of a file, right where the file ranks. `[fresh]` means the file is byte-identical to when the summary was verified — the agent can rely on it without re-reading the file.
2. **Recall at prompt time** (optional hook) — notes whose titles, aliases, or anchors match the incoming prompt are surfaced as a compact title + gist + path block, hard-capped, framed as reference data. Nothing matches → nothing injected.
3. **`kb search` / `kb lookup`** — a search engine over the notebook for mid-task vocabulary changes, and an exact-address lookup (`path [symbol]`) before editing a file.
**Why it can be trusted.** This is the part that took the design work:
- **Freshness is mechanical, not hoped-for.** Every anchor is stamped with a content hash at write time; the index re-checks stamps as the code changes. A drifted note renders `[evidence changed: