会话分叉(打分支)

SKILLAI 工具
AI 工具 未标注权限 许可证不明确
安装这个技能

把一个会话的工作现场(上下文、已确认结论、已做步骤、工具结果)整体复制成独立分支,供用户从任意节点换方向重走、并行试几条路、或保住原线不被带偏;分叉对象是工作现场而非聊天记录,对话 / 任务 / 方案 / 代码 / 写作 / 调研均可。当你说"打分支""会话分叉""把这个任务复制成新分支""以某条回复为界新建对话""并行试几条路""把对话截断复制",或提到 fork this session / branch this task 时使用。底层为 fork-core 通用引擎,跨产品可用。

一句话选型结论

按资料字段整理

会话分叉(打分支)是AI 工具类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类AI 工具 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_5b43da63/session-fork
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

AI 工具
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_5b43da63仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791733715
正文体量44.6 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
组合多个 AI 能力

把写作、检索、总结串成一条流程。

搭工作流

把固定流程做成可重复调用的步骤。

做提示词与评测

整理提示词并对比输出效果。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在AI 工具场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
会话分叉(打分支)当前 未标注权限 未标注 未标注 未标注 有
执行计划 只读 GitHub 仓库 151.5 万 Codex、Claude、Cursor 有
Playwright MCP 测试 浏览器控制 ClawHub 市场 136.5 万 OpenClaw 有
完成前的验证 未标注权限 GitHub 仓库 131.9 万 Codex、Claude、Cursor 有
子 Agent 驱动开发 只读 GitHub 仓库 131.2 万 Codex、Claude、Cursor 有
前端设计 执行命令 GitHub 仓库 125.6 万 Codex、Claude、Cursor 有

SKILL.md 全文

44.6 KB
模型实际读到的说明书原文,来自技能仓库

<h1><img src="https://raw.githubusercontent.com/yamingmou/session-fork-core/main/logo.png" width="40" height="40" alt="Fork Logo" style="vertical-align: middle;"> Session Fork(会话分叉 · 打分支)</h1>

语言 / Language — 本技能面向中文用户编写。英文总览见 README.en.md;中文总览见 README.md。
Written in Chinese. For an English overview see the linked README.en.md.

把一个会话的工作现场整体复制成独立分支:取源会话 transcript 的前 1..截断点行 → 递归改写其中的会话 id → 写入新会话文件 → 在会话索引与谱系索引注册。原会话零改动。

  • 分叉对象 = 工作现场(上下文 + 已确认结论 + 已做步骤 + 工具结果),不是"聊天记录"。因此对话、任务、方案、代码、写作、调研都可以分叉——用户说"把这个任务分个支""同一个任务并行试几条路"同样属于本技能职责。
  • 它替你省下的(一句话):不用重讲一遍背景、不用重跑一遍前面的步骤,原线也不会被带偏。
  • 默认行为:截断点 = 上一轮输出的结束;用户一旦给出断点信息,必须改用 --match / --line / --request-id(见「工作流程 · Step 2」)。

⚠️ 分叉边界:上下文会回去,产物不一定(必读)

分叉自由,产物不自由。 分叉复制的是会话的工作现场(transcript 的 1..截断点 前缀,含工具结果的记录文本,不是把工具重跑一遍),外加会话索引 / 谱系登记——它不复制、也不回退工作区文件,更不撤销任何已经发生的外部动作。

所以分支落地后可能出现这种错位:分支里的上下文停在切点,而磁盘上的产物已经是"现在"的样子(最终态)。产物能不能跟着回到那一刻,取决于它自己有没有版本记录:

产物形态 能否回到那一刻 怎么做
在 git 仓库里(已提交) ✅ 能 分支侧 git switch -c &lt;名&gt; &lt;sha&gt; 或 git worktree add &lt;目录&gt; &lt;sha&gt;,把工作区切到与切点对应的提交,上下文与产物重新对齐
有版本记录的载体(云文档版本历史、系统快照 / Time Machine、备份、日志) ✅ 通常能 手动回溯到对应时间点
无任何版本记录的本地文件 ❌ 只有最终态 分叉给到的是「旧上下文 + 新文件」;需要旧版本只能事先备份
已发生的外部副作用(发出的消息 / 邮件、已发布页面、已 push 的提交、API 写入、装好的依赖) ❌ 不可撤销 分叉不能取消已发生的事,需在外部自行补救

打分支时的约定(每次都要执行):

  1. 每次打分支都用一句话交代边界(一句话即可,不要长篇):分叉的是会话上下文;工作区文件不会跟着回退,除非它在 git 等有版本记录的载体里。不得任何措辞暗示分叉能"时光倒流";没把握时宁可说得保守。
  2. 动手前看一眼工作目录(一条命令的事):
    - git rev-parse --show-toplevel 成功 → 是仓库:报告当前 HEAD(短 sha + 提交主题)并告知"分支侧可用 git worktree 对齐到切点";若 git status --porcelain 非空,明确提示这些未提交改动不会被分叉带走;
    - 失败/非仓库 → 明确告知该目录下的文件只有当前最终态,分叉无法回退它们。
  3. 用户真实意图是"回到旧产物"(而不只是"从旧上下文继续")时,不要只打一个会话分支了事——先建议(用户同意后执行)git 检查点(commit / stash)或文件备份,再分叉。
  4. 分支是快照:分叉点之后原会话新增的消息不会进分支——这是设计行为,向用户说明时不要误称为"丢数据"。

