2026年4月23日 周四晚上19:30,来了解“从个人单点提效,到构建企业AI生产力”(限30人)
免费POC, 零成本试错
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


我要投稿

我写了一个 claude code session 迁移 skill

发布日期:2026-04-18 06:43:47 浏览次数: 1516
作者:手工川

微信搜一搜,关注“手工川”

推荐语

轻松解决Claude Code会话迁移难题,一键找回丢失的对话记录!

核心内容:
1. 开发cc-migrate-session脚本解决会话迁移痛点
2. 技能安装与使用方式详解
3. 技能开发背后的架构思考与未来规划

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家

本文原先是在 ~/.claude 下基于 cc 写完初稿,接着移动到了个人的 obsidian 知识库下,结果之前的对话记录就没了……

但一点不慌,在新的目录下打开 cc 后输入 /lovstudio-cc-migrate-session 原目录在 ~/.claude,它就整理出了之前的对话记录(一共 14 条)。

我继续说 只要 cc-migrate-session 相关的即可,它通过分析就是最后一条,然后就把它迁移到了本目录。

接着我退出当前 cc,并输入 cc --resume,它顺利显示出了之前的对话记录,选择其中一条后进入,我接着进行下一步的创作。

这就是我今天想给大家介绍的 cc-migrate-session 脚本(并同步提供了skill: npx skills add lovstudio/cc-migrate-session-skill),能帮你免费、精准、按顺序地迁移旧地址的 cc 对话记录,让你不再为移动文件夹而丢失记录而担忧!

值得注意的是,在研究本 skill 时,发现了一些关于 skill 触发的限制,也正暗合我最近对我们 Lovstudio.ai 官网 skills 的一些架构调整思考:

claude code 官网关于 skill 窗口的限制

claude code 官网关于 skill 窗口的限制

Lovstudio.ai 计划对 skills 做领域分层

Lovstudio.ai 计划对 skills 做领域分层

搬家之前、搬家之后、修复之后

搬家之前、搬家之后、修复之后

大家肯定遇到过这样的情况

你在用 Claude Code 和一个项目聊了一两周,几十小时对话、几百次工具调用、几万字上下文全在里面。某天你觉得这个项目应该归档到别处,或者目录命名该统一一下,或者单纯就想清理一下 ~/ —— 一个 mv 就搬走了。

然后你 cd 到新路径,敲 claude --resume

No conversations found
claude --resume 无法找到之前的对话

claude --resume 无法找到之前的对话

回旧路径(已经是空目录了)—— 也没有。

这是个几乎没人谈、但一旦踩到就很疼的坑。只要你是会整理自己文件系统的那种人(我身边不少知识工作者都是),你迟早会撞进来一次。撞进来的那次通常也不会立刻损失重要数据,只是"哎?我昨天那个会话呢?"然后你就放弃了,另开一个新会话重讲一遍上下文。

但次数多了你会发现:Claude Code 的会话历史,其实是被你随手的文件整理动作慢慢磨掉的一种资产

所以我把这个问题做成了一个 Claude Code skill,叫 lovstudio:cc-migrate-session

装上之后你不用再记任何命令 —— 在任何会话里随口说一句 "我把项目搬到了 /new/path"、或者 "本项目之前是在 /old/path"、或者 "claude --resume 找不到历史了",CC 就会自动唤起这个 skill 把会话迁过去,迁完提示你重启到新路径 --resume,上下文立刻续上。

下面讲一下这个 skill 是怎么想的、怎么装、以及中间我踩到的一个所有现有方案都漏掉的细节


装到 CC 或龙虾里

Skill 是 Claude Code 这半年最值得关注的生态扩展方式之一 —— 它比 slash command 更"隐形"、比 plugin 更轻,Anthropic 自己给它的定位就是"让 Claude 在需要的时候自己调用的能力包"。而且它不只能在 CC 里用 —— 龙虾、以及其他兼容 Claude Code skill 规范的客户端都能装,同一个 skill 写一遍,多处生效。

cc-migrate-session skill, at Lovstudio.ai skills

cc-migrate-session skill, at Lovstudio.ai skills

最简单的装法,一条命令

npx skills add lovstudio/cc-migrate-session

装完重启 CC,随便开一个会话说"我把项目搬到了 /xxx"试试 —— 它会自动触发、先 dry-run preview 给你看、确认后执行。

龙虾用户:直接在 app 里打开 "Manage Skills",搜 cc-migrate-session 一键安装,和 CC 里的体验是对齐的。

或者上 Agentskills.io[1] 搜 cc-migrate-session,网页直接一键装。

agentskills.io 首页

agentskills.io 首页

(如果你更喜欢自己手动,clone 仓库再 symlink 到 ~/.claude/skills/ 也行,但 npx skills add 会帮你处理路径和多客户端差异,推荐这个。)

