跳转到内容

让它拥有记忆

octo 会跨会话记住你的偏好、项目约定和过去的纠正——存在本地的 ~/.octo/memories/<repo-slug>/ 下面,绝不上云。

没有专门的 remember/forget 工具,也没有代码驱动的整理步骤。agent 管理记忆的方式和管理任何文件 一样——用 read_file / write_file / edit_file——只是遵循一个约定:

  • MEMORY.md —— 索引。每次会话都会被注入系统提示(最多前 200 行 / 25KB,以先到者为准—— 和 Claude Code 自己的注入上限一致)。
  • <topic>.md —— agent 按需创建和读取的详情文件,从索引里链接过去。

记忆目录在权限引擎里自动带了一条 write_file/edit_fileallow 规则,所以 agent 管理它时每次写入都不会弹确认——除了这个目录,别的地方还是照常受门控。

Terminal window
octo memory list # 列出项目自己的和继承来的记忆文件
octo memory path # 打印项目的和继承的记忆目录
octo --no-memory # 单次会话关闭记忆注入

记忆按仓库划分作用域,用 git 的公共目录而不是每个 worktree 各自的顶层目录作为 key—— 所以同一个仓库的所有 worktree 共享一份记忆,而不是各自从空白开始。在非 git 目录下工作时, 记忆直接以该目录为作用域。

还有一份主目录级别的索引(~/.octo/memories/<home-slug>/MEMORY.md)会被继承进每一个项目, 在项目自己的索引之前注入——适合放不属于某个具体仓库的东西,比如你喜欢的工作方式; 具体到某个项目的事实应该放进那个项目自己的记忆里。

除了普通笔记,还有两种规则区块

Section titled “除了普通笔记,还有两种规则区块”

MEMORY.md 支持两个可选的区块,行为跟普通的索引条目不一样:

  • 必须遵守的规则——每一轮都会重新带上,适合那种绝对不能漏掉的事。
  • 触发式规则——每条规则配一组触发关键词;一个会话里,只有你输入的内容第一次命中某个 关键词时才会被提醒一次(英文关键词按单词边界匹配,所以 deploy 不会被 deployment 误触发; 中文关键词按子串匹配)。

这两种都是作为附加在你这条消息上的提醒发出去的,而不是编辑进系统提示本身,所以被缓存的 prompt 前缀不会变。一份两种区块都没有的普通索引,除了索引本身不会有额外开销。

一次 terminal 调用,如果命令匹配 gh pr creategh pr merge 并且执行成功,octo 会在那次 工具结果后面追加一条一次性提醒,建议模型想一想刚落地的这次工作里有没有什么值得记下来的东西—— 一个已经定下来的决定、一个被否掉的方案、一条以后的会话必须遵守的约束。这个提醒每个用户轮次最多 触发一次,所以连续跑一串 git 命令不会被反复打扰;用 octo hooks list 能看到它和其他配置的 hook 列在一起。

  • Web 和 IM 每一轮都会重新组装系统提示,所以不管是这个会话还是别的会话写进 MEMORY.md 的内容,从下一轮开始就能看到。IM 在 /bind//unbind 时会专门丢弃并重建这部分状态, 所以一个被重新绑定的聊天会拿到这个会话当前记忆里的最新内容。这一点在这两个场景下很重要, 因为一个 octo serve 进程、以及它撑着的会话,生命周期通常比任何一个具体任务都长——要跨越 重启,IM 聊天还可能中途被重新绑定到完全不同的底层会话上。
  • CLI 只组装一次,在交互式会话启动的时候,之后整个进程都复用同一份系统提示。这是故意这么 设计的,不是疏漏:一次 CLI 会话通常就是围绕一个具体任务展开的一段连续对话,为这个任务打开、 做完就关掉——你在会话过程中告诉 agent 的任何事,本来就已经活在这次对话自己的历史里了, agent 不需要重新读一遍 MEMORY.md 才知道。这次会话里 agent 写进记忆的东西, 要等你在这个仓库下下一次octo 才会生效——而这恰恰是一份纯索引文件该发挥作用的时候: 服务一个没有经历过“这件事是怎么学到的”那段对话的新会话。

实际使用中,agent 会用它来记录代码本身恢复不出来的信息:谁在做什么、为什么这么做,你明确表达过的 稳定偏好(“这个仓库一律用 worktree”),以及你纠正过不止一次的地方。它不会重复 git log 或代码里已经写明的内容。

下一步:记忆和hooks搭配很合适——除了内置的保存提醒,你还可以挂自己的副作用。