功能特性

  • 零配置默认模式:用户只说"打分支"即可,截断点自动 = 上一轮对话的输出结束,无需提供任何拆分点文本;
  • 精确指定模式:按用户引用的某条回复特征文本(--match)、行号(--line)或请求ID(--request-id)截断;
  • 存储级复制:新 jsonl 文件 + 会话索引新行记录,不是"链接/指向"——原会话后续写入不会污染分支;
  • 谱系可追溯:parent_id + at_seq(快照点)记录分支从哪派生,--list --tree 展示分叉树;
  • 快照点可回:分支可再派生(从分支再 fork = 新投影继续演进);
  • 内置安全:执行前自动备份(仅源 jsonl),递归 id 替换(rawContent/rawResponse 等原始内容黑名单不碰),自带完整性校验;
  • 可预览:--dry-run 先确认截断点定位,再正式执行。

实现结构(通用引擎)

脚本基于 fork-core 通用引擎 + 产品 adapter 设计(实现细节,不影响使用):

session-fork/
├── SKILL.md                    # 技能定义
├── scripts/
│   └── create_branch.py        # 唯一入口(调用它即可)
├── fork_core/                  # 通用引擎(与产品无关)
│   ├── engine.py               # 截断点定位/截取/备份/验证/汇报
│   ├── models.py               # SessionMeta / ForkResult 契约
│   ├── cli.py                  # 命令行解析与输出
│   ├── adapters.py             # adapter 注册表(工厂)
│   ├── adapter_base.py         # TranscriptionAdapter 接口
│   ├── adapter_workbuddy.py         # WorkBuddy(默认)
│   ├── adapter_claude_code.py       # Claude Code
│   ├── adapter_codex.py             # Codex
│   ├── adapter_hermes.py            # Hermes
│   ├── adapter_pi.py                # pi
│   ├── adapter_openclaw.py          # OpenClaw ≤2026.6.x(JSONL 后端)
│   └── adapter_openclaw_sqlite.py   # OpenClaw ≥2026.9.x(SQLite 后端)
└── tests/                      # 自测(仅源码仓库有;安装包里不含)
  • 核心逻辑(默认/--match/--line/--request-id 定位、结构化 id 替换、完整性校验)全部在引擎层,与存储格式无关;
  • 每个产品只实现一个 adapter(接口组:定位/消息判定/读写/注册/文案/体检),格式差异被完全隔离;
  • 未来新增产品支持 = 新增一个 adapter 文件,引擎零改动(旧 adapter 亦无需改动,走基类默认实现)。

触发条件

用户明确要求创建/执行"打分支 / 会话分叉 / 对话分支 / 任务分叉 / 复制对话成新分支 / 把任务复制成新分支 / 同一个任务并行试几条路 / 分支会话 / split session / fork session / branch this task / 新建分支 / 从这里分叉"。

只需记住这一条(其余交给工具):
> 没贴 conversation ID → 打当前对话的分支;贴了 conversation ID("复制请求 ID"的 JSON)→ 打那个对话的分支。

  • 默认:用户只说"打分支"或"打分支,命名『X』"(没贴任何 ID)——源会话 = 当前对话,截断点 = 上一轮对话输出结束。
  • 从某条回复打:用户贴了复制的 ID(可能来自本对话或任何其他对话),或说了"从『XXX』那条回复打"——按用户给的信息定位源会话和断点。
  • 命令映射(按用户给的信息直接判断,不把选择抛给用户):

> 怎么选 flag(一句话口诀):
> 用户贴了 ID → 用 --request-id(和 --session 一起);
> 用户只是在说文字(哪怕他说的是"那条回复")→ 用 --match &quot;&lt;那段文字&gt;&quot;。
> ⚠️ --request-id 只能装 ID,不能装文字。

> ⚠️ 动手前先做这一件事:下面的命令统一写成 WorkBuddy 形式(python3 &quot;${SK}/scripts/create_branch.py&quot; …)。若你不在 WorkBuddy 里,先读「Step 0 · 先判定你在哪个产品里」,把前缀换成 fork(pip 渠道)或你所在产品的技能目录路径,并补上 --adapter &lt;你的产品&gt;——其余参数完全相同。
>
> 入口路径先用命令取,不要写死(技能目录可能带市场后缀,如 session-fork__skillhub/;写死会指向不存在的路径,等于跑到别的目录的副本上):
> bash &gt; SK=$(ls -d ~/.workbuddy/skills/session-fork*/ 2&gt;/dev/null | head -1) &gt; SK=&quot;${SK%/}&quot; # 去掉尾斜杠:下面统一用 ${SK}/scripts/…,两平台拼法都成立 &gt; [ -n &quot;$SK&quot; ] &amp;&amp; [ -f &quot;${SK}/scripts/create_branch.py&quot; ] || echo &quot;⚠️ 找不到技能入口,先确认技能装在哪&quot; &gt; echo &quot;入口: ${SK}/scripts/create_branch.py&quot; &gt;

用户给了什么 用什么命令
什么都没贴(当前对话) python3 &quot;${SK}/scripts/create_branch.py&quot; --session current(默认截断点)
@引用了一段内容(long-text quote)说打分支 从引用 JSON 提取 id(格式 &lt;sessionId&gt;-&lt;requestId&gt;,如 &quot;ec48e1ae-…-e683a22a…&quot;)→ python3 &quot;${SK}/scripts/create_branch.py&quot; --session &lt;sessionId&gt; --request-id &lt;requestId&gt;
贴完整 JSON(conversationId + conversationRequestId) python3 &quot;${SK}/scripts/create_branch.py&quot; --session &lt;conversationId&gt; --request-id &lt;conversationRequestId&gt;(conversationId = 会话 ID,直接定位)
只贴了 conversationRequestId / traceId python3 &quot;${SK}/scripts/create_branch.py&quot; --request-id &lt;id&gt;(自动反查该 ID 所属会话,跨工作区)
说了文本/行号 python3 &quot;${SK}/scripts/create_branch.py&quot; --session current --match &quot;XXX&quot; 或 --line N
只是在聊天里"提到"某段文字(没有复制任何 ID) 同上:--match &quot;&lt;那段文字&gt;&quot; ⚠️ 不要把它当 --session,也不要自己造一个 --request-id

