agentmemory filesystem-watcher 接入指南:把目录变更变成可检索的持久化记忆
【免费下载链接】agentmemory#1 Persistent memory for AI coding agents based on real-world benchmarks项目地址: https://gitcode.com/GitHub_Trending/age/agentmemory
导读:
agentmemory是面向 AI 编码 Agent 的持久化记忆服务(详见仓库根目录 README.md)。而 integrations/filesystem-watcher/README.md 描述的@agentmemory/fs-watcher,则是它的一个文件系统数据源连接器:它以常驻进程的方式监控一个或多个目录,每当文件发生写入或删除,就把变更作为一条post_tool_use观测(observation)推送给正在运行的 agentmemory 服务器。读完本文,你将掌握它的安装方式、CLI 与环境变量用法、全部配置项与默认值、事件载荷结构,以及底层脱敏、去抖与容错实现,从而把“编辑文件”这一高频行为自动沉淀为 Agent 可检索的记忆。
一、背景:为什么需要文件系统连接器
agentmemory 的核心能力是把 Agent 工作过程中的信号(hook 事件、对话、工具调用等)沉淀为可检索的观测。但这类观测通常来自 Agent 运行时本身(如 Claude Code、Codex、Cursor 的钩子)。而现实中的很多重要信息——笔记、文档、配置、代码草稿——是直接在编辑器中修改的,并不会经过 Agent 的工具调用链路。
@agentmemory/fs-watcher正是为填补这一空白而设计的单向数据源连接器(属于仓库中>npm install -g @agentmemory/fs-watcher
安装后即获得agentmemory-fs-watcher命令(bin字段指向 bin.mjs)。
2.3 不安装直接运行
npx @agentmemory/fs-watcher ~/work/my-reponpx会临时拉取并执行该包,适合快速试用。参数含义与全局安装完全一致:后续 CLI 参数即为要监控的目录列表。
三、用法与参数优先级
3.1 用 CLI 参数指定监控目录
# CLI args win over env. —— CLI 参数优先于环境变量 agentmemory-fs-watcher ~/work/my-repo ~/notes可以同时监控多个根目录,空格分隔即可。从 bin.mjs 的源码可以看到解析逻辑:
const roots = cliArgs.length > 0 ? cliArgs : envCfg.roots;只要 CLI 传入了任意目录,环境变量AGENTMEMORY_FS_WATCH_DIRS就会被忽略,这正是文档中 "CLI args win over env" 的源码依据。
3.2 用环境变量配置
# 一次性设置 export AGENTMEMORY_FS_WATCH_DIRS=~/work/my-repo,~/notes export AGENTMEMORY_URL=http://localhost:3111 export AGENTMEMORY_SECRET=... # 仅当服务器要求认证时 agentmemory-fs-watcher此时不传任何 CLI 参数,进程会从环境读取配置。若既不传 CLI 参数、也未设置AGENTMEMORY_FS_WATCH_DIRS,bin.mjs 会向 stderr 输出用法提示并以退出码 2 结束。
3.3 完整配置项一览
以下参数表完整继承自 integrations/filesystem-watcher/README.md:
| 变量 | 默认值 | 含义 |
|---|---|---|
AGENTMEMORY_FS_WATCH_DIRS | — | 逗号分隔的待监控目录列表 |
AGENTMEMORY_FS_WATCH_IGNORE | — | 逗号分隔的正则模式,匹配相对路径则忽略 |
AGENTMEMORY_FS_WATCH_ALLOW_BINARY | 0 | 设为1时把二进制文件也纳入预览读取 |
AGENTMEMORY_URL | http://localhost:3111 | agentmemory 服务器地址 |
AGENTMEMORY_SECRET | — | Bearer Token;当服务器设置了AGENTMEMORY_SECRET时必须提供 |
AGENTMEMORY_PROJECT | — | 可选,附加到每条观测的项目标签 |
AGENTMEMORY_SESSION_ID | — | 可选,观测归属的会话 id |
结合 watcher.mjs 中的configFromEnv,可以补充两点实现细节:
AGENTMEMORY_PROJECT_NAME是规范覆盖项:代码注释与 test/project-scope-parity.test.ts 的测试均说明,AGENTMEMORY_PROJECT_NAME优先级更高,AGENTMEMORY_PROJECT仅作为向后兼容的别名保留;且两者都会先trim(),纯空白视为未设置。AGENTMEMORY_FS_WATCH_IGNORE是逐条编译为正则的:每个逗号分隔的片段都会new RegExp(s),因此可以直接写foo$、^bar这类锚定表达式(测试中configFromEnv用例对此有断言)。
四、事件语义:一次文件变化 = 一条观测
4.1 观测类型与载荷结构
监控根目录内每次文件变化都会成为一条post_tool_use观测,其data.changeKind为:
file_change:文件被写入/修改;file_delete:文件被删除。
观测载荷的完整形态见 watcher.mjs 的flush方法,其 JSON 结构如下:
{ "hookType": "post_tool_use", "sessionId": "fs-watcher-<ts>-<rand>", "project": "<仓库名或目录名>", "cwd": "<根目录绝对路径>", "timestamp": "2026-09-10T01:06:57.000Z", "data": { "source": "filesystem-watcher", "changeKind": "file_change", "files": ["notes.md"], "content": "notes.md (13 bytes)\n\nhello world\n", "rootDir": "/abs/path/to/root", "absPath": "/abs/path/to/root/notes.md", "size": 13, "truncated": false } }这一结构完全符合 agentmemory 的HookPayload契约。在 src/types.ts 中,HookPayload要求hookType、sessionId、project、cwd、timestamp五个必填字符串字段,watcher 发送的每条消息都完整携带。
4.2 服务端如何消费这条观测
理解载荷之后,值得看一下它进入服务器后的处理链路,这能让"文件变更如何变成可检索记忆"变得具体:
- HTTP 入口:src/triggers/api.ts 中
api::observe注册在POST /agentmemory/observe,会先校验hookType/sessionId/project/cwd/timestamp五个必填字段,再转发给mem::observe(缺失任一字段返回 400)。若服务器配置了AGENTMEMORY_SECRET,该路由还受middleware::api-auth中间件保护(src/triggers/api.ts)。 - 观测入库:src/functions/observe.ts 中的
mem::observe把载荷包装成RawObservation(见 src/types.ts)。由于hookType属于post_tool_use,其origin.channel被标记为tool,同时尝试从data中提取toolName、toolInput、toolOutput。 - 会话自动创建:一个值得注意的细节是,若
sessionId对应的会话尚不存在,只要载荷携带了合法的project与cwd,服务端会自动创建会话记录(src/functions/observe.ts 中else if分支)。这正是 watcher 文档强调"session id 和 project 是 observe 端点必需项"的原因——有了它们,即使 watcher 没有先调用/session/start,记忆也能正确归入会话。 - 压缩与索引:默认走零 LLM 消耗的合成压缩(
buildSyntheticCompression),随后写入 BM25 搜索索引与向量索引(src/functions/observe.ts),使文件内容片段可被后续recall/搜索命中。
4.3 session id 与 project 的自动推导
observe 端点要求会话与项目信息,watcher 的处理策略是"能自动则自动":
- session id:未显式设置
AGENTMEMORY_SESSION_ID时,生成形如fs-watcher-<时间戳36进制>-<3字节随机hex>的按进程会话 id(watcher.mjs 构造函数)。也就是说,一次常驻运行对应一个会话。 - project:默认取第一个根目录的目录名;但若该目录位于 Git 仓库内,则优先使用仓库顶层目录名。这是因为 watcher.mjs 的
deriveProjectName与 hooks 的resolveProject保持相同解析顺序(先git rev-parse --show-toplevel取顶层名,失败再退回目录名),从而让监控子目录时记忆仍按仓库名归类。 - 多根目录的按根归属:构造器中还维护了
projectByRootMap——多根场景下每条事件会打上产生该事件的根目录所对应的 project,而不是统一用第一个根的项目;仅当显式配置了AGENTMEMORY_PROJECT时才对所有根统一覆盖。
五、预览内容与脱敏机制
5.1 预览规则
- 文本文件会读取前 4 KB(
MAX_PREVIEW_BYTES = 4096)作为data.content,使得后续检索可以通过子串匹配命中;更大的文件会置data.truncated: true。 - 二进制文件默认不读取,只产生一条不含内容的路径观测;设置
AGENTMEMORY_FS_WATCH_ALLOW_BINARY=1可覆盖此行为。 - 可读文本扩展名内置了一套白名单(见 watcher.mjs 的
TEXT_EXTENSIONS):涵盖.ts/.tsx/.js/.jsx/.mjs/.cjs、.py/.rb/.go/.rs/.java/.kt/.swift、.c/.cc/.cpp/.h/.hpp、.md/.mdx/.txt/.rst、.json/.yaml/.yml/.toml/.ini/.env、.html/.css/.scss/.vue/.svelte、.sh/.bash/.zsh/.fish、.sql/.graphql/.proto等;此外.env及其变体(.env.*)也被强制视为文本。 - 未知扩展名的文件只记录路径,不带内容。
content的拼装格式(formatContent)为:相对路径 (字节数[, truncated])\n\n<预览内容>;删除事件则简化为deleted: 相对路径。
5.2 敏感信息脱敏(源码级细节)
这是该连接器最有价值的防护设计,watcher.mjs 中有一整套redactSensitivePreview脱敏管线,且每条规则都有对应的测试覆盖(见 test/fs-watcher.test.ts):
- 敏感键值对:匹配
KEY=value/KEY: value(含引号与export前缀)形式的赋值,若键名(去除符号后小写)命中apikey/accesstoken/accesskey/authorization/bearer/clientsecret/password/passwd/privatekey/pwd/secret/token之一,则值替换为[REDACTED]。注意:.env中的OPENAI_API_KEY会被脱敏,而PUBLIC_FLAG这类非敏感键保持原样(测试断言PUBLIC_FLAG=enabled仍可见)。 - Bearer Token:对
Bearer <token>形式的明文令牌(至少 8 个可见字符)统一脱敏。 - PEM 私钥块:
-----BEGIN ... PRIVATE KEY-----与-----END ... PRIVATE KEY-----之间的全部内容折叠为[REDACTED],但保留 BEGIN/END 标记;同一行内内联的 PEM(如 JSON 单行值)也能被正确识别,服务账号 JSON 中的private_key即属此类场景。 - JWT:长度 >= 100 的三段式
eyJ...JWT 字符串整体替换为[REDACTED];而较短的、或非三段式 base64 形态的词语不会被误伤(测试用例专门验证了这一点)。
5.3 去抖(Debounce)
编辑器保存文件往往会在短时间内产生多次写事件。watcher 对每个路径做了500 ms(DEBOUNCE_MS)的去抖:schedule会先取消该路径未决的定时器再重新计时,因此"编辑器连续保存"最终合并为一条观测(测试debounces rapid writes to a single observation断言连续 4 次写入后命中观测数不超过 2)。
六、默认忽略规则与自定义扩展
文档明确列出的默认忽略清单如下,无需任何配置即可生效:
.git/、node_modules/、dist/、build/、.next/、.turbo/、coverage/、.DS_Store、*.log、*.lock
对应到 watcher.mjs 的DEFAULT_IGNORE,它们是编译好的正则数组,例如/(?:^|\/)node_modules(?:\/|$)/匹配路径中任意层级的node_modules目录,/\.log$/匹配所有.log后缀文件。isIgnored会在两个环节生效:事件回调中立即跳过(不入队),以及flush落库前的二次校验。
需要扩展时,通过AGENTMEMORY_FS_WATCH_IGNORE传入逗号分隔的正则表达式(作用于相对路径),例如:
export AGENTMEMORY_FS_WATCH_IGNORE='tmp/,^\.cache/,\.swp$'七、运行机制、容错与运维建议
7.1 底层机制
- 基于 Node 内置
fs.watch的{ recursive: true, persistent: true }(watcher.mjs 的start),macOS、Linux、Windows 10+ 原生可用,无任何原生依赖。 - 事件回调会把相对路径统一为
/分隔后再做忽略判断与入队,保证跨平台一致。 - 观察到的文件变化会先确认目标仍是文件(
statSync且isFile()),已被删除则走file_delete分支——这正是删除事件能被识别的方式。 - 对外发送使用全局
fetch提交到${AGENTMEMORY_URL}/agentmemory/observe,带 5 秒超时;失败只记录warn日志,不影响进程继续监控。
7.2 容错设计
- 单个根目录 attach 失败(权限、平台差异等)时,watcher 会记录错误并继续监控其余根目录。
- 对根目录会先做显式
statSync校验(存在性 + 是否为目录)。test/fs-watcher.test.ts 中有一条重要回归测试:在 Linux + Node 24+ 上,fs.watch对不存在路径不再同步抛错,若不自行校验,缺失目录会被静默当作"已监控";而现在的实现会直接抛错(could not watch any of the configured roots)。 - 若所有根目录都失败,进程抛错退出,并给出 Node 版本相关的升级提示(
Node >=19.1.0/ 建议 Node 20 LTS)。 stop()会关闭全部 watcher 句柄并清空未决定时器,保证优雅退出。
7.3 常驻与进程管理
watcher 进程必须保持运行才能持续捕获变化,文档明确建议用进程管理器托管:
Use a process manager(
launchd、systemd、pm2)to supervise it.
例如 systemd 服务的ExecStart指向agentmemory-fs-watcher并带上目标目录即可。由于 bin.mjs 已对SIGINT/SIGTERM注册了优雅关闭(调用watcher.stop()后退出),无论前台 Ctrl-C 还是进程管理器发信号,都能干净收尾。
八、测试验证与仓库对照
本连接器的行为在 test/fs-watcher.test.ts 中有系统性的集成测试覆盖(通过 mockfetch捕获请求断言),可作为理解其行为的权威参考:
| 测试场景 | 验证点 |
|---|---|
| 写入文件 | 发出post_tool_use观测,URL 为/agentmemory/observe,changeKind=file_change,content含文件内容 |
| 删除文件 | changeKind=file_delete |
| 无效根目录 | 抛could not watch any of the configured roots |
| 根目录是文件 | 拒绝监控 |
| 默认忽略 | node_modules/ignored.js不产生观测 |
| Bearer 认证 | 配置 secret 后请求头携带Authorization: Bearer shhh |
.env脱敏 | OPENAI_API_KEY=[REDACTED],PUBLIC_FLAG=enabled保留 |
| JSON 敏感键 | "api_key": [REDACTED],公开键保留 |
| 明文 Bearer | Authorization: Bearer [REDACTED] |
| PEM 多行/内联私钥 | 内容折叠为[REDACTED],保留 BEGIN/END 标记 |
| JWT 脱敏 | 长 JWT 被替换,短 base64 词不受影响 |
| 去抖 | 连续写入合并为少量观测 |
九、典型应用场景小结
- 笔记与文档记忆化:把
~/notes纳入监控,随手写的想法、调研结论会自动进入 agentmemory,后续会话可通过检索召回。 - 配置与草稿追踪:监控
.env、.yaml、.md等变更,让 Agent 知道项目配置与文档"何时、在哪、改了什么"。 - 代码仓库的增量观察:监控仓库根目录,配合
AGENTMEMORY_FS_WATCH_IGNORE排除构建产物,为 Agent 补充基于文件系统信号的工作上下文。
最后再强调两点边界:一是该连接器单向——只写入观测、从不读取记忆库,想给 Agent 注入记忆需依赖 agentmemory 的 recall/检索能力;二是它把文件系统信号作为post_tool_use类观测入库,与钩子事件同构,因此能无缝复用压缩、索引、会话归并等全部下游能力。
【免费下载链接】agentmemory#1 Persistent memory for AI coding agents based on real-world benchmarks项目地址: https://gitcode.com/GitHub_Trending/age/agentmemory
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考