历史不是一条线,而是一棵树;你随时可以回到任何一个分岔口重新出发。
设计思想
大多数 coding agent 的历史是线性的:压缩有损且不可逆,走错了只能重开。Pi 把会话设计成单文件内的树结构——每次交互都是树上的节点,你可以回到任意历史节点原地分叉,探索不同方向而互不覆盖。配合自动压缩(compaction),长会话不炸上下文,且原始历史永远完整保留。
原理
存储格式
- 会话保存为 JSONL 文件,存于
~/.pi/agent/sessions/,按工作目录组织,自动保存。 - 每条记录有
id和parentId,整个会话本质是存在单文件里的一棵树(格式详见docs/session-format.md)。
三种"回到过去"的方式
| 操作 | 行为 | 文件 |
|---|---|---|
/tree |
会话树内原地导航:选中任意历史点继续聊、在分支间切换 | 不新建文件,全部历史保留 |
/fork |
从活跃分支上的某条历史 user message 开新会话文件,复制到该点为止的路径,并把该提示词放回编辑器供修改 | 新文件 |
/clone |
把当前活跃分支的当前位置完整复制成新会话文件,编辑器为空 | 新文件 |
CLI 侧:pi --fork <path|id> 可直接从既有会话或部分 UUID 分叉出新会话。
/tree 的操作
- 直接输入文字即搜索;Ctrl+←/→(或 Alt+←/→)在分支间跳转,←/→ 翻页
- Ctrl+O 切换过滤模式:default → no-tools → user-only → labeled-only → all
- Ctrl+X 复制选中消息
- Shift+L 给节点打标签做书签,Shift+T 切换标签时间戳显示
Compaction(上下文压缩)
- 手动:
/compact或/compact <自定义摘要指令>。 - 自动(默认开启):上下文溢出时触发(恢复并重试);接近上限时主动预防性压缩。可在
/settings或settings.json配置。 - 压缩有损(旧消息被摘要替代),但完整历史仍在 JSONL 文件里——
/tree随时可回看;压缩行为可通过 extensions 自定义(内部机制见docs/compaction.md)。
用法
会话生命周期
pi -c # 继续最近一次会话
pi -r # 浏览历史会话并选择
pi --no-session # 一次性模式,不保存
pi --name "my task" # 启动时命名
pi --session <path|id> # 使用指定会话(部分 UUID 亦可)
pi --fork <path|id> # 从既有会话分叉新会话
交互内用 /session 查看当前会话 ID,方便之后 --session <id> / --fork <id> 复用。
典型工作流
- 方案 A/B 对比:聊到关键决策点,
/tree回到分岔口,先走方案 A;不满意再回同一节点走方案 B,两个分支互不干扰。 - 危险操作前存档:执行大规模重构前,用
/clone复制当前分支;翻车后直接回原会话继续。 - 重写提示词:
/fork选中某条历史提示词,新会话中修改后重发,比较两次结果。 - 长任务防炸上下文:放着让自动 compaction 处理;发现质量下降时
/tree回到压缩前的节点,换个问法继续。 - 书签导航:给关键节点 Shift+L 打标签,之后在 labeled-only 过滤模式下快速定位。
- 分享与归档:
/export导出 HTML/JSONL,/import恢复,/share上传为私有 GitHub gist。