> ⚠️ 关键规则:用户给了任何形式的引用(@long-text 引用 / 复制的请求 ID JSON / 纯 requestId / 指向别处的会话内容)→ 源会话 = 引用所指的那个会话,不要默认用 --session current 打当前对话。识别引用 ID:JSON 里找 conversationId,或 @引用内容里找 &quot;id&quot;: &quot;&lt;sessionId&gt;-&lt;requestId&gt;&quot; 双段拼接格式。拿不准时先 --dry-run 展示将要打源会话名 + 断点,问用户确认再正式执行——不要反复试错创建分支。

> ⚠️ 三个最常见的错误:
> ① 把"用户口头提到的文字"当成会话 ID:用户说"从『teal』那条回复打分支"→ 用 --match &quot;teal&quot;,不是 --session teal;
> ② 自己造 --request-id:用户没贴任何 ID 时,本来就没有 request-id 可用;"某段文字"要放进 --match,不是 --request-id;
> ③ 命令入口写错产品:在 WorkBuddy 里不要输出裸 fork …(要写完整路径);在 pip 渠道不要输出 ~/.workbuddy/skills/…(那台机器上没有这个路径)。入口按「Step 0」定。

命令示例(左边是用户的话,右边是完整命令;前缀按 Step 0 替换):

用户这么说 对应命令
打分支,命名『论文讨论』 python3 &quot;${SK}/scripts/create_branch.py&quot; --session current --name &quot;论文讨论&quot;
从『teal』那条回复开始打分支 python3 &quot;${SK}/scripts/create_branch.py&quot; --session current --match &quot;teal&quot;
打分支,从第 6 行截断 python3 &quot;${SK}/scripts/create_branch.py&quot; --session current --line 6
(贴了 conversationId + conversationRequestId) python3 &quot;${SK}/scripts/create_branch.py&quot; --session &quot;&lt;conversationId&gt;&quot; --request-id &quot;&lt;conversationRequestId&gt;&quot;

排除(不触发执行,只回答问题)

以下场景用户只是咨询/了解,不应执行分叉操作:

  • "什么是分叉 / 分叉有什么用 / 怎么用分叉功能" → 解释功能,不执行
  • "帮我看看当前有没有分支 / 列出分支" → 用 --list 查询,不创建
  • "这个对话太长了" / "对话需要整理" → 不自动推断要分叉,询问用户意图
  • "能不能回到之前的某个点" → 解释可以用分叉实现,询问是否执行
  • 用户在讨论分叉的概念/原理/对比 → 只回答,不执行

工作流程

Step 0 — 先判定"你在哪个产品里"(决定命令入口,不要写死)

本技能在 6 个产品可用,但命令入口不一样。动手前先定下来你是哪一种,再照后面的示例写命令:

你在哪 命令入口
WorkBuddy(技能市场安装) python3 &quot;${SK}/scripts/create_branch.py&quot; &lt;参数&gt;
其他产品的技能目录(如从 ClawHub 装进该产品的 skills 目录) python3 &lt;该技能目录&gt;/scripts/create_branch.py &lt;参数&gt;
pip 安装的命令行(Claude Code / Codex / Hermes / pi / OpenClaw 在终端里的路径) fork &lt;参数&gt;

判定顺序(30 秒内定下来,不要猜、不要两套都试):

  1. fork --version 能跑通 → 用 fork;
  2. 否则 ls -d ~/.workbuddy/skills/session-fork*/ 2&gt;/dev/null | head -1 有命中、且该目录下 scripts/create_branch.py 存在 → 用 WorkBuddy 形式(真入口 = ${SK}/scripts/create_branch.py,见上文取法;⚠️ 目录名可能带市场后缀 __skillhub,不要写死成 session-fork/);
  3. 否则看你所在产品的 skills 目录里有没有本技能;
  4. 都不确定 → 问用户一句:"你是在 WorkBuddy 里用,还是本机命令行(pip 装的)?"

adapter 对应:WorkBuddy 是默认(不写 --adapter);其余五种必须写 —— --adapter claude-code / codex / hermes / pi / openclaw。

Step 0.5 — 平台差异(决定「命令怎么写」)

先判平台:uname 能跑 → macOS / Linux / WSL(POSIX,本文其余命令直接可用,无需替换);报"不是内部或外部命令" → 你在原生 Windows,按下表换写法。

用途 POSIX(macOS / Linux / WSL) 原生 Windows(PowerShell / CMD)
跑入口 python3 &quot;&lt;技能目录&gt;/scripts/create_branch.py&quot; py -3 &quot;&lt;技能目录&gt;\scripts\create_branch.py&quot;
取技能目录 SK=$(ls -d ~/.workbuddy/skills/session-fork*/ \| head -1) $SK=(Get-ChildItem &quot;$env:USERPROFILE\.workbuddy\skills&quot; -Dir -Filter &quot;session-fork*&quot;)[0].FullName
家目录 ~ / $HOME $env:USERPROFILE(PS)· %USERPROFILE%(CMD)
设环境变量 export CODEX_HOME=/x PS $env:CODEX_HOME=&quot;C:\x&quot; · CMD set CODEX_HOME=C:\x
查文件内容 grep -n &quot;词&quot; f.jsonl PS Select-String -Path f.jsonl -Pattern &quot;词&quot; · CMD findstr /n &quot;词&quot; f.jsonl
设文件只读 chmod 444 f attrib +R f