触发方式就是自然语言。我给这个 skill 写的 description 和 when_to_use 里埋了一组中英混合的触发短语:

  • 中文:"我把项目搬到了"、"本项目之前是在"、"claude --resume 找不到历史"、"cc --resume 找不到"
  • 英文:"I moved the repo to"、"this project used to be at"、"renamed the folder"

你不用背,这些只是 LLM 做 skill 匹配时的锚点 —— 你用自然语言描述你在做什么,CC 自己会判断该不该调。


CC 的存储:一个和 Git 截然相反的决定

要写这个 skill,第一步是搞清楚 CC 到底把会话存在哪、怎么存。

Git 的决定很直白:每个项目自己的历史放在项目内部的 .git/ 里。搬家的时候整个目录 mv.git 跟着走,git log 永远能看到所有提交。这是一种项目自包含的世界观。

CC 的决定正好相反:所有项目的会话历史放在全局中心仓库~/.claude/projects/ 里。每个项目按它的绝对路径编码成一个 slug 目录,用这个 slug 去反查。

Git 把历史塞进项目里,CC 把历史存在一个中心仓库,所有项目都指回去

Git 把历史塞进项目里,CC 把历史存在一个中心仓库,所有项目都指回去

规则非常简单 —— 把绝对路径里每一个不是 [A-Za-z0-9] 的字符替换为 -

每个 slug 目录下是若干 <session-uuid>.jsonl。打开任意一个,每一行是一个 JSON 事件,字段里都带着一个 cwd,记录当时那条消息发生时的绝对工作目录。

这套存储是典型的 append-only event stream[2] 设计 —— 会话不是可变文档而是事件流,只追加不改写,重启/崩溃/强退都不丢数据。这个决定本身很漂亮。

Milvus 这篇博客把 CC 存储为什么这么稳拆得很清楚

Milvus 这篇博客把 CC 存储为什么这么稳拆得很清楚

真正让搬家出问题的是另一层 —— 路径就是 ID。CC 把"这是哪个项目的会话"和"这个项目当前在哪个绝对路径"彻底等同了。slug 是路径,jsonl 每一行还在重复确认"我当时在哪个路径"。整个会话身份完全由文件系统位置定义,位置一变,身份就没了。

所以一个最小完备的迁移动作是什么?按上面的存储模型推:

  1. 把 slug 目录名改掉 —— 从旧路径的 slug 改成新路径的 slug
  2. 把每行 jsonl 里的 cwd 字段改掉 —— 从旧绝对路径改成新绝对路径(精确匹配 + 前缀匹配,因为子目录 cwd 也可能出现)

这两步做完,cd <新路径> && claude --resume 就能看到历史。我的第一版脚本就是这两步,10 行代码,跑起来确实 work。

然后我发出去了。然后我自己真用了一次。然后发现了一个谁都没在文章里提过的坑


社区现有方案漏了哪一刀

在开自己的 repo 之前我去几个 CC 社群和 GitHub issue tracker 翻过一圈。

结论是:这个问题在过去一年里被独立地、反复地提出过至少七八次,但从没被 Anthropic 正式解决。

最刺眼的一个是 Anthropic 官方仓库的 Issue #34115 — "Folder no longer exists" when project paths change — no recovery path, requires manual binary DB edits[3]

Issue #34115,报完被关成 duplicate,问题仍然存在

Issue #34115,报完被关成 duplicate,问题仍然存在

报告人详细罗列了恢复一次会话需要编辑的四处状态

他的原话:

"This took multiple hours of investigation and several failed attempts to fix for one user. It should not be this hard."

Issue #34115 最后被关成了 duplicate。同样被关掉的还有 #27473[4]#5768[5]#3473[6]#19707[7]#36937[8]。都是一个意思,都没 fix。

中文社群里也有碎片。一位朋友在群里说:

"有的,之前也遇到了,想直接迁移,结果只能查到索引,原来的对话记录文件直接消失了。"

这位大概率是在 Mac 的 ~/Library/Application Support/claude/ 里动了 LevelDB,所以"索引还在,文件没了"。

也有已经动手写过的。`@curiouslychase` 的 "Rescuing Your Claude Conversations When You Rename Projects"[9] 做了个 claude-mv bash 脚本,`gwpl` 的 gist[10] 也给了几乎一样的手工流程。

curiouslychase 的 "Rescuing Your Claude Conversations"

curiouslychase 的 "Rescuing Your Claude Conversations"

gwpl 的 gist,同一个解决方案的手工版

gwpl 的 gist,同一个解决方案的手工版

逻辑和我第一版一样 —— rename slug 目录 + sed 改 jsonl 的 cwd

他们漏的那一刀,和我第一版漏的是同一个:文件 mtime


