关于 scree
scree 是面向 Claude Code 用户的本地搜索工具,可检索代码仓库和笔记文件夹中的 Markdown。它结合语义与关键词检索,以 SQLite 按文件夹保存索引,并返回带源文件行号的匹配片段。
主要功能
- 01按标题将 Markdown 拆分为片段
- 02支持语义、关键词和混合搜索
- 03每个文件夹单独保存 SQLite 索引
- 04在 Claude Code 会话期间保持索引更新
- 05返回带行位置的匹配片段
- 06应用多层文件忽略规则
适用场景
- 01查找相关笔记而不加载整个文件
- 02同时搜索精确标识符和相关 Markdown
- 03按源文件行号定位文档内容
- 04建立索引前排除私人文件
MCP 相关
MCP 服务通过 stdio 向 Claude Code 提供文档搜索。它在本地为 Markdown 建立索引;语义嵌入通过 API 请求,关键词搜索则在本地运行。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
scree
通过 MCP 向 Claude Code 提供对仓库和笔记中 Markdown 内容的本地语义搜索。
Scree 按标题拆分 Markdown,通过 API 为各部分生成嵌入向量,并将其存储在磁盘上的 SQLite 文件中,每个文件夹对应一个索引。Claude Code 会检索与问题匹配的少量文本块,而不是加载整个文件。每条结果都会注明其来源行,因此 Claude 只需读取这些内容即可。Markdown 始终是事实来源;索引可随时删除并重建。
设计说明请参阅 docs/SPEC.md。
快速开始
需要 Go 1.26 和一个 OpenRouter API 密钥,获取地址为 https://openrouter.ai/settings/keys。除非某个步骤另有说明,否则命令均在此仓库的根目录下运行。
-
构建静态二进制文件(不使用 CGO):
CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o bin/scree ./cmd/scree -
将密钥保存到设置文件中。
scree key会提示你输入密钥,输入时不会回显,因此密钥不会留在 shell 历史记录中,也不会显示在屏幕上;它会以权限模式 600 写入~/.config/scree/env,并向 API 发起一次测试调用:bin/scree key它会保留文件中的其他行,并替换之前保存的密钥。
scree key < file则会从文件的第一行读取密钥,并且只有使用-replace才会替换已保存的密钥;-offline会跳过测试调用,-check则只执行测试调用。在提示处按 Ctrl-C 不会保存任何内容。若要将 Claude Code 的 OpenRouter 费用与自己的搜索费用分开,请使用bin/scree key -mcp保存第二个密钥:之后scree mcp会使用该密钥,其他命令仍使用第一个密钥(见设置文件)。 -
安装二进制文件:
mkdir -p ~/.local/bin install -m 755 bin/scree ~/.local/bin/Claude Code 必须能在
PATH中找到scree。如果~/.local/bin不在其中,请在 shell 配置文件中添加它。 -
在为仓库建立索引前检查它。
scree run会加载设置文件并运行 scree 命令。在仓库内运行:cd ~/code/myrepo scree run doctor -vdoctor -v会列出所有将被忽略的文件,并估算为其余文件建立索引的费用。如果任何私密内容显示为可建立索引,请在建立索引前添加.screeignore或.gitignore条目。 -
**在仓库中启用 scree。**在仓库根目录运行:
claude mcp add scree --scope project -- scree mcp这会写入
.mcp.json,内容为"command": "scree", "args": ["mcp"],不含密钥或路径,因此请将其提交到仓库。Claude Code 会要求每个人批准一次项目服务。此后,该仓库中的每个会话都会保持索引为最新状态;第一个会话会在后台构建索引。若仓库自身的.mcp.json未声明scree mcp,serve就会拒绝处理该仓库,因此即使 scree 也在其他位置注册,该仓库没有此条目也绝不会建立索引。无论如何,都不要在用户级别注册 scree。**批准项目服务意味着信任该仓库。**Claude Code 会在启动服务前应用仓库
.mcp.json中的env,包括PATH,因此你批准的仓库可以决定scree实际指向哪个程序,而该程序可以访问你的设置文件。只有在信任仓库的.mcp.json时才批准其中的 scree,就像批准任何项目服务一样。若要撤销此选择,请参阅绝对路径。 -
**可选:在仓库之外使用笔记文件夹。**请参阅笔记文件夹。
构建
需要 Go 1.26。不使用 CGO。带标签的版本还会在 GitHub releases 页面发布 Linux、macOS 和 Windows(amd64 和 arm64)的预编译二进制文件、ghcr.io/jrapakko/scree 镜像,以及一个 Claude Desktop 安装包;scripts/mcpb.sh 会使用该版本的二进制文件将其打包为 zip。
CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o bin/scree ./cmd/scree
配置
设置通过环境变量提供。设置文件是存放这些设置(包括 API 密钥)的唯一位置。不要在 shell 配置文件中 export 密钥。如果未设置 OPENROUTER_API_KEY,直接运行命令(scree search、doctor、reindex、watch)时仍会使用设置文件中的密钥,运行方式与 scree run 相同;详见下文。
| 变量 | 默认值 |
|---|---|
SCREE_DB | $XDG_DATA_HOME/scree/indexes/<folder>-<hash>/index.db,每个文件夹一个(或使用 -db) |
SCREE_MODEL | openai/text-embedding-3-small |
SCREE_DIMENSIONS | 512;0 表示使用模型的默认维度 |
SCREE_EMBED_URL | https://openrouter.ai/api/v1/embeddings |
SCREE_MAX_FILE_BYTES | 1048576;超过此大小的文件会被跳过 |
SCREE_FIRST_SYNC_MB | 50;如果文件夹中的 Markdown 文件超过此大小,Claude Code 会话或 watch 不会启动该文件夹的首次索引(0 = 不限);scree reindex 始终会执行 |
SCREE_ZDR | 1;对于 OpenRouter 以外的端点,设为 0 |
SCREE_HTTP_TOKEN | 无;使用 serve -allow-remote 时必需,若已设置,也会在回环地址上强制校验 |
SCREE_PAGER | /usr/local/bin、/usr/bin 或 /bin 中的 less -FRX;在终端中显示 scree search 文本视图时使用的分页器,不通过 shell 运行:可以是绝对路径,也可以是这些目录中的名称(绝不通过 PATH 查找),后面可接参数。设为空则不使用分页器 |
SCREE_COLORS | word=1:match=1;33:link=36:lineno=2;文本视图的颜色,使用 SGR 代码(仅限数字和 ;),分别用于词语标题、匹配词语、位置和行号。将某项设为 match= 可关闭其颜色 |
OPENROUTER_API_KEY | 无;若未设置,且设置文件中存有密钥(scree key 会将密钥写入该文件),则 search、reindex、doctor 和 watch 的运行方式与 scree run 相同。若没有密钥(未设置或为空),则只为关键词搜索建立笔记索引,auto 搜索会运行 keyword |
SCREE_MCP_API_KEY | 无;仅从设置文件读取(scree key -mcp 会将密钥写入该文件),且仅由 scree mcp 使用;它会将该密钥作为 OPENROUTER_API_KEY 传给 serve,而不是使用文件中的密钥。直接运行的命令和 scree run 均不会使用它 |
$XDG_DATA_HOME 默认为 ~/.local/share;相对路径会被忽略。如果它未设置,且主目录不是绝对路径,scree 将拒绝打开索引,除非通过 -db 指定索引。
选择文件夹。 使用 -notes <dir> 在命令行中指定文件夹。若未指定,CLI 命令会使用当前目录的 git 根目录;若当前目录不在 git 仓库中,则使用当前目录。在 Claude Code 下,serve 会索引 Claude Code 启动时工作目录的 git 根目录(项目或当前活动的工作树),拒绝使用 -notes、-db 和 SCREE_DB,并要求 CLAUDE_PROJECT_DIR 位于同一个仓库中;.mcp.json 可以设置环境变量,但不能设置工作目录。此外,如果文件夹根目录下的 .mcp.json 未指定 scree mcp 服务,serve 也会拒绝使用该文件夹。在 Claude Code 之外,serve 没有默认文件夹:请传入 -notes。如果自动找到的文件夹是你的主目录(从密码数据库获取,只有查询失败时才回退到 $HOME)、主目录的上级文件夹或文件系统根目录,则会被拒绝;在命令行中传入 -notes 即可强制为其建立索引。即使通过 -notes 指定,serve 也会拒绝此类文件夹(例如 Claude Desktop 这样的客户端会传入用户选择的文件夹),除非指定 -allow-home。检查会比较文件夹本身,而不只是其路径,因此指向主目录的其他路径(如绑定挂载、macOS 上不同的字母大小写、/System/Volumes/Data/Users/…)也会被拒绝。检查只会将所选文件夹与主目录及其上级文件夹进行比较,因此,若某个文件夹内部挂载了主目录(某些容器和开发容器会如此配置),则无法检测到。每个索引都会记录其对应的文件夹,并拒绝用于其他文件夹。
更改模型或维度需要运行 scree reindex -all。索引会记录创建它时使用的模型,并拒绝混用不同模型。
隐私
每次嵌入请求都会要求 OpenRouter 仅路由到数据零留存且 data_collection: deny 的端点。没有此类端点的模型会报出明确错误并指出模型名称,而不会改用会保留数据的端点。设置 SCREE_ZDR=0 可关闭此限制,其他兼容 OpenAI 的端点可能需要这样做。发送到 API 的只有分块文本及其路径和标题;关键词搜索在本地运行。
忽略文件
被忽略的文件不会被读取以进行索引,不会发送到嵌入 API,不会出现在搜索结果中,并且会被 read_doc 和 reindex 拒绝。以下四层规则共同决定忽略哪些文件:
- 内置规则: 隐藏文件和文件夹,但根目录下的
.claude/(不包括.claude/worktrees/)、.github/、.gitlab/、.gitea/、.forgejo/、.cursor/、.codex/、.gemini/、.windsurf/、.circleci/和.buildkite/除外;扩展名不是.md、.markdown或.mdc的文件;指向文件夹外部的符号链接;超过SCREE_MAX_FILE_BYTES的文件;FIFO 等非普通文件(永远不会打开,且doctor会将其报告为不可读);以及名称中包含控制字符的文件。 .gitignore: 在 Git 仓库中,Git 忽略的所有内容(包括嵌套的.gitignore文件、.git/info/exclude和全局排除文件)。node_modules/等被忽略的文件夹不会被读取,嵌套仓库会被跳过。匹配某条规则的已跟踪文件仍会被忽略。设置-gitignore=false可关闭此层规则。.screeignore: 位于已索引文件夹的根目录,使用 gitignore 语法。- Front matter: 文件 front matter 中的
scree: ignore。
# .screeignore
journal/
**/private-*.md
/inbox/scratch.md
!journal/public.md
在 .screeignore 中使用 include-hidden .name/ 可索引另一个根级隐藏文件夹;使用 /.cursor/ 之类的规则可取消一条默认规则。! 规则会重新包含被排除文件夹中的文件,但不会重新包含被规则按名称匹配的文件,因此即使在 !archive/2024/ 之下,*.private.md 仍会被忽略;doctor -v 会列出由 ! 规则重新包含的内容。如果无法读取 .screeignore、它是符号链接,或其中有 scree 无法解析的行,则在修复之前不会索引任何内容;doctor 会按行号指出错误行。
---
scree: ignore
---
在依赖某条规则之前,运行 scree doctor -v 查看每一层忽略了哪些内容。完整规则见 docs/SPEC.md。
使用
scree key # save the API key in the settings file
scree key -mcp # optional: a separate key for scree mcp (Claude Code)
scree doctor # check config, index, and the API
scree doctor -v # also list every ignored file, and check the keyword index
scree reindex # index new and changed files
scree reindex docs/a.md # re-index one file
scree reindex -all # rebuild from scratch
scree search "how do I rotate the backup keys"
scree search -mode keyword PURGE_OLD_RECORDS # exact words, no API call
scree search -format text "ci seed" # hits grouped by query word (the default on a terminal)
scree search -no-pager "ci seed" # the same, printed without the pager
scree search -format json "…" # one JSON object per hit
scree search -format grep "…" # path:line:text, for fzf or vim -q
scree watch # keep the index current (run as a service)
scree serve -notes . # MCP over stdio, from a terminal
scree serve -notes . -http 127.0.0.1:7077 # MCP over HTTP, loopback only
scree indexes # list per-folder indexes; -prune deletes ones whose folder is gone
除 indexes 和 key 外,每个命令都接受 -notes <dir>、-db <file> 和 -gitignore=false。在 Claude Code 之外,serve 需要 -notes。如果未设置 OPENROUTER_API_KEY,但设置文件中有密钥,那么在终端运行 search、reindex、doctor 和 watch 的效果与运行 scree run <command> 相同;无论如何,scree run 都会加载该文件,例如 scree run search "…"。
搜索模式
scree search -mode 和 search_docs 工具的 mode 可使用以下模式:
auto(默认):使用semantic,除非查询中含有类似标识符的词、包含字母和_或数字的词(例如PURGE_OLD_RECORDS、psycopg_pool、R7-Q2或v2),或文件夹代码词汇表(见下文)中的词;此时使用hybrid。ID、API、2026和well-known不计入。hybrid:对分块文本、标题和路径执行向量搜索及 SQLite FTS5 关键词搜索,再通过倒数排名融合合并结果,因此精确名称会排在前面。semantic:仅使用向量。keyword:仅使用 FTS5。此模式不会调用 API,因此没有密钥或 API 停机时也能使用。嵌入调用失败时会说明原因。
没有 API 密钥时,auto 会运行 keyword,并在输出末尾附上 [mode: auto → keyword: no API key; run scree key, or set OPENROUTER_API_KEY];使用 -mode semantic 或 hybrid 则会报错。serve 不会自行读取设置文件;在 Claude Code 下会显示相同提示(scree mcp 会传入文件中的密钥),在其他环境(例如 Claude Desktop)则会提示:add an OpenRouter API key in the extension's settings, set OPENROUTER_API_KEY, or start through scree mcp。在 Windows 上,会去掉其中的 scree key 和 scree mcp 部分。
没有密钥时,索引仍可正常工作:每条笔记都会分块并存储,以供关键词搜索,不会调用 API;reindex 会将这些文件报告为 indexed (N keyword only: no API key)。设置密钥后,下一次同步(scree reindex,或写入器启动时)会且只会为这些文件生成嵌入。在此之前,semantic 和 hybrid 搜索不到它们,并会说明原因([N files indexed for keyword search only; scree reindex embeds them]);scree doctor 会在索引行中统计这些文件。设置密钥后发生的 API 错误或服务中断,不会按无密钥处理:文件仍会像以前一样失败或等待 API 响应。若 API 拒绝密钥(401),则从那以后,该进程只会为关键词搜索建立索引,不会再次请求 API;auto 会运行 keyword,并提示 the embedding API rejected the API key; replace it: <hint>;下一个使用有效密钥的进程会为这些文件生成嵌入。OpenRouter 对被其内容审核标记的输入返回 403,这种情况只会使对应文件失败,与其他 API 错误一样;密钥不会被判定为已遭拒绝。
Scree 会去除 OPENROUTER_API_KEY 首尾的空格和换行符。若值是未填写的 ${...} 占位符,或是 scree key 会拒绝的值(包含内部空白、控制字符或引号),则视为没有密钥,并只记录一行日志,且不会显示该值。
在一组由真实笔记构成的私有数据集上,针对 16 个自然语言查询和 7 个标识符查询进行测试后,auto 将自然语言问题的文件 MRR 保持在 0.89,同时把标识符 MRR 从 0.46 提高到 0.80。始终启用的 hybrid 对标识符的提升同样大,但会损害自然语言问题的效果,因此它不是默认模式。
代码词汇表可以捕获没有 _ 或数字的名称,例如 psycopg 或 PageFetcher。每次同步时,程序都会按照与 Markdown 相同的忽略规则读取依赖项名称,但绝不会进入隐藏文件夹(.claude/ 风格的允许列表仅适用于 Markdown);这些名称来自 requirements*.txt、pyproject.toml、package.json、go.mod 和 Cargo.toml,以及 Python、JavaScript、TypeScript 和 Go 文件导入语句及声明中的混合大小写名称(PageFetcher、useState)。跳过 vendored 文件夹和未更改的文件,每次同步最多打开 20,000 个文件。常见词会被排除,即使它们是包名也不例外:golang.org/x/sync 只会添加完整路径;约 350 个词的停用词表会过滤功能词(how、the)、普通单词形式的包名(sync、requests、next、config),以及以混合大小写书写的普通词(setUp、fileName);漏掉的词仍可能让自然语言问题转到 hybrid。查询中的 PageFetcher's 会按 PageFetcher 计数。在本地索引中只保存转为小写的名称;代码绝不会被分块、生成嵌入或发送给 API。在两个包含代码和文档的代码库上,这一机制略微提升了提及代码的问题的结果,且没有让任何自然语言问题转到 hybrid。
路由只依据词汇表,不论笔记中是否包含该名称:hybrid 的关键词搜索会匹配查询中的每个词,因此即使文档很少提及代码,提及代码的问题也能从中受益。提取器采用基于行的启发式方法,而非解析器,因此可能会把字符串中的文本误读为名称;这种误读最坏只会让问题转到 hybrid,绝不会被打印或生成嵌入。scree doctor 会报告读取到的名称数量,以及笔记中也包含的名称数量(pagefetcher 会匹配 PageFetcher;带点或斜杠的名称,例如 golang.org/x/sync,必须作为短语匹配);-v 只会显示后一类名称的示例;仅在代码中找到的名称绝不会被打印。
查询绝不会作为语法传给 FTS5:每个词都会变成带引号的词项。词项会保留 _ 和 -,因此 psycopg_pool 是一个词项,而单独的 pool 只能通过向量搜索找到它。
结果
在终端中,scree search 会打印按查询词分组的文本视图。每条命中只会列出一次,归在其文本、路径或标题中包含的第一个查询词下,与关键词搜索的匹配方式相同:先显示标题和包含该词的行(最多 10 行,每行截断至 160 个字符),再显示位置,然后显示该范围在当前文件中的所有行,并附上行号(按相同的忽略规则读取,截断至 3,500 字节)。不包含任何查询词的命中(通常仅为语义命中)和过时命中会列在最后;过时命中没有带行号的行。
seed:
### 5.1 Files
- `.forgejo/workflows/ci.yml`: build, test, and the seed from the run number
>docs/plan.md:189-191
>>189 ### 5.1 Files
>>190
>>191 - `.forgejo/workflows/ci.yml`: build, test, and the seed from the run number
other hits:
## Keys
>docs/keys.md:3-4
>>3 ## Keys
>>4 Rotate them yearly.
# Old notes
>docs/old.md (stale)
[mode: auto → hybrid]
词语按完整词元匹配,与关键词搜索相同,包括匹配笔记中写出的路径(ci 会匹配 .forgejo/workflows/ci.yml)以及跨行匹配。支持 OSC 8 链接的终端会将每个位置显示为文件链接。查询词在摘录和带行号的行中匹配到的地方都会着色;词语标题、位置和行号也各自有颜色(SCREE_COLORS)。设置 NO_COLOR 或 TERM=dumb 可关闭链接和颜色(scree run search 也会遵循此设置)。使用 -mode keyword 可显示类似 grep、但不含语义命中的视图。
在终端中,文本视图会通过分页器显示,因此会从顶部开始:less -FRX(如果视图能在一屏内显示完毕,就会立即退出;保留颜色和链接,并在退出时让文本留在屏幕上),或使用 SCREE_PAGER。less 566 及更高版本会通过 -R 传递 OSC 8 链接;较旧版本会将其显示为原始转义序列,因此请在这些版本中使用 -no-pager 或 SCREE_PAGER=。使用 -no-pager、设置为空值的 SCREE_PAGER=、管道,或无法启动的分页器时,内容会直接打印。提前退出分页器不算错误。除非设置了 LESSCHARSET,分页器会以 LESSCHARSET=utf-8 运行,因此即使没有 LANG,less 也能显示 → 等字符。scree run search 以及使用设置文件中的密钥直接运行的 scree search,只会从设置文件读取 SCREE_PAGER 和 SCREE_COLORS。只有当 TERM 是 xterm-256color 这类普通终端名称时,它们才会传递你的 TERM;绝不会传递 TERMINFO、TERMINFO_DIRS 或 TERMCAP。如果没有可用的 TERM,就不会使用默认的 less,因为 less 需要它。
通过管道传输或使用 -format xml 时,每条命中都是一个 <hit> 元素:
<hit n="1" path="docs/setup.md" lines="12-19" heading="Setup > Keys" score="0.912" match="both">
chunk text
</hit>
lines是文本块所来自的源文件行范围,因此 Claude 可以准确读取这些行(read_doc(path, start, end))。如果文件在建立索引后发生变化,搜索会在当前文件中查找该文本块(精确匹配或忽略空白变化),并报告当前范围。如果文本已不存在,该命中会带有stale="true",且没有lines。已更改的文件会加入重新索引队列。match表示找到该命中的搜索方式:semantic、keyword或both。score是余弦相似度;仅由关键词搜索命中的结果没有此字段。- 如果多个文件中存在相同的文本块(例如已提交的构建副本),搜索只会返回一条命中。显示的副本路径最短;
also="docs/print/x.md:12-18, …"会列出最多另外三个副本,其余副本数量会记录在also_more="N"中。列出的副本若其文件发生变化,会像该命中一样重新定位,或显示为path:stale。使用.screeignore排除构建文件夹仍是更好的做法:这样可以节省嵌入成本。 - 在
auto模式下,输出末尾会有类似[mode: auto → hybrid]的行。
-format json 会逐行打印一个对象,这是脚本和评测使用的稳定格式:{"n","mode","path","start","end","heading","score","match","stale","also","also_more"}。其中 mode 是实际运行的模式;缺失时,start、end 和 score 为 null;also 是由 {"path","start","end"} 组成的列表(文本已不存在的副本会带有 "stale":true);只有存在更多副本时才会出现 also_more。
-format grep 会打印类似 grep -n 的 path:line:text 行:按排名顺序列出每条命中中包含查询词的行,或语义命中的首行;每行只列出一次,并移除控制字符。使用 fzf 选择一条命中并在 vim 中打开,或将所有命中加载到 vim 的 quickfix 列表中:
sg() { scree search -format grep "$*" | fzf --delimiter : \
--preview 'n={2}; case $n in ""|*[!0-9]*) exit;; esac; sed -n "$(( n>5 ? n-5 : 1 )),+30p" -- {1}' \
--bind 'enter:become(n={2}; case $n in ""|*[!0-9]*) exit 1;; esac; vim "+$n" -- {1})'; }
vim --cmd 'set efm=%f:%l:%m' -q <(scree search -format grep "ci seed")
路径相对于所在文件夹,因此请从该文件夹的顶层运行这些命令。你没有编写的文件夹可以自行选择文件名和文本,因此应将这些字段视为不可信数据:检查该行是否为数字,并像上面那样在路径前加上 --,而不是将 {1} 或 {2} 粘贴到 Shell 算术表达式或命令行中;同时为 vim -q 指定 %f:%l:%m 错误格式,因为其默认格式也会匹配笔记文本中的 "file" line N:。对于路径中含有 : 或控制字符的匹配项,scree 会将其排除(并在 stderr 中显示数量);对于以 - 或 + 开头的路径,则会在前面加上 ./。
设置文件
scree mcp(用于 Claude Code)、scree run(从终端运行)和 systemd 单元都读取同一个文件 ~/.config/scree/env,因此 API 密钥只需存放一处,且文件权限为 600。scree key(快速开始的第 2 步)会创建该文件或更新其中的密钥。文件中存放密钥和可选设置,不存放文件夹。
直接运行命令而不使用 scree run 时,命令会使用环境变量。如果 OPENROUTER_API_KEY 未设置(或为空、是占位符或无效,如上所述),且此文件中存有密钥,那么 search、reindex、doctor 和 watch 会改为按照 scree run 的方式重新运行:仅使用此文件构建环境,因此密钥只会发送到文件中的 SCREE_EMBED_URL(或默认端点),并通过文件中配置的代理发送(如果有);Shell 中的 SCREE_*、代理、SSL_CERT_FILE 或 GODEBUG 变量均不会生效。此时 doctor 会说明密钥来自此文件。文件缺失或其中没有密钥,均表示没有密钥。若文件未通过下述检查,命令会发出一条指出问题的警告,并在无密钥的情况下运行(auto 搜索会运行 keyword)。
serve 本身从不读取该文件;在 Claude Code 下,scree mcp 已经应用了其中的设置。
文件还可以存放第二个密钥 SCREE_MCP_API_KEY,该密钥由 scree key -mcp 写入(其标志和规则与 scree key 相同;-check -mcp 用于测试该密钥)。随后,scree mcp 和 scree mcp -docker 会将此密钥作为 OPENROUTER_API_KEY 传给 serve,而不是使用文件中的常规密钥。这样,OpenRouter 按密钥统计的用量就能将 Claude Code 与 scree search 及其他命令区分开,后者仍使用 OPENROUTER_API_KEY。SCREE_MCP_API_KEY 不会以其自身名称传递给任何进程。如果该密钥不可用(为空、是占位符、含有内部空白字符或引号),scree mcp 会在 stderr 中说明原因,但绝不会显示密钥值,并会改用 OPENROUTER_API_KEY;doctor 也会对此发出警告,否则会说明 scree mcp 正在使用单独的密钥。和其他设置一样,文件中最后一条 SCREE_MCP_API_KEY 配置会生效。
~ 根据密码数据库确定(即登录用户的主目录),而不是根据 $HOME 或 $XDG_CONFIG_HOME 确定。如果文件缺失、是符号链接、不归你所有,或对组用户或其他用户可读,scree mcp 和 scree run 都会拒绝启动;最后一种情况可通过 chmod 600 修复。对于这类文件,scree key 也会拒绝操作(文件缺失则没问题);如果 ~/.config/scree 文件夹是符号链接、不归你所有或对组用户或其他用户可写,如果 ~/.config 是符号链接,或者密钥会使文件大小超过 64 KB,也会拒绝操作。在 Linux 上,主目录取自 /etc/passwd;如果是 LDAP 或 sssd 登录,则会使用 getent passwd。如果两者都无法识别你的账户,程序会拒绝启动,而不会信任 $HOME。它们不能在 Windows 上运行:请在环境中设置变量,然后直接运行 scree serve -notes … 或其他命令。
每行写一个 NAME=value,并像 scree key 一样用单引号括起值,这样含空格的路径就会作为一个整体值处理。允许使用 export 前缀。文件会作为数据读取,绝不会作为 Shell 脚本运行,因此不会展开值中的任何内容。只接受 scree 自身的变量(SCREE_*、OPENROUTER_API_KEY)、代理变量,以及 DOCKER_HOST 和 DOCKER_CONTEXT(仅传递给 scree mcp -docker 启动的 docker);任何其他变量名都会被视为错误,并指出所在行。Configure 表中的其他变量也可以写入同一文件。值本身不能包含用于包裹它的引号字符。
Claude Code
scree mcp 会加载设置文件并运行 scree serve。Claude Code 只会保存命令,因此密钥不会留在 ~/.claude.json 中。安装 scree(快速入门第 3 步),然后从每个仓库的根目录为其注册:
claude mcp add scree --scope project -- scree mcp
提交生成的 .mcp.json。serve 会为 Claude Code 启动时所在工作目录的 Git 根目录建立索引,检查 CLAUDE_PROJECT_DIR 是否位于同一个仓库中,并检查仓库的 .mcp.json 是否指定了 scree mcp(command 为 scree,或以 /scree 结尾的路径,且第一个参数为 mcp)。在工作树中,建立索引的是该工作树。一个仓库中的多个会话共享同一个索引:一个会话负责写入,其他会话读取;写入者退出后,另一个会话会接手。若仓库大小超过 SCREE_FIRST_SYNC_MB,则在仓库中运行一次 scree run reindex 之前不会建立索引;搜索会对此作出提示。
这些工具是 search_docs(query, k, mode?)、read_doc(path, start?, end?) 和 reindex(path?)。每条搜索结果都包含行范围,因此 Claude 可以只读取这些行;复制文件夹中重复的内容会合并为一条结果(also=)。仍请使用 .screeignore 排除构建输出。
设置文件是 scree mcp 使用的唯一配置。仓库已提交的 .mcp.json 会设置它的启动环境,因此 scree mcp 会忽略该环境:它会拒绝除 -docker 之外的所有参数,从密码数据库中查找设置文件,并用自身二进制替换自身(exec),在仅包含 HOME(你的 passwd 主目录)、PATH=/usr/local/bin:/usr/bin:/bin、CLAUDE_PROJECT_DIR 以及文件中设置项的环境中运行 scree serve。其他任何内容都不会传入:包括继承的 SCREE_*、密钥或代理变量、XDG_DATA_HOME、XDG_CONFIG_HOME、DOCKER_HOST,以及 Go 运行时的 GODEBUG 和 GOMAXPROCS。scree 是不带 shell 的静态二进制,因此 LD_PRELOAD、bash 的 SHELLOPTS 和 PS4,以及导出的 BASH_FUNC_* 函数(这些内容可能会在旧的 shell 包装脚本执行第一行之前产生作用)对它都不起作用。真正的 scree 启动后,仓库环境无法将你的密钥发送到其他端点、替换设置文件、移动索引或让 scree 指向其他文件夹。不过,仓库环境仍可通过 PATH 决定最初以 scree 名义运行哪个程序;请参阅快速入门中的信任说明。(在 macOS 上,Go 二进制会动态链接系统库,因此 DYLD_* 变量仍可影响第一个进程;请参阅 docs/SPEC.md 中尚待解决的事项。)
使用普通的 scree 或绝对路径
已提交的 .mcp.json 指定普通的 scree,因此无论安装目录是什么,每个人都能使用;二进制由每个人自己的 PATH(或仓库的 env)查找。在只有你自己使用的配置中,改为注册绝对路径,这样就不会由 PATH 决定哪个程序能获取你的设置。此项目在 ~/.claude.json 中保存的本地作用域条目,会优先于项目中同名的条目,包括 env:
claude mcp add scree --scope local -- "$HOME/.local/bin/scree" mcp
运行命令时,shell 会展开 $HOME,因此保存的命令是绝对路径,例如 /home/you/.local/bin/scree。仓库已提交的 .mcp.json 仍必须指定 scree mcp;这是仓库选择启用该功能的方式。
建议通过 scree mcp 使用 Stdio。serve -http 仅监听回环地址。非回环地址需要 -allow-remote 和至少 16 个字符的 SCREE_HTTP_TOKEN,之后每个请求都必须发送 Authorization: Bearer <token>。请将令牌保存在设置文件中,而不要放在命令行上:
printf 'SCREE_HTTP_TOKEN=%s\n' "$(openssl rand -hex 32)" >> ~/.config/scree/env
scree run serve -notes ~/notes -http 0.0.0.0:7077 -allow-remote
请在终端中运行此命令,不要在 Claude Code 会话中运行;会话中会设置 CLAUDE_PROJECT_DIR,而 serve 会拒绝 -notes。
客户端随后需要该请求头。如果通过 claude mcp add --transport http ... --header "Authorization: Bearer $SCREE_HTTP_TOKEN" 添加请求头,shell 展开变量可以避免令牌进入 shell 历史记录,但 Claude Code 仍会将展开后的请求头保存在 ~/.claude.json 中。
一个笔记文件夹
在命令行中使用仓库之外的文件夹,例如 ~/notes:
scree run reindex -notes ~/notes
scree run search -notes ~/notes "backup password"
systemd unit 会运行 scree run watch -notes ~/notes 使其保持最新。要在 Claude Code 中搜索该文件夹,请在 ~/notes 中运行 claude mcp add scree --scope project -- scree mcp,然后在那里启动 Claude Code;它不是一个 git 仓库,因此该文件夹本身就是 ~/notes。在其他位置运行的 Claude Code 会话无法访问它,因为在 Claude Code 中,serve 只会索引会话所在的文件夹。
Claude Desktop(一键安装包)
未经测试。 该安装包尚未在任何平台上的任何 MCP 客户端中测试过:既未在 Claude Desktop 中测试,也完全未在 macOS 或 Windows 上测试过。它并非面向 Linux。仅在 Linux 上使用 Linux 构建版本测试了它所运行的服务命令。请预期会有一些问题,并欢迎反馈发现的情况。
0.3.6 之后的版本包含 scree_<version>.mcpb,这是适用于 macOS 和 Windows 上 Claude Desktop 的 MCPB 安装包。它包含 macOS 通用二进制文件和 Windows amd64 二进制文件(Windows ARM 会通过模拟运行)。在 Claude Desktop 中打开该文件即可安装,并会要求设置两项内容:
- 笔记文件夹(必填):scree 用于索引和搜索的文件夹。选择该文件夹即表示选择加入,因此
.mcp.json检查不适用。请选择笔记文件夹或仓库:服务会拒绝你的主目录、位于主目录上层的文件夹或驱动器根目录,并且不会启动。 - OpenRouter API key(可选):没有该密钥时,scree 只会按关键词索引和搜索。提供密钥后,也可以按含义搜索,笔记和每条查询都会发送到 OpenRouter 进行嵌入。粘贴在密钥周围的空格或换行符会被去除。如果 OpenRouter 拒绝该密钥,scree 仍会仅按关键词运行,搜索结果也会说明密钥已被拒绝。
随后,Claude Desktop 会从安装包中运行 server/scree serve -notes <folder>,并将 OPENROUTER_API_KEY 设为该密钥或空值。安装包不会读取设置文件,因此其中的 SCREE_MODEL、SCREE_DIMENSIONS 和 SCREE_EMBED_URL 不适用。已使用其他模型建立索引的文件夹会被拒绝。包含超过 50 MB Markdown 的文件夹不会自动建立索引;搜索结果会说明这一点,并告知 Claude 在运行不带路径的 reindex 工具(该工具仍会为其建立索引)之前先询问你。索引存放在 CLI 指定的位置,因此 CLI 可以搜索同一文件夹;请让两者保持相同版本,因为其中一个可能会将索引升级到另一个无法读取的版本。
这些二进制文件未签名或公证。在 macOS 上,Gatekeeper 可能会拒绝运行已下载安装包中的 server/scree,直到你在“系统设置”→“隐私与安全性”中允许它;未签名的二进制文件也会带来 docs/SPEC.md 中所述的 DYLD_* 注意事项。Windows SmartScreen 也可能发出类似警告。每个版本还包含 scree_<version>.mcpb.sha256(sha256sum 格式;使用 sha256sum -c 检查,或在 macOS 上使用 shasum -a 256 -c),注册表条目 io.github.jrapakko/scree 也记录了相同的 sha256。客户端是否会在安装时检查该值尚未测试。
后台服务(systemd)
# needs ~/.config/scree/env from "Settings file" above
mkdir -p ~/.local/bin ~/.config/systemd/user
cp bin/scree ~/.local/bin/
cp contrib/scree-watch.service ~/.config/systemd/user/
systemctl --user daemon-reload && systemctl --user enable --now scree-watch
journalctl --user -u scree-watch -f
该单元会运行 scree run watch -notes ~/notes,因此它会像 scree mcp 一样读取设置文件(而不是通过 systemd 的 EnvironmentFile)。如需使用其他文件夹,请编辑 ExecStart 中的 -notes。如果该文件夹中的 Claude Code 会话已持有写入锁,它会等待该锁释放。
Docker 或 Podman
该镜像约为 18 MB。它只包含静态二进制文件,并以非特权用户身份运行。文件夹以只读方式挂载,索引存放在 /data 卷中。在 Linux 上,文件变更事件会通过绑定挂载传递到容器中。在 macOS 上,Docker Desktop 不会传递这些事件,因此 watch 无法检测到其中的编辑。日常使用请改用原生二进制文件或 systemd 单元。
SELinux 主机(Fedora、RHEL、CentOS Stream)需要在每个绑定挂载上添加 :z。否则,容器无法读取挂载的文件夹,scree 会报错 open /notes: permission denied。以下示例均包含 :z,而 scree mcp -docker 需要在设置文件中配置 SCREE_MOUNT_OPTS=ro,z。:z 会永久重新标记主机上文件夹中的每个文件(标记为 container_file_t),即使挂载为只读也是如此。请挂载笔记文件夹或代码库,切勿挂载主目录。在未启用 SELinux 的系统上,请移除 :z。如果不想重新标记任何内容,请改用原生二进制文件。
docker build -t scree . # or: podman build -t scree .
使用 docker run:
# background indexer
docker run -d --name scree-watch --restart unless-stopped \
-e OPENROUTER_API_KEY \
-v "$HOME/notes:/notes:ro,z" -v scree-data:/data \
scree watch -notes /notes
# one-off commands against the same index
docker run --rm -e OPENROUTER_API_KEY -v "$HOME/notes:/notes:ro,z" -v scree-data:/data scree doctor -notes /notes
docker run --rm -e OPENROUTER_API_KEY -v "$HOME/notes:/notes:ro,z" -v scree-data:/data scree search -notes /notes "backup password"
不带值的 -e OPENROUTER_API_KEY 会从 shell 传递该变量,因此密钥不会出现在命令行中。
使用 compose 时,它会从 shell 或 compose.yaml 所在目录中的 .env 读取 OPENROUTER_API_KEY:
SCREE_NOTES_DIR=$HOME/notes docker compose up -d # starts watch
docker compose logs -f watch
SCREE_NOTES_DIR 只是 compose 为挂载到 /notes 的主机文件夹指定的名称。compose.yaml 也会传递 SCREE_MODEL、SCREE_DIMENSIONS、SCREE_MAX_FILE_BYTES、SCREE_FIRST_SYNC_MB、SCREE_ZDR 和 SCREE_EMBED_URL,并将 SCREE_HTTP_TOKEN 传递给 serve。serve 服务位于 mcp 配置文件之后,因此 up 不会启动它。
对于 Claude Code,MCP 服务可以通过 stdio 为每个会话运行一个容器。scree mcp -docker 会加载设置文件并运行 docker run -i --rm --pull=never(不会从镜像仓库拉取缺失的镜像,因为容器会获取密钥),将项目文件夹以只读方式挂载到其自身路径(因此每个代码库都会在 scree-data 卷中拥有自己的索引),并挂载 scree-data 卷;同时只会按名称传递已设置的选项(-e NAME),因此密钥不会出现在命令行中。它会按照与 serve 相同的规则挂载其工作目录的 git 根目录(仅限通过你拥有且不是符号链接的 .git,并且绝不位于粘滞文件夹中或其上级目录中,例如 /tmp),因此 .gitignore 会生效;如果 CLAUDE_PROJECT_DIR 位于另一个工作树中,它会拒绝启动。serve 会在挂载的文件夹中运行(-w),并应用相同的文件夹规则和 .mcp.json 选择加入检查。你的全局 git 排除文件在容器内不可见,而 git 目录位于挂载文件夹之外的工作树也无法在容器内读取。
代码库中提交的 .mcp.json 指定了 scree mcp,供所有人共用。若要自行使用 Docker,请添加一个本地作用域条目;对你而言,它的优先级高于项目配置:
claude mcp add scree --scope local -- "$HOME/.local/bin/scree" mcp -docker
docker CLI 会获得 HOME 环境变量、值为 /usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin 的 PATH、设置文件中的配置,以及设置文件中指定的 DOCKER_HOST 或 DOCKER_CONTEXT;Claude Code 或代码库环境中的其他内容均不会传递。因此,如果你的引擎需要这两个变量,请在设置文件中设置它们。设置文件中的 SCREE_DOCKER(仅支持 docker 或 podman,且只会在上述目录中查找,不会通过 PATH 查找)、SCREE_IMAGE(默认为 scree:latest;自行拉取的完整限定名 ghcr.io/jrapakko/scree:<version> 也可使用)和 SCREE_DATA_VOLUME(卷名称,而非路径)可以更改引擎、镜像和卷。SCREE_MOUNT_OPTS(默认为 ro)用于设置挂载选项,只接受 ro、ro,z 或 ro,Z;在 SELinux 主机上,请按上文说明设置为 ro,z。它绝不会挂载你的主目录(根据密码数据库确定)、其上级文件夹或 /,并且会拒绝包含 : 的路径。与 scree mcp 一样,它会忽略继承的设置,且不接受其他参数。
在容器内,serve -http 必须绑定非环回地址,才能通过已发布的端口访问,因此需要 -allow-remote 和 SCREE_HTTP_TOKEN。请仅将端口发布到主机的环回地址,例如 -p 127.0.0.1:7077:7077。
watch 和 serve 容器共用 scree-data 卷。与原生进程一样,SQLite 的 WAL 模式允许 serve 在 watch 写入时进行读取。
工作原理
- 每个文件夹在
$XDG_DATA_HOME/scree/indexes/下都有自己的索引。持有索引锁文件的scree serve(每个 Claude Code 会话运行一个)或scree watch是该索引的唯一写入者:它会在启动时按内容哈希同步,然后使用 fsnotify 监视文件;某个路径最后一次发生事件后等待 1.5 s,并且只重新嵌入哈希发生变化的文件。同一索引上的其他进程只读,并每 5 s 重试一次获取锁,因此写入者退出后,其他进程会接管。 - 首次同步在后台运行,因此 Claude Code 可以立即连接;同步完成前,搜索结果会提示索引尚未完成。SQLite 的 WAL 模式允许读取者在写入者写入时进行搜索。
- 搜索结果是
<hit>元素,包含路径、行范围、标题和匹配类型。分块最多 3500 个字符,单条命中的文本最多 4000 个字符,每条响应最多 64 KB。如果查询中包含标识符,搜索会将向量与 SQLite FTS5 关键字索引结合,因此完全匹配的名称会优先显示。read_doc会在<doc>元素中返回文件或指定行范围,最多 256 KB。服务会告知客户端将这两者都视为数据,而非指令。 - 返回每条命中结果前,都会根据当前忽略规则重新检查;因此,新近被忽略或已删除的文件会立即从结果中移除。
- 搜索等待 API 的时间最多为 10 s(尝试 2 次)。索引处理每次尝试最多等待 30 s(尝试 3 次)。API 中断后,索引处理会暂停 30 s,之后逐步延长暂停时间,最长为 5 min,然后重新同步;这样,中断期间发生更改的文件无需再次编辑也能被纳入索引。
- 关闭时,
serve和watch等待写入者的时间最多为 5 s;再次按下 Ctrl-C 或发送 SIGTERM 会立即退出。 - 如果索引文件或文件夹消失或被替换,
scree watch会报错退出,以便 systemd 或 Docker 重启它。在serve中,写入者会停止,搜索会报告此情况。文件夹重命名或忽略文件发生变化时,会重新添加监视。索引目录以 0700 权限创建,其文件权限为 0600。 - 向量存储在 vec1 中,这是 SQLite 的向量扩展,使用平面(精确)余弦索引;关键字存储在 SQLite 的 FTS5 中。两者都由 ncruces/go-sqlite3 编译为 WebAssembly,因此二进制文件无需 CGO。
- scree 只信任由你拥有且不是符号链接的
.git,绝不会在粘滞目录(如/tmp)中或其上级目录查找.git;绝不跟随 git 忽略文件(.gitignore、.git/info/exclude、.git文件)或.screeignore的符号链接;绝不读取仓库的.git/config,也绝不打印这些文件的内容:消息只会指出文件名和行号。由他人拥有的.git会导致错误;若仍要索引其下的文件夹,请传入-notes <folder> -gitignore=false。 - 索引文件、其
-wal和-shm文件以及writer.lock绝不会通过符号链接打开;如果索引文件夹或其上级的scree/indexes文件夹是符号链接,则会拒绝使用。 - 由同一套策略决定允许读取哪些内容;索引处理、搜索、
read_doc和reindex都会通过这套策略。只有位于索引文件夹内的符号链接才会被跟随,并且也会对其目标进行规则检查。不会递归进入符号链接所指向的文件夹。
对于较小的索引,每个进程的空闲内存约为 13–15 MB;索引包含 1000 个文件(4000 个分块)时,约为 20 MB。使用默认模型时,每 MB Markdown 的索引成本约为 $0.0025;doctor 的估算值是上限。
从 scree-mcp 包装脚本迁移
scree-mcp、scree-run 和 scree-mcp-docker 这些 shell 包装脚本已移除;scree mcp、scree run 和 scree mcp -docker 会在二进制文件内部执行相应功能。设置文件保持不变,但不能是符号链接,现在还可以包含 DOCKER_HOST 和 DOCKER_CONTEXT。
-
在每个仓库中,重新注册并提交新的
.mcp.json:claude mcp remove scree --scope project claude mcp add scree --scope project -- scree mcpserve仍接受旧条目(其中指定了scree-mcp),但只有在存在scree-mcp程序时该条目才有效,而现在已不再安装此程序。 -
删除旧包装脚本:
rm -f ~/.local/bin/scree-mcp ~/.local/bin/scree-run。如果你曾将scree-mcp-docker安装为scree-mcp,也请将其删除,并添加本地 Docker 条目。 -
在原先使用
scree-run <command>的地方改用scree run <command>。 -
更新 systemd 单元;现在它会运行
scree run watch,而不是通过EnvironmentFile读取文件:cp contrib/scree-watch.service ~/.config/systemd/user/ && systemctl --user daemon-reload && systemctl --user restart scree-watch。
从单文件夹版本迁移
单文件夹版本会读取 SCREE_NOTES,并将一个索引保存在 ~/.local/share/scree/index.db。现在每个文件夹都有自己的索引,文件夹路径取自仓库或 -notes。
- 从
~/.config/scree/env中删除SCREE_NOTES=这一行。该设置会被忽略,而且只要它还存在,doctor就会发出警告。 - 删除用户级别的注册:
claude mcp remove scree --scope user。该注册会在你打开的每个项目中启动 scree;随后,serve会拒绝所有.mcp.json未指定scree mcp的项目。请改为在每个仓库中注册 scree(参见快速入门第 5 步),并通过命令行指定笔记文件夹。 - 使用
scree run reindex -notes ~/notes在新位置重建笔记索引,然后删除~/.local/share/scree/index.db。或者,使用-db ~/.local/share/scree/index.db保留该索引,并将其用于该文件夹。scree indexes会指出旧文件的位置。 - 更新 systemd 单元:
cp contrib/scree-watch.service ~/.config/systemd/user/ && systemctl --user daemon-reload && systemctl --user restart scree-watch。 - Docker:镜像不再设置
SCREE_NOTES或SCREE_DB;请传入-notes /notes。scree-data卷中的旧文件/data/index.db已不再使用;请重新建立索引。
打开早期的逐文件夹版本所建的索引时,系统会就地升级:下次同步时会填充行范围,而不会对未更改的文件重新生成嵌入;重复哈希和关键词索引则会根据已存储的分块构建。对于使用当前分块大小限制之前的版本所建的索引,需要运行一次 scree reindex -all。
许可证
MIT;详见 LICENSE。发布压缩包和容器镜像中包含捆绑依赖项的许可证(THIRD_PARTY_LICENSES/;镜像中位于 /usr/share/doc/scree)。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。