Windows 上的四个坑(均有官方依据):

  1. python3 不保证存在 —— Python 官方把它定位为"捕获 POSIX 习惯误用"的兼容命令,不推荐使用 ⇒ 优先 py -3,其次 python。
  2. python 可能被 Microsoft Store 应用别名拦截(敲了没反应、或弹出商店)⇒ 同样优先 py -3。
  3. PowerShell 执行策略可能拦住全局 npm 装的 CLI(报 npm.ps1 cannot be loaded because running scripts is disabled)。修法是用户自行执行 Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser —— 本技能不会替你改系统设置。
  4. WSL 与原生 Windows 的会话库互不共享(/home/u/.codex ↔ C:\Users\u\.codex)—— 你在哪边跑,就用哪边的库。

> 目录位置两平台同构(~/.claude ↔ %USERPROFILE%\.claude;~/.codex ↔ %USERPROFILE%\.codex)⇒ --adapter 与其余参数完全一致,平台差异只在"命令怎么写"。
> 输出编码:本技能的 CLI 会自动把 stdout 固定为 UTF-8(仅当当前编码容纳不了中文/emoji 时),所以 Windows 上中文与 emoji 都能正常输出,不需要你额外设环境变量。若你的控制台仍显示乱码,那是控制台自身的代码页问题——chcp 65001 切到 UTF-8 即可。

分支怎么出现(按产品,与工具输出一致;不要凭记忆)

脚本创建后会在输出里给一行 ACTION : 分支已创建——…,那句话是按产品适配的。照它转述给用户;下表是同一份内容的备查(有反直觉项,不要凭印象):

产品 怎么看到分支
WorkBuddy 左侧会话列表非实时刷新 → 重启客户端(macOS:⌘Q 重开 或 open -a WorkBuddy;Windows:托盘图标右键 → 退出后重开)
Claude Code 在终端重跑 claude,用 /resume 选择该会话(无需重启其他程序)
Codex ① 可直接续跑:codex exec resume &lt;新 id&gt; &quot;…&quot;;② 桌面版会话列表也要重启才可见(macOS ⌘Q / Windows 托盘退出);③ 想被 codex fork --last 选中,用 codex exec resume 跑一轮
Hermes 无需重启、无需修复命令:hermes sessions list 即可看到;hermes chat --resume &lt;分支 id&gt; 续跑
pi 无需重启:会话选择器(/resume)或 /tree 刷新即可
OpenClaw openclaw sessions --json 立即可列出;若 Gateway 正在运行,重启一次以加载

只对 WorkBuddy 成立的四件事(不要套到其他产品上):① 界面上的"复制请求 ID"按钮;② 「重启后左侧才出现」这个具体表现;③ --fix(仅 workbuddy,其他 adapter 会直接报错;⚠️ 这是本技能的参数,与 OpenClaw 官方的 openclaw doctor --fix 不是一回事);④ 项目日志写 .workbuddy/memory/。

Step 1 — 确认源会话

按上表映射,先看用户贴了什么:
- 什么都没贴 → --session current(当前对话,脚本自己判定,含义见下);
- 贴了完整 JSON(UI 复制请求 ID 的原始格式)→ 取 conversationId 作为源会话(WorkBuddy / Claude Code 这类按 id 命名的存储里,conversationId 就是会话文件名,直接定位、不扫描;其他产品交给引擎按 id 定位);conversationRequestId 作为断点;
- 贴了纯 requestId/traceId(无 conversationId)→ 用 --request-id 自动反查该 ID 属于哪个会话(跨工作区兜底,按 mtime 新→旧搜)。
- --session current 的含义:你正在其中的这个对话。唯一判据 = 执行环境里的会话标识(CLAUDE_SESSION_ID / CODEBUDDY_SESSION_ID / BAGGAGE);其他产品由各自 adapter 定义。不需要自己去翻数据库找"当前会话"——交给 --session current。
- ⚠️ current 不猜:拿不到会话标识时脚本硬失败,不会替你选一个"最近活跃的会话"。那不是你正在其中的对话,打出来会是另一个对话的分支。确实想从"最近活跃的会话"打时,用显式的 --session latest-working(语义即其名)。
- 会话存在哪,不用你记;也❌不要把 WorkBuddy 的路径套到其他产品上:

  • WorkBuddy:~/.workbuddy/projects/&lt;workspace-slug&gt;/&lt;session-id&gt;.jsonl(slug = cwd 去 / 后 / 换 -);元数据在 ~/.workbuddy/workbuddy.db 的 sessions 表。
  • 其他产品:由 adapter 自动探测——Claude Code / Codex / Hermes / pi / OpenClaw 的目录与格式各不相同(JSONL 与 SQLite 都有)。需要覆盖位置时用环境变量(如 CODEX_HOME / HERMES_HOME),不要手改会话文件。

Step 2 — 确认截断点(默认规则优先)

⚠️ 最高优先级规则:用户说了断点 → 必须用 --match 或 --line,不要用默认模式。

默认模式只在用户完全没提断点(只说"打分支")时才用。一旦用户描述了任何断点信息("截断到 XXX"、"从 XXX 之前分叉"、"到 XXX 产生处"),就必须用指定模式。

三种场景的处理方式:

用户说的 用什么 怎么做
"打分支"(没提断点) 默认模式 脚本自动定位最后一条 assistant 回复
"截断到这条回复" + 提供了请求ID --request-id 最精确,直接匹配 conversationRequestId
"截断到 XXX" --match &quot;XXX&quot; 取最后一条包含 XXX 的 assistant 回复
"截断到 XXX 产生处" --line N 先用 grep/Read 在源会话 jsonl 中搜索 XXX 所在行号,再用 --line