mtime:被所有人漏掉的一刀

把 slug 目录 copy 过去、把每个 jsonl 里的 cwd 从旧路径改成新路径 —— 到这里为止,cd <新路径> && claude --resume 确实能看到历史。

但列表乱序

全部顶在最上面,列表失去意义

全部顶在最上面,列表失去意义

迁移过来的会话,不管它实际发生在一周前还是昨天,统统冒到 resume 列表最上面,排在我刚刚才在新路径里开的那个会话前面。列表变得毫无意义。

我一开始以为是 --resume 有什么奇怪的排序逻辑。不是。ls -lt 一看就明白:所有迁移过来的文件的 mtime 都被重置成了复制那一刻cp / fs.copyFileSync / Python 的 shutil.copy(不是 copy2)—— 大部分拷贝方式默认都把 mtime 设成"现在"。

CC 的 --resume 列表正是按文件 mtime 倒序排的。

所以社区那几个方案 —— mv 目录 + sed 改 cwd —— 在技术上是正确但不完整mv 本身是保留 mtime 的,所以用 mv 那一派的方案里这个问题被掩盖了;但 mv 在跨分区、跨挂载点、或者你想"copy 而不是 move 留个备份回滚"的时候,会退化为 cp + rm,mtime 就丢了。我自己正是因为想保留旧目录做 backup 才用 copy,撞进来的。

修复很短:拷贝每个 jsonl 后用 utimes 把 atime/mtime 从源文件恢复过去。如果旧 mtime 已经丢了(比如之前已经迁移过一次),还有一个兜底 —— 每条 jsonl 消息里都带 timestamp 字段,读最后一行非空消息的 timestamp 然后 touch -d 回去即可。这是 append-only event stream 设计的一个意外好处:时间信息是冗余的,文件系统层的时间戳丢了还能从数据流里重建。

这一刀的成本是两行代码。但它是"把会话找回来"和"把会话找回来并且仍然好用"之间的差别。我把这个修复从 0.1.0 升到了 0.1.1,也算这个 skill 真正 ready 的标志。

加了 mtime 保留的 0.1.1

加了 mtime 保留的 0.1.1


怎么想这个 skill 的

做成一个 skill、而不是一个你要记住名字的命令行工具,对我来说是这个项目最重要的决定。

整理磁盘是一个不预设的动作。你不会在 mv 之前先打开某个 README 想"等会我要跑那个迁移工具叫什么名字"。事情是反过来的 —— 你先搬了,搬完发现 --resume 空了,然后才想起来"诶这事应该有工具吧"。

这正是 skill 存在的意义:你不用记它叫什么,CC 自己判断"你现在描述的事情"和"我手上有哪个 skill"匹配不匹配。Skill 把"工具发现"这一层也交给了 LLM。

我给 lovstudio:cc-migrate-session 写的 description 和 when_to_use 就是这个思路 —— 不堆形容词,堆真实用户会说的原话:"本项目之前是在"、"claude --resume 找不到"、"我把项目搬到了"。这些是 CC 在判断"当前情境是否要调这个 skill"时的锚点。

底层其实有一个 npm CLI(`@lovstudio/cc-migrate-session`[11]),skill 只是一个智能封装。但对 99% 的用户来说,知道"装了这个 skill 之后随口说一句话就能用"就够了 —— 那个 npm 包是我自己调试和维护用的,大部分人一辈子不用敲 npx

这也是我更看好 skill 而不是 plugin 的原因。Plugin 要求用户预先知道它存在、预先去安装、预先去配置;skill 是在用户真正需要它的那一刻才浮出水面。对"整理磁盘"这种半年一次、但每次都痛的场景,这种触发逻辑才是对的。


做这件事的不止我一个

CC 生态现在有一个有意思的现象 —— Anthropic 把 CLI 内核做得很好,但会话治理这一圈留了大量空白:迁移、导出、归档、跨机检索、GUI 化 —— 每一块都有社区的人在做自己的小工具。

前两天看到 `LKbaba/Claude-code-ChatInWindows`[12] —— 把 Claude Code CLI 包成原生 VS Code GUI,当天就同步了 Opus 4.7 和 xHigh 思考强度。

LKbaba 把 CC CLI 包成了原生 VS Code GUI

LKbaba 把 CC CLI 包成了原生 VS Code GUI

龙虾(Lobster)做的是另一个方向 —— 把 skill 生态做成给普通人用的 GUI,不懂命令行的知识工作者也能一键安装。

每个人都在挖自己踩到的坑自己填,而且填的方式越来越"让别人装了就能用" —— 要么是 skill,要么是 GUI app,要么是一键安装市场。我觉得这个趋势是对的:Anthropic 把生态的地基和 CLI 做好,具体的工作流由社区来补,补的形式是对用户来说无需学习成本的 skill 或 app,而不是每人一份藏在 dotfiles 里的 bash 脚本。


