AkashGoenka/coldstart
GitHub: AkashGoenka/coldstart
coldstart 是一个为 AI 编程 Agent 维护代码库知识的工具,通过确定性 AST 索引和自动管理新鲜度的 Agent 笔记,解决 Agent 每次会话重复摸索代码库的问题。
Stars: 2 | Forks: 0
一个工具,两层结构:
- **笔记本** (`coldstart kb`) —— 持久化、由 Agent 编写的笔记,记录_这个_代码库实际是如何运作的:某个文件的作用、跨文件的流程、哪些是不变式。这些笔记在真实任务执行后被捕获,在后续匹配的任务中被召回,并通过索引保持其可靠性——每一条笔记都锚定在实际的文件上,如果某个笔记的证据发生偏移,它会被标记出来,而不会被当作事实返回。
- **导航** (`coldstart find` / `coldstart gs`) —— 一个基于文件路径、符号名称、导出和 import/call graph 的快速静态索引。它能在几毫秒内回答“哪些文件与此任务相关?”,并提供可检查的证据,而不是相似度评分。
没有 embeddings,没有需要运行的模型,也没有需要看护的服务。Agent 已经非常擅长阅读和理解代码;它们浪费 token 的地方在于_寻找_正确的文件和_重新推导_上一次会话已经弄清楚的内容。coldstart 就是专门做这两件事,并且不干预其余部分。
## 安装
要求 Node.js 18+。
```
npm install -g @cstart/coldstart --legacy-peer-deps
cd your-project
coldstart init # coldstart.md + client wiring + notebook + background index warm-up
```
一个简单的 `coldstart init` 就能完成所有工作——导航**和**笔记本。它会询问两件事——**体验**(`cli`(推荐)或 `mcp`)以及**客户端**——然后将面向 Agent 的指导写入客户端自身的规则文件中(对于 Claude Code,会作为一个导入的 `coldstart.md`;对于无法解析 `@file` 引用的 Cursor 和 Codex,则直接内联),接着连接客户端并设置笔记本(骨架、git 连线,以及——对于 Claude Code、Codex 和 Cursor——捕获/召回钩子)。传入 `--experience` / `--client` 可跳过提示。客户端永远不会被自动检测;你始终需要手动选择。
- **Claude Code** → 编写 `coldstart.md` 并确保 `CLAUDE.md` 通过 `@coldstart.md` 导入它,并在 `.claude/settings.json` 中注册 find/gs 搜索钩子(一个 PostToolUse 提示 + 一个 PreToolUse find 去重防护)以及笔记本召回/捕获钩子,并合并到任何现有设置中,绝不覆盖它们。`mcp` 体验也会写入 `.mcp.json`。
- **Codex** → 将完整的 coldstart 指导以内联方式嵌入到 `AGENTS.md` 中带有标记的区块里(Codex 没有 `@file` 包含功能,因此没有单独的 `coldstart.md`),并在重新运行时原地刷新,同时在 `.codex/hooks.json` 中注册 Codex 专用的导航和笔记本钩子。捕获钩子能够理解 Codex 的 rollout 和 subagent 对话记录。`mcp` 体验也会将 `[mcp_servers.coldstart]` 写入 `.codex/config.toml`。
- **Cursor** → 写入 `.cursor/rules/coldstart.mdc` —— 一个始终生效的规则,以内联方式携带完整的 coldstart 指导(Cursor 无法可靠地解析规则中的 `@file` 引用),在每次初始化时重写——并在 `.cursor/hooks.json` 中注册 Cursor 专用的导航和笔记本钩子(一个 `preToolUse` find 去重防护、一个 `postToolUse` 提示、`beforeSubmitPrompt` 召回以及 `stop`/`subagentStop` 捕获——并合并到任何现有的钩子中)。捕获钩子会解析 Cursor 自身的对话记录。`mcp` 体验也会写入 `.cursor/mcp.json`。
- **其他** → 仅写入 `coldstart.md`,并打印连线说明(以及 `mcp` 体验对应的 MCP server 条目)。
然后 `init` 会在后台预热索引,这样你的第一次查找就是即时的。重新运行 `init` 是安全的——它绝不会产生重复条目。
### 升级
```
npm install -g @cstart/coldstart@latest --legacy-peer-deps
coldstart init # re-run in each project to refresh coldstart.md
```
keeper 锁文件中的版本戳会让旧的后台 keeper 在下次查找时关闭;新的 keeper 会从新的二进制文件中启动。无需手动重启。
## 笔记本
一个位于 `.coldstart/notebook/` 中、由 Agent 编写和读取的代码库本地知识库:
```
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 status / lint / render / init / migrate
```
**笔记是什么。** 有三种形式:**文件笔记**(一个文件的作用——单个摘要,或针对核心文件按符号划分的方面)、**流程笔记**(跨文件的故事:有序步骤、不变式)以及**经验教训**(陷阱、规则、bug 原因、基本原理或确认的缺失)。每条笔记都带有**锚点** ——其声明所依赖的具体文件路径和符号。
**笔记如何传递给 Agent。** 三个途径,不需要养成新习惯:
1. **`find` 结果上的 `Summary:` 行** —— 过去某个 Agent 对文件的经过验证的概述,就在该文件排名的位置。`[fresh]` 表示该文件与验证摘要时逐字节相同——Agent 可以依赖它而无需重新阅读文件。
2. **提示词时的召回**(可选钩子) —— 标题、别名或锚点与传入提示词匹配的笔记将以紧凑的“标题 + 主旨 + 路径”区块呈现,设有硬性上限,并作为参考数据框架。如果没有匹配项 → 不会注入任何内容。
3. **`kb search` / `kb lookup`** —— 针对笔记本的搜索引擎,用于任务中途的词汇表更改;以及在编辑文件前进行的精确地址查找(`path [symbol]`)。
**为什么可以信任它。** 这是设计中耗费心血的部分:
- **新鲜度是机械化的,而不是一种奢望。** 每个锚点在写入时都会盖上内容 hash 戳;随着代码的更改,索引会重新检查这些 hash 戳。发生偏移的笔记会呈现 `[evidence changed:
]`,并且指导说明要求重新验证——陈旧的知识会退化为一个带有标签的假设,而不是一个自信的谎言。
- **日志即真相。** 笔记保存在只追加的 `.raw` 事件日志中(提交它——合并即是求并集,因此平行的笔记分支可以无冲突地协调)。Markdown 笔记是派生的,由机械方式重新生成,并被 gitignore。
- **写入需要经过门控。** 新笔记的概念首先会针对现有笔记进行搜索——Agent 必须显式合并到匹配项中(`--into `)或声明其为新笔记(`--new`)。重复项在写入时即被拦截,而不是事后清理。
- **并发会话是安全的。** 多个 Agent 可以同时写入:每个笔记的只追加日志、新笔记 ID 的排他性创建(同一时刻的重复项会变成两个可见的笔记,绝不会是静默合并)、共享文件笔记的无损合并,以及原子渲染(读取者绝不会看到写了一半的笔记)。
- **更正在会话内进行。** 如果 Agent 在上下文中存在证据时发现笔记有误,指导会告诉它立即修复或撤回该笔记——不存在比这位置更好的未来 Agent。
**设置:** 笔记本随 `coldstart init` 一起提供——无需单独的步骤。它创建了笔记本骨架,为日志设置了求并集合并,并且(在 Claude Code 和 Codex 上)连接了两个钩子——会话结束时捕获,提示词时召回。(如果你只想(重新)连接笔记本,`coldstart kb init` 仍然可以作为别名使用。)其他宿主可以在没有钩子的情况下驱动笔记本:通过完整的 `kb` CLI,或者——对于无 shell 的客户端——通过 `kb_search` / `kb_lookup` / `kb_write` / `kb_status` MCP 工具。
**语言无关。** 笔记本的新鲜度机制基于内容 hash,因此它适用于任何代码库——包括导航索引无法解析的语言。在索引能够解析的地方,笔记还可以获得符号级别的新鲜度。
## 导航:两个操作
| | 它回答了什么 | 替代了 |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| **`find `** | “哪些文件与此相关?” —— 根据文件覆盖了多少查询词(文件名、路径片段、导出符号,外加全仓范围的名称引用扫描)来对文件进行排名。 | 在熟悉环境时大量的 `grep`/`glob` |
| **`gs `** | “这个文件是什么?” —— 带有行号范围的顶层符号,谁 import 了它,谁调用了每个符号,以及名称相关的邻近文件。 | 为了了解其结构和使用方式而阅读整个文件 |
预期的流程:**`find`** 一个概念 → 选择最佳路径 → 对该文件执行 **`gs`** 查看其结构和谁在使用它 → 仅为方法体内部的实现使用 `Read`。笔记本摘要会附带在 `find` 结果上,因此通常熟悉环境这一步自己就能得出答案。
```
flowchart LR
A["coldstart find
which files?"] --> B["coldstart gs
what is it? who uses it?"] --> C["Read
just the method body"]
class A,B cold
class C warm
classDef cold stroke:#16708f,stroke-width:2px
classDef warm stroke:#c26714,stroke-width:2px
```
### `find` —— 定位与概念相关的文件
```
coldstart find auth session cookie
```
在速度方面,`find` 可与原生 grep 媲美:其全仓引用扫描运行在 **ripgrep** 上——使用你 PATH 中的、捆绑的副本,或编辑器自带的(可通过 `COLDSTART_RG` 覆盖)——带有 `git grep`/`grep` 回退机制,并且排名页面来自预构建的索引,而不是扫描。
**标志:** `--path GLOB`(限定范围;逗号组合,`!` 排除) · `--tests`(包含测试文件) · `--via`(显示名称引用关系) · `--json`
### `gs` —— 深入探究单个文件
```
coldstart gs src/auth/service.ts
```
在一次调用中返回文件的符号(带有行号范围)、其一跳的内部 imports、谁 import 了它,以及每个符号的跨文件调用者。这是 **“谁使用这个文件 / 谁调用这个符号”** 的答案;它不是 grep。
**标志:** `--symbol a,b`(内联交付命名的方法体) · `--match TERM`(将一个巨型文件过滤到一个区域;`a|b` = OR,`/regex/` = 正则表达式) · `--view symbols|imports|importers|callers` · `--json`
### 在一次 Shell 调用中批量处理独立查询
```
coldstart find auth; coldstart find 'session cookie'; coldstart gs src/auth/service.ts
```
## 两种调用方式,输出完全相同
coldstart 以一个带有两个前门的二进制文件形式发布:
- **CLI(主要方式)** —— `coldstart find …` / `coldstart gs …` / `coldstart kb …`。适用于任何具备 Shell 能力的 Agent(Claude Code、Cursor、终端使用)。这是快速路径。
- **MCP(适用于无 shell 客户端)** —— `find` 和 `gs` 工具,加上作为 `kb_search` / `kb_lookup` / `kb_write` / `kb_status` 的笔记本,所有这些都与 CLI 输出逐字节相同。适用于像 Claude Desktop 这样没有 shell 的客户端。(`kb commit` 仍然仅限于 CLI/人类使用——将笔记发布到 git 绝不是 Agent 的操作。)
相同的引擎,相同的索引,相同的结果。选择你的 Agent 能够访问的那种方式。
它与 **Claude Code**、**Codex** 和 **Cursor** 配合使用效果最好:这三者都会从 `coldstart init` 获得特定于平台的 find/gs 钩子和笔记本召回/捕获钩子。任何其他客户端都会获得 `coldstart.md` 以及打印出的连线说明。
## 引入你自己的语义
coldstart 没有 embeddings,没有生成的摘要,也没有在索引时计算的语义层——这是**故意的。语义层就是 Agent。** 每个使用者已经是前沿模型;在索引时预先计算意义只会重复这一点,而且更糟、更陈旧。因此,索引保留了那些_容易保持精确_的东西——路径、符号、导出、import/call graph——并返回每个文件排名靠前的_原因_。
笔记本是将相同的哲学应用于记忆:coldstart 仍然不计算自己的意义。它存储、锚定并新鲜度检查 **Agent** 所创作的意义——在任务执行时,由掌握完整上下文的推理者编写,并针对真正重要的问题。完整的论述在 **[PHILOSOPHY.md](./PHILOSOPHY.md)** 中。
## 索如何保持新鲜
coldstart 采用的是 **一个 keeper,多个轻量级读取器** 的架构:
```
flowchart TD
K["keeper — coldstart --daemon
watches repo, patches/rebuilds, saves cache
serves nothing"] -->|debounced save| C[("on-disk cache")]
C --> F["coldstart find
reads cache, prints"]
C --> G["coldstart gs
reads cache, prints"]
C --> M["MCP server
reads cache, stdio"]
class K cold
classDef cold stroke:#16708f,stroke-width:2px
```
- 每个代码库中只有一个 **keeper** 进程,它负责监视文件系统并保持磁盘缓存最新。它**不**负责回答查询。
- CLI 读取器(`find`/`gs`)和 MCP server 是基于该缓存的**无状态读取器**。代码库的第一个读取器惰性地启动 keeper,因此即使未提交的编辑也能保持最新。
- **读取器从不构建索引。** 在缓存未命中时,它们会等待 keeper 的构建(进度输出至 stderr),而不是静默地触发长达数分钟的行内构建——或者同时触发三个构建。
- 没有 HTTP,没有端口,没有 bridge。keeper 会将日志记录到 `~/.coldstart/daemon/.log`,并在其锁文件被移除时退出。
**没有缓存 TTL。** 索引永远不会因为陈旧而被丢弃——它会被保持_正确_:
- **当 keeper 运行时:** 编辑会被防抖(400 毫秒),然后被**增量打补丁**(约 2–5 毫秒/文件,最多 30 个文件或仓库的 20%,取决于哪个更大),或者在此之上触发**后台完整重建**(在切换前从最后一个良好的索引提供服务)。缓存在编辑稳定后约 5 秒重新保存,使用**原子化世代**——读取者绝不会加载新旧内容写了一半的混合体。
- **当 keeper 启动时:** 它会进行**协调**——将每个被索引的文件与其存储的指纹进行 stat 检查(即使在 1.6 万个文件的情况下也只需约 150 毫秒),加上针对被索引的 HEAD 进行 git diff——并精确地修补在没有监视时所发生的更改。过去在 1.6 万个文件的代码库上,切换分支会强制进行 96 秒的重建,现在只需约 3 秒的修补。
- **作为兜底:** 每个补丁都会针对索引不变量进行 lint 检查(违规会触发自动重建,并记录在 `status` 会显示的修复日志中),并且在每次保存后进行轮换的指纹审核会捕获监视器遗漏的事件。
keeper 还会为笔记本的锚点新鲜度盖上时间戳(一个小的附属文件,通过 single-flight 派生)——笔记本永远不会为了回答查询而加载代码索引。
### 生命周期命令
```
coldstart status # keepers on this machine: alive? fresh? last patch/rebuild/save? repairs?
coldstart restart # kill the current repo's keeper (respawns on next lookup)
coldstart restart --root DIR # kill a specific repo's keeper from anywhere
coldstart restart --all # kill every keeper
coldstart index # build + save the cache once, up front (single-writer prep)
```
每当感觉有东西陈旧时,`restart` 都是正确的做法——一个全新的 keeper 在启动时会进行协调,所以它恢复过来时是_正确_的,而不仅仅是_活着_。`status` 回答“我的索引是最新的吗,为什么?”:存活状态、缓存期限、keeper 最后一次协调/修补/重建/保存的时间戳,以及修复日志的尾部——无需网络探测。
## 支持的语言
导航索引:TypeScript、JavaScript、JSX/TSX、Vue、Svelte、Astro、AngularJS 1.x、Java、Kotlin、Ruby(Rails 感知:`has_many`/`belongs_to` 关联、`routes.rb` 资源、controller↔view 边缘)、Python(Django 约定边缘)、Go、Rust、C#、PHP(Laravel 约定边缘)、C++、Groovy(包括 Gradle DSL)、GraphQL、YAML、TOML、XML 和 `.env` 文件。
**未索引:** Swift、Dart —— 没有扩展映射;这些文件不会被遍历或解析。
**笔记本在任何情况下都能工作** —— 它的新鲜度戳基于内容 hash,因此 Swift 代码库上的笔记与 TypeScript 上的笔记一样可靠(它们只是缺乏符号级别的新鲜度细节)。
## 什么时候_不_该使用它
- 文件内部的字面字符串 / 短语 / 正则表达式 → **Grep**。
- 阅读实现 → 在 `gs` 为你提供了结构之后使用 **Read**。
- `find` 提示 _"no indexed file contains any of […]"_ → 这些标识符不在代码库中。不要去 grep 拼写变体。
## 开发
```
npm install
npm run build
npm test
# 从你的 build 运行 query:
node dist/index.js find auth --root .
# 在单个进程中运行 MCP server(无后台 keeper)以进行 debugging:
node dist/index.js --root . --no-daemon
```
有关 coldstart 为何不计算自身语义,请参阅 [PHILOSOPHY.md](./PHILOSOPHY.md);有关索引管道、进程模型和笔记本内部结构,请参阅 [ARCHITECTURE.md](./ARCHITECTURE.md);有关恢复程序,请参阅 [TROUBLESHOOTING.md](./TROUBLESHOOTING.md)。
## 限制
1. 它是一个路由层加上一个由 Agent 编写的笔记本——没有语义分析或生成的代码摘要。这是故意的:进行消费的 Agent 就是语义层(参见 [PHILOSOPHY.md](./PHILOSOPHY.md))。
2. `gs` 调用者是一跳且基于文件范围的。成员表达式调用(`this.method()`、`api.method()`)不会被跨文件解析;命名函数/常量调用会被解析。通过在调用者文件上调用 `gs` 来追踪更深层的跳数。
3. 动态/计算的 imports(`import(variable)`)和运行时 DSL 引用(多态关联、由 gem/reflection 支持的模型)仍然无法解析。
4. 隐藏目录和超过 1 MB 的文件会被索引跳过。
5. keeper 是针对单个代码库和单台机器的——不能跨项目或主机共享。笔记本_确实_可以移动:它的 `.raw` 日志会被提交,并在不同分支和机器之间进行 union-merge(求并集合并)。
6. 笔记本的质量受限于编写的 Agent 实际阅读的内容——笔记对其陈述的内容是准确的,但笔记并不能证明其完整性。
## License
MIT标签:AI编程助手, AST解析, MCP, MITM代理, SOC Prime, 代码知识库, 代码索引, 开发工具, 暗色界面, 自动化payload嵌入, 自动化攻击