⚠️ 最精确的截断点 = 请求ID(--request-id)——但"怎么拿到它"只有 WorkBuddy 有现成按钮:

  • WorkBuddy:① 在 UI 中点击目标断点处的助手回复;② 点"复制请求ID",得到 JSON 如 {&quot;traceId&quot;:&quot;...&quot;,&quot;conversationRequestId&quot;:&quot;abc123&quot;,&quot;conversationId&quot;:&quot;...&quot;};③ 用 --request-id abc123 截断——唯一标识一条回复,不会误匹配。

⚠️ 关键:当用户口头描述断点但没给精确文本时(如"截断到项目思维规则模板产生处"),必须先在源会话 jsonl 中搜索确认行号,然后用 --line,不要忽略断点用默认模式。

断点定位步骤(指定模式):
1. 在源会话 jsonl 中搜索用户描述的关键词(grep -n &quot;关键词&quot; &lt;session-id&gt;.jsonl);
2. 确认匹配行是 assistant 消息且有 output_text(必须是完整回复,下一行是 user 消息或 EOF);
3. 用 --line N 或 --match &quot;精确文本&quot; 截断;
4. 跑 --dry-run 验证定位正确后,再正式执行。

默认模式规则(仅当用户完全没提断点时):
- 会话内打分支(你自己就是执行者,脚本跑在被 fork 的那个会话里):
截断点 = 上一轮对话的输出结束(用户最后一条 user 消息之前的最后一条完整 assistant 回复)。
本轮"打分支"这条指令与你此刻的叙述都不进分支。
- 从外部打分支(人在终端执行、或显式指定另一个会话):截断点 = 整份复制到文件末尾最后一条完整 assistant 回复(此时没有"本轮"要排除)。
- 两种语义由脚本按"执行环境里有没有本次会话的标识"自动判定,不需要你指定;
--dry-run 会打印走了哪一种(in-session / whole)以及锚在哪一行、锚点原文是什么——照它核一遍再正式执行。
- 要覆盖判定结果,只在会话内才需要:加 --whole 强制整份复制。

Step 3 — 执行创建(用脚本,不要手写)

打分支的固定顺序(脚本已内置,不要绕过或手写等价流程):

  1. 写入 .tmp 文件(零外部可见副作用)
  2. 立即自检(校验磁盘上的字节,不是内存数据)
  3. 自检通过才 os.replace 到正式路径(原子落位)
  4. 最后登记 db 与谱系

自检失败 = 什么都没发生(只留可忽略的 .tmp);登记失败 = 干净回退(文件回滚 + 痕迹清除)。
不要「先落 db 再验证」——那会让坏分支出现在侧边栏。
dry-run 也走完整校验(会真写 .tmp + 自检,只是不落位/不登记)——Verify: OK 才是真 OK。

执行方式:只用这一条命令(不需要 pip、不依赖 cwd,整行复制即可用):

  • WorkBuddy:python3 &quot;${SK}/scripts/create_branch.py&quot; &lt;参数&gt;
  • 其他产品的技能目录:python3 &lt;该技能目录&gt;/scripts/create_branch.py &lt;参数&gt;
  • pip 命令行:fork &lt;参数&gt;

> ⚠️ 两条不要做:① 不要把两套入口混用(在 WorkBuddy 里不要用裸 fork;在 pip 渠道不要写 ~/.workbuddy/skills/...——那台机器上没有);② 不要执行 fork_core/cli.py(唯一入口是 scripts/create_branch.py)。
> 下面示例统一写 WorkBuddy 形式,按 Step 0 换成你的入口(参数完全相同)。

# 场景 1:当前对话打分支(用户没贴任何 ID)
python3 &quot;${SK}/scripts/create_branch.py&quot; --session current --name &quot;&lt;分支名&gt;&quot;                 # 默认截断到上一轮输出结束
python3 &quot;${SK}/scripts/create_branch.py&quot; --session current --match &quot;&lt;拆分点特征文本&gt;&quot;          # 从当前对话某条回复打

# 场景 2:从贴的 conversation ID 打(用户贴了&quot;复制请求 ID&quot;,可能来自任何对话/工作区)
python3 &quot;${SK}/scripts/create_branch.py&quot; --session &quot;&lt;conversationId&gt;&quot; --request-id &quot;&lt;conversationRequestId&gt;&quot; --name &quot;&lt;分支名&gt;&quot;
#   ↑ conversationId 即 UI 复制 JSON 里的 conversationId(= 源会话 ID),直接定位
# 只拿到 requestId/traceId 时:自动反查所属会话(无需 --session)
python3 &quot;${SK}/scripts/create_branch.py&quot; --request-id &quot;&lt;conversationRequestId&gt;&quot; --name &quot;&lt;分支名&gt;&quot;

# 运维类
python3 &quot;${SK}/scripts/create_branch.py&quot; --list                                        # 查询分支
python3 &quot;${SK}/scripts/create_branch.py&quot; --fix &lt;分支会话ID&gt;                              # 修复被追加消息的分支(仅 workbuddy)
python3 &quot;${SK}/scripts/create_branch.py&quot; --verify                                      # 本机会话库自检(环境变化或换机器后建议跑一次),别名 --doctor
python3 &quot;${SK}/scripts/create_branch.py&quot; --session current --adapter pi                # pi
python3 &quot;${SK}/scripts/create_branch.py&quot; --session current --adapter claude-code       # Claude Code
python3 &quot;${SK}/scripts/create_branch.py&quot; --session current --adapter codex             # Codex
python3 &quot;${SK}/scripts/create_branch.py&quot; --session current --adapter hermes            # Hermes
python3 &quot;${SK}/scripts/create_branch.py&quot; --session current --adapter openclaw          # OpenClaw(≤2026.6.x / ≥2026.9.x 自动识别后端)
# OpenClaw 后端也可强制:FORK_OPENCLAW_BACKEND=jsonl|sqlite(默认 auto)