几个更一般的判断

写完、发完、回头看,有几个感受值得从这件小事里抽出来:

第一,路径耦合是一种普遍的技术债。 Git 选的是"身份住在项目里",代价是你不能跨项目检索历史;CC 选的是"身份住在全局索引里",代价是搬家就丢历史。两种设计都合理,但后者必须在产品层给出迁移工具,不然用户做的任何整理行为都被偷偷惩罚。Anthropic 在 2026-03 的 Issue #34115 里被直接指出这一点,到现在仍然没动作。

第二,"大多数人没发现"不等于"问题不存在"。 这类问题只有真的在整理自己文件系统的人会撞到,dev 群体里不是多数派,但知识工作者里是。做工具的人要对这种"小众但重要"的场景有敏感度。

第三,Skill 改变了工具分发的默认形态。 过去写一个小工具要想清楚"怎么让用户知道它存在、怎么让用户愿意装、怎么让用户记得用";现在可以只想第一件事,后两件交给 CC 的 skill 匹配机制。这对"低频但刚需"的长尾工具是巨大的解放。我自己接下来做小工具的默认形态都会是 skill 优先。

第四,也是最直接的 —— 别在 Claude Code 跑着的时候 mv 项目目录。 要搬就先 exit、再搬、再让 skill 迁移、再重新开 session。这不是工具能救的,是纪律。

搬家这件事本身不是问题,问题是搬之前没先 exit

搬家这件事本身不是问题,问题是搬之前没先 exit


关于其他 agent runtime

这个 skill 目前只针对 Claude Code 的会话存储做适配 —— 因为 CC 的 ~/.claude/projects/<slug>/*.jsonl 结构是我调研清楚、测试充分的部分。

其他 agent runtime(Codex CLI、Cursor Agent、龙虾自己的 agent 模式、以及各种 Claude Agent SDK 包的第三方客户端)各自有不同的会话持久化方式。有的完全不落盘,有的用 sqlite,有的用自家云端 —— 目前不在这个 skill 的范围内。

如果你在其他平台上也遇到"搬家之后上下文找不到"的问题,欢迎评论或在 lovstudio/cc-migrate-session[13] 开 issue 告诉我是哪个工具、大概的存储位置长什么样、你的痛点具体是什么。积累到一两个之后我会考虑把这个 skill 拓成一个更通用的 agent-session-migrator,或者针对每个平台单独做一个 skill。

我对这类"会话治理"的工具感兴趣,也有意愿做 —— 但前提是它确实是大家共同的痛点,而不是我一个人的 edge case。


装一下试试

一条命令装好

npx skills add lovstudio/cc-migrate-session

龙虾用户也可以直接在 app 里 "Manage Skills" 搜 cc-migrate-session 安装。

装完重启,在任何会话里说一句 "本项目之前在 /old/path" 或 "我把项目搬到了 /new/path" 就行。

已经被 mv 过一次、历史好像丢了的:大概率没丢,只是还躺在旧 slug 目录里:

ls ~/.claude/projects/ | grep <你记得的路径里某个片>

找到之后直接在会话里说"本项目原来在 <你找到的那个旧路径>",skill 会把它迁过来。

会话的半年记忆,值得比 cp -r 多花十秒。


[1] agentskills.io, https://agentskills.io

[2] append-only event stream, https://milvus.io/blog/why-claude-code-feels-so-stable-a-developers-deep-dive-into-its-local-storage-design.md

[3] Issue #34115 — "Folder no longer exists" when project paths change — no recovery path, requires manual binary DB edits, https://github.com/anthropics/claude-code/issues/34115

[4] #27473, https://github.com/anthropics/claude-code/issues/27473

[5] #5768, https://github.com/anthropics/claude-code/issues/5768

[6] #3473, https://github.com/anthropics/claude-code/issues/3473

[7] #19707, https://github.com/anthropics/claude-code/issues/19707

[8] #36937, https://github.com/anthropics/claude-code/issues/36937

[9] `@curiouslychase` 的 "Rescuing Your Claude Conversations When You Rename Projects", https://curiouslychase.com/posts/rescuing-your-claude-conversations-when-you-rename-projects/

[10] `gwpl` 的 gist, https://gist.github.com/gwpl/e0b78a711b4a6b2fc4b594c9b9fa2c4c

[11] `@lovstudio/cc-migrate-session`, https://www.npmjs.com/package/@lovstudio/cc-migrate-session

[12] `LKbaba/Claude-code-ChatInWindows`, https://github.com/LKbaba/Claude-code-ChatInWindows

[13] lovstudio/cc-migrate-session, https://github.com/lovstudio/cc-migrate-session/issues


53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询