文件读取门
它是什么
文件读取门是一个 PreToolUse 钩子,用于拦截 Claude 的 Read 工具调用。当 Claude 尝试读取数据库中已有先前观察记录的文件时,该门会阻止读取,而是显示该文件过去工作的简明时间线。然后 Claude 决定获取所需上下文的最廉价路径。
这是 progressive disclosure 的具体实现——先展示已有内容,让代理决定获取什么。
运作方式
Claude calls Read("src/services/worker-service.ts")
↓
PreToolUse hook fires
↓
File size < 1,500 bytes? ──→ Allow read (timeline costs more than file)
↓ No
Project excluded? ──→ Allow read
↓ No
Query worker: GET /api/observations/by-file
↓
No observations found? ──→ Allow read
↓ Has observations
Deduplicate (1 per session)
Rank by specificity
Limit to 15
↓
DENY read with timeline当传送门启动时,Claude会看到这样的消息:
Current: 2026-04-07 3:25pm PDT
Read blocked: This file has prior observations. Choose the cheapest path:
- Already know enough? The timeline below may be all you need (semantic priming).
- Need details? get_observations([IDs]) -- ~300 tokens each.
- Need current code? smart_outline("path") for structure (~1-2k tokens),
smart_unfold("path", "<symbol>") for a specific function (~400-2k tokens).
- Need to edit? Use smart tools for line numbers, then sed via Bash.
### Apr 5, 2026
42301 2:15pm Fixed database connection pooling
42298 1:50pm Refactored worker startup sequence
### Mar 28, 2026
41890 4:30pm Added health check endpoint决策树
Claude在看到时间表后有四个选项,从最便宜到最贵排序:
| 选项 | token消耗 | 何时使用 |
|---|---|---|
| 语义启动 | 0 额外 | 时间轴标题提供给 Claude 足够的信息以继续 |
| get_observations([IDs]) | 每次约300 | 需要来自过去工作的具体细节 |
| smart_outline / smart_unfold | ~1-2k | 需要当前的代码结构或特定函数 |
| 完整文件读取 | 5k-50k | 自观察以来文件已发生重大变化 |
在实际操作中,大多数文件读取都是在语义启动或 get_observations 级别解决的,从而每次交互节省数千个 token。
用于时间推理的当前日期/时间
时间轴的第一行包括当前日期和时间:
Current: 2026-04-07 3:25pm PDT这使 Claude 能够推理观察结果相对于现在的新旧程度。例如:
- 今天的观察 -- 可能仍然准确,语义启动是安全的
- 上周的观察 -- 可能准确,详情请查看 get_observations
- 几个月前的观察 -- 文件可能已更改,请考虑使用 smart_outline 或完整读取
时间戳格式与会话开始上下文头 (YYYY-MM-DD time timezone) 匹配,因此 Claude 在整个会话中看到一致的时间标记。
token经济学
一个典型的源文件完整读取的成本为 5,000-50,000 个 token。文件读取门将其替换为:
| 组件 | token |
|---|---|
| 时间轴标题 说明 | ~120 |
| 15 条观察记录 | 约 250 |
| 总时间表 | ~370 |
如果 Claude 需要更多细节,它会获取每条约 300 个标记的单独观察记录。即使获取 3 条观察记录,总计约 1,270 个标记——相比读取整个文件,仍然节省 75-97%。
现实世界的例子
没有门(阅读 worker-service.ts):
Read: 18,000 个 token与大门一起:
Timeline: 370 个 token
+ 2 observations: 600 个 token
Total: 970 个 token (95% savings)特异性排名
并非关于文件的所有观察都是同等相关的。门会根据每个观察与目标文件的具体相关性对其进行评分:
| 信号 | 分数奖励 |
|---|---|
| 文件被修改(不仅仅是读取) | 2 |
| 观察覆盖 3 个或更少 的总文件 | 2 |
| 观察覆盖 4-8 个文件 | 1 |
| 观察涵盖 9 个文件(类似调查) | 0 |
得分较高的观察会优先出现在时间线上。一个文件是主要修改目标的观察,其排名高于一个文件仅偶然被读取并伴随其他20个文件的观察。
配置
小文件绕过
小于 1,500 字节 的文件总是可以直接通过网关而不会被拦截。在这个大小下,时间线(约 370 个标记)的成本将超过直接读取文件的成本。这个阈值在 src/cli/handlers/file-context.ts 中是硬编码的。
项目排除
与 CLAUDE_MEM_EXCLUDED_PROJECTS 中的模式匹配的项目将完全跳过此门。请在 ~/.claude-mem/settings.json 中配置此项:
{
"CLAUDE_MEM_EXCLUDED_PROJECTS": "/tmp/*,/scratch/*"
}如何关闭门
文件读取门作为 Read 工具匹配器上的 PreToolUse 钩子实现。要禁用它,请从钩子配置中删除 Read 匹配器条目:
打开你的 Claude Code 设置:
~/.claude/settings.json在
hooks.PreToolUse下找到 claude-mem hooks 部分,并移除带有Read匹配器的条目。
或者,如果你想保留门控但在特定读取时绕过它,Claude 可以请求你允许该读取——门控的拒绝决定会呈现给用户,用户可以覆盖它。
禁用门控意味着 Claude 每次都会读取完整文件,这会增加 token 使用量,但确保它始终看到最新的代码。这对于小型项目或观察数据稀少的情况是一个合理的选择。
它是如何组合在一起的
文件读取门是claude-mem分层上下文策略的一部分:
- 会话开始:注入最近观察的时间轴(第1层——元数据)
- 文件读取门:通过观察历史截获读取(第1层——元数据)
- get_observations:按需获取特定观察详情(第2层——详细信息)
- smart_outline / smart_unfold:高效阅读当前代码结构(第3层 -- 源码)
- 完整文件读取:当其他方法都不足时的最后手段
每一层的费用逐渐增加。这个门确保Claude从最便宜的层开始,并且只有在需要时才升级。