执行规范:
- 先交代产物边界 + 看一眼工作目录的 git 状态(见「分叉边界 · 打分支时的约定」第 1/2 条)——这一步在创建之前做,不要等到用户发现产物没跟着回退才解释;
- ⚠️ 回读 Source 行(必做):脚本输出的第一行是
Source : &lt;会话id&gt; 「&lt;会话名&gt;」
先确认这个源会话就是你(和用户)所在的那个对话。父 id 对不上时肉眼看不出来,名字能一眼看出来。不一致 → 立即停手,把"你在的对话 / 实际被当成源会话的对话"两个名字摆给用户,问清要哪条;不要继续,更不要交付一个"来历正确但对话不对"的分支;
- 先 --dry-run 确认截断点,再正式执行(推荐,防打错位置);
- python3 &quot;${SK}/scripts/create_branch.py&quot; --verify 自检:环境变化或换机器后建议跑一次;打分支前也可以先跑。输出分三档:
- ❌ 失败 = 要修(前缀内残留 / 结构性 sessionId 残留等):以非 0 退出(表示确有需要处理的问题);
- ⚠️ 需复核 = 不用修,看一眼即可:典型情形是你在分支里记录了血缘("我的父会话是谁"),
于是 fork 之后追加的内容里出现了父会话 id。它不会让体检失败、不影响退出码。
想彻底消解就重打一次该分支——新分支会带上"前缀指纹"(prefix_fp),此后体检能证明
"边界之内仍是 fork 原样产物",不再提示。两处边界要知道:
① 追加区必须先开一轮新 user 消息(你接着说下一句)——若紧接快照点的不是 user 消息,
这段按"疑似前缀残留"从严判失败(宁可在这一处误报,也不让真污染借"追加区"溜过);
② 指纹证据只覆盖快照点之前那 N 行,对追加区不作任何担保,不要把它读成"整条分支都没问题";
- ✅ 通过。
(Claude adapter 在没有真实 CLI 会话时,这一档属预期情况)
- 脚本自动完成备份 → 截取 → 会话 id 替换 → 注册 → 校验,无需手工介入。

Step 4 — 验证与汇报

脚本自带验证(行数/解析/sessionId 一致性/零残留/末条完整)。汇报必须使用以下固定模板:

✅ 分支创建完成

📋 分支信息
- 分支 ID:&lt;new-session-id&gt;
- 名称:&lt;custom_title&gt;
- 截断位置:第 N 行 / 共 M 行(默认模式注明&quot;上一轮输出结束&quot;)
- 分支行数:N 行

📦 原会话不受影响
- 源会话:&lt;src_id&gt;「&lt;源会话名&gt;」(= 你所在的那个对话,**已核对名称**)
- 原会话继续正常使用,不受影响

💡 查看新分支
- &lt;原样复制脚本输出里那一行 `ACTION : 分支已创建——…`,它已按产品适配(逐产品要点见 Step 0「分支怎么出现」表)&gt;
- **不要凭记忆写&quot;重启 WorkBuddy&quot;**——非 WorkBuddy 渠道那样说就是错的

📌 下一步
- 按上面那条提示回到产品里打开该分支
- 或在当前对话继续(分支已独立保存,不会丢失)

查询分支时(--list)使用:

📂 当前工作区的分支列表
- &lt;id&gt; | &lt;名称&gt; | &lt;状态&gt; | &lt;创建时间&gt;
- ...
(共 N 个分支,无分支时提示&quot;当前工作区暂无分支&quot;)

Step 5 — 记录(可选)

建议把分支创建记录追加到项目自己的日志里:新 id、行数、截断点、custom_title、备份路径——便于日后回溯"这个分支从哪条线分出来的"。

  • WorkBuddy:日志惯例是 .workbuddy/memory/YYYY-MM-DD.md;
  • 其他产品:用它自己的记忆 / 日志约定,不要凭空创建 .workbuddy/ 目录。

分支命名建议(可自定义)

  • 分支体系用序号区分:XX·分支A|描述 / 分支B|描述 / 分支C|描述;
  • custom_title 建议格式:&lt;主题&gt;·分支X|&lt;用途&gt;,如 重构登录模块·分支A|接口拆分;
  • status 一律 terminated(无活跃 agent 的正常终态,不影响打开查看)。

关键坑位

  1. 用户说了断点 → 必须用 --match / --line,不要用默认模式:默认模式只回答"这一轮之前 / 整份"两种问题,不是用户指定的中间位置——用它去执行"截断到 XXX 产生处",会把不该有的后续对话也带进分支(事后只能用 --fix 修)。
  2. 默认截断点是两种语义,由脚本自动判定:
    - 会话内打分支(最常见:你在对话里说"打分支",由 agent 执行脚本)→ 切在上一轮输出结束(最后一条 user 消息的完整回复末尾)。本轮指令与叙述不进分支。
    - 从外部执行(终端、定时任务、显式指定别家会话)→ 整份复制到末尾最后一条完整 assistant 回复。
    - ⚠️ 不要在会话内自己判断"上一轮结束在哪":本轮你自己的叙述已经在同一份文件里,按"最后一条 assistant 文本"看,看到的必然是自己。这个判定由脚本按环境自动完成,不需要人工介入——人工判定还会随对话继续而滑动。以 --dry-run 打印的锚点为准(会打出行号与锚点原文)。要强制整份:--whole。
    - 这就是"默认模式在会话内为什么锚在上一轮结束"的原因:脚本必须先定位最近一条 user 消息,再取它之前的最后一条完整 assistant 回复。任何"倒扫全文件最后一条 assistant 文本"的做法,都会把本轮内容一起吞进来。
  3. 嵌套字段旧 id 残留:只改顶层 sessionId 不够——output.text / arguments / argumentsDisplayText / toolResult.renderer.value / error.message 等字段都会出现旧 id。v2.4.3 起使用递归 id 替换(覆盖全部可读字段,仅 rawContent/rawResponse 等原始内容黑名单不碰),且在引擎层统一实现,所有产品一致——一次打分支通常要改上千处,漏一处就会被体检拦下。
  4. 指定模式边界:用户引用文本可能出现在多条回复里,取最后一条;且必须确认该回复是完整收尾(下一行是 user 消息)。
  5. WorkBuddy 会追加消息到分支文件(这条只对 WorkBuddy 成立,不要套到其他产品):脚本创建分支后,WorkBuddy 主进程可能仍向该 jsonl 追加新消息。脚本不自动锁只读(执行后提示用户自行设为只读),已有分支可用 --fix 修复(仅 workbuddy)。
  6. 快照分支特性:复制发生在读取时刻,原会话之后的新消息不会进分支——这是正常行为,不是丢数据。
  7. 附属目录 tool-results/:是运行时输出缓存,jsonl 已内嵌完整 function_call_result,分支不需要复制附属目录(或建空目录即可)。
  8. 先备份再动手:脚本已内置备份,不要跳过。备份默认落在你所用产品自己的目录里——WorkBuddy ~/.workbuddy/backups;Claude Code ~/.claude/fork-backups;Codex ~/.codex/fork-backups;Hermes $HERMES_HOME/fork-backups;pi ~/.pi/agent/fork-backups;OpenClaw &lt;agent 目录&gt;/fork-backups。想统一改到别处:设环境变量 FORK_BACKUP_DIR(对所有产品生效)。(Windows 上这些路径里的 ~ 一律指 %USERPROFILE%。)

边界

血缘只认谱系文件,不认转录(重要)

fork 产物的正文里读不出"它从谁来"——因为本引擎做的是递归 id 替换:被复制正文里出现的源会话 id,会被一并改写成分支自己的 id(覆盖全部可读字段,仅 rawContent / rawResponse 等原始内容黑名单不碰)。

⇒ 拿转录去证"我来自谁"必然得出错误结论(父 id 在产物里已经被改写掉了)。
唯一可信的出处是谱系索引:本产品目录下的谱系文件(WorkBuddy 为 ~/.workbuddy/fork.lineage.json)里的 parent_id、at_seq(快照点)与 prefix_fp(该前缀的指纹)—— --list --tree 读的是它。
(at_seq 与 prefix_fp 还让体检能核对"边界是否可信":前 at_seq 行的指纹与 fork 时一致 ⇒ 那段确是复制出来的原样产物,之后的差异只可能来自 fork 之后。)

> 于是会出现这种情形:分支自己的文件里,标记全部指向它自己;父会话文件里,标记也只指向父、不指向该分支。
> 两边都只剩"自己" ⇒ 光看转录,会得出"它来自自己"这种荒谬结论。

任务分支 vs 身份分化:同一个工具,两种语义

任务分支 身份分化
用户意图 同一段经历换个窗口继续走 造出一个新个体
产物是什么 一份可继续的工作现场 一个成员(有自己的身份与记忆)
要多做的一件事 交代分支怎么打开、原线不受影响 提醒用户:新个体需要"自报身份" + 它自己的记忆文件

⚠️ 身份分化时最容易出错的一件事:让新个体与来源共用同一份记忆 / 档案文件 ⇒ 两边互相覆盖,比丢记忆更糟。
来源的记忆对新个体是"继承来的上下文",不是"它的履历"。

  • 产物边界(最重要的一条,详见上文「分叉边界」):分叉只复制会话上下文,不回退工作区文件与已发生的外部副作用。会话可以分叉到任意节点,产物则只有在自身有版本记录(git 提交 / 云文档版本历史 / 快照备份)时才能对齐回切点;没有记录的就只有最终态。因此"回到过去"这件事,上限由产物的版本记录决定,不由分叉决定。
  • 本技能做的是存储级复制(JSONL 后端 = 新 jsonl 文件;SQLite 后端 = 库内新 session_id 的一整套行 + 会话索引记录),不是"链接/指向"——链接会让原会话后续写入污染分支,且无法表达"截断到某行为止"。
  • 分支创建后如需删除,由用户决定,不擅动。
  • 适配边界:准入判据是「会话转录在静息态可表达为有序的 JSON 条目序列,且能独立完整表达会话」——引擎的读/切/写建立在这个形状上;承载介质由适配器的行存储接口决定(v2.4.8 起,不再要求"必须是文本文件")。
  • 已在真机 / 真库验证:WorkBuddy(默认);pi(用官方包造真实会话后 fork,再用官方 API 回验)。
  • 已被产品自己认下(引擎产出能被产品读取、继续使用):Claude Code · Codex · Hermes · OpenClaw
    • Claude Code:隔离 home 真机跑出会话 → 引擎 fork → 决定性自包含测试(把源会话重命名隐藏后 --resume 仍能取到被复制的全部前缀消息);并用原生 --fork-session 做对照裁定(复制式 + 线性化修剪 + 切点不可指定)。
    • Codex:真机 codex exec 跑出会话 → 引擎 fork(自包含:丢弃源的 history_base 引用)→ 产品自己读回该分支并 resume 成功。原生分叉是零拷贝引用式(只写 history_base 指针、不复制历史),我们的自包含方案与之并存,两种取值产品都接受。
    • Hermes:隔离 HERMES_HOME 真机跑出会话 → 纯 SQL 写入 state.db(sessions + messages 两表)→ 产品 sessions list 列出该分支、chat --resume 续跑并答对被复制前缀里的信息;随后产品自己往分支追加消息(已接管)。无需任何产品侧修复命令。
    • OpenClaw(两世代):
    • ≤2026.6.x(JSONL 后端):真机跑出会话 → 引擎 fork → 官方 CLI openclaw sessions 列出 → 在分支上续跑成功。
    • ≥2026.9.x(SQLite 后端):转录落在 agents/&lt;id&gt;/agent/openclaw-agent.sqlite 的 transcript_events 表((session_id, seq) → event_json,与 JSONL 的行序→条目完全同构)。真机 fork 后官方 CLI 列出、分支续跑成功,且 OpenClaw 自己接管并维护该分支的投影进度(indexed_seq 随续跑推进)。
      写入涉及 7 张表缺一不可,且须跑一次 openclaw doctor --fix。
      ⚠️ 这是 OpenClaw 官方的命令(让官方校验并置 entry_valid),与本技能自己的 --fix 参数完全无关——两者同名不同物,不要混用(前者在 OpenClaw 里跑,后者只在 WorkBuddy 里跑)。
  • 不在范围:C 端云优先 SaaS(元宝 / 千问等)本地无转录。

数据与权限边界(本技能会读写什么)

> 这一节写给要在受管环境里评估本技能的人(安全审查 / 平台审核 / 团队管理员)。照实写,不夸大也不含糊。

读:本产品自己的会话记录(WorkBuddy / Claude Code / Codex / Hermes / pi 的 transcript 文件,或 OpenClaw 的 SQLite 库),以及只读打开的产品会话索引。
写(只有这三处,且从不修改源会话):
1. 新建的分支会话(源会话逐字节不动);
2. 旁路谱系索引(如 ~/.workbuddy/fork.lineage.json)——不写产品官方 schema;
3. 产品自己的会话索引(sessions.json / sessions 表等)新增一行指向该分支;写前自动备份(.bak.&lt;时间戳&gt;)。

明确不做:不联网、不上传任何数据、不读凭据或密钥文件、不请求提权(不调用 sudo / root)、不改系统配置、不安装任何东西。
可先验证再执行:--dry-run 不落位、不登记、不改源会话——它会写一个临时文件用于磁盘字节校验(校验完即清理),所以运行处需要写权限;--verify 是只读体检。
文件权限:分支文件要不要设为只读,完全由你自己决定;本技能只建议、不代为修改。
语言:本技能面向中文用户编写;同时提供英文字段 display_name_en / description_en(英文说明见仓库 README.en.md)。

故障排查(现象 → 原因 → 处理)

适用 现象 原因 处理
全部 VERIFY FAILED: old session id still present in non-raw fields 替换引擎漏了某可读字段(真残留,会拦) 属创建阻断——v2.4.3 起验证前置:失败自动清理已写文件与注册,不留脏分支;排查残留字段是否在新字段类型上
全部 VERIFY FAILED 但分支已出现在产品里 旧版本的问题(v2.4.3 及更早:verify 在注册后才跑,失败也留脏分支) 删掉该脏分支;升级到 v2.4.3+,新失败不再留痕
仅 WorkBuddy 分支建好但左侧没出现 WorkBuddy 会话列表非实时刷新(正常行为) 重启客户端(macOS:⌘Q 重开 或 open -a WorkBuddy;Windows:托盘图标右键 → 退出后重开)后即可看到
非 WorkBuddy 分支建好但看不到 各产品不同,且有反直觉项(如 Codex 桌面版也要 ⌘Q 重开) 照脚本输出的 ACTION 行做;逐产品要点见 Step 0「分支怎么出现」表——不要照搬 WorkBuddy 的说法
仅 WorkBuddy 分支打开后末尾多了一段不是我的内容 主进程在创建后继续向分支文件追加了消息(脚本不锁只读) 用 --fix &lt;分支会话ID&gt; 重截断到谱系记录的 at_seq(仅 workbuddy 支持)
全部 原会话之后的新消息没进分支 快照特性(复制发生在读取时刻)——正常行为,不是丢数据 无需处理
全部 分支文件找不到 / 索引有记录但文件被删 外部清理 无恢复必要则删该索引记录(分支是快照,内容已在源会话)
全部 --verify 体检某分支报"源 id 残留" 两种可能:①(v2.4.3 及更早)该分支在 v2.2.0 前创建,替换不彻底;②误报——fork 后产品追加的消息里恰好出现源 id(如一次 ls 输出中恰好有个同名目录,WorkBuddy 的实例是 ls ~/.workbuddy/tasks)。v2.4.4 起追加区只对工具/函数 I/O 字段宽容,正文等其余字段仍从严 ①历史脏分支:重新打分支后删除旧分支(备份后);②升级到 v2.4.4+ 即可。若该分支谱系 at_seq 缺失或与实际不符,校验会故意退回更宽的旧边界——宁可误报也不漏检,此时重打一次该分支即可

安装 / 升级(按产品,各一句话)

  • WorkBuddy:技能市场搜「会话分叉」,或 SkillHub 搜 session-fork;升级 = 重新装一次(装完是静态副本,不会自动更新)。

  • 源码:https://github.com/yamingmou/session-fork-core · 作者 OfferKuai(Offer快)团队 · License MIT(自由使用、修改与再分发,保留署名)。

变更历史

见仓库根 CHANGELOG.md(每版按:价值 / 实现 / 修改 / 检查)。本文件只留「怎么执行」——把历史塞进每次执行都要读的文档里,是噪音也是成本。当前版本不在此处手写:唯一权威是仓库的 tag / Release 与包内 frontmatter 的 version。

常见问题

5 问
答案由本站依据条目字段整理
会话分叉(打分支)怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_5b43da63/session-fork。安装方式为未标注。装完刷新技能列表或重开客户端。

会话分叉(打分支)支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

会话分叉(打分支)权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

会话分叉(打分支)收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

会话分叉(打分支)用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。