
一个从八月底那个晚上开始的小项目:关掉 Claude,对话自动同步到我自己的服务器;手机打开网页,翻阅、搜索、摘抄。不经过任何第三方云。
项目代号
claude_sync。这篇文章是它的开发手记。
深夜想找回一段对话
八月底的一个晚上,我想找回一段和 Claude 的对话——就是用访谈的方式、一个问题一个问题把「答题问卷网站」的需求聊清楚的那个会话。它聊了两千多条。很多判断在当时觉得已经记住了,第二天就模糊了。
我打开电脑翻了半天。对话都在,但它们锁在一台台式机的隐藏目录里。坐在书桌前我忽然意识到一件事:这段时间我往 Claude 里倒了多少思考,就有多少思考被锁在这台电脑里。
放同步盘?对话里有我全部的项目路径、服务器地址和还没成型的想法。传第三方云?我连张截图都舍不得交出去。想了想,我还有一台吃灰的 Ubuntu 小服务器,一年花不掉一杯咖啡钱。
那就自己修一条路。
起点:对话都去哪了
动手之前先搞清楚数据在哪。答案是 %USERPROFILE%\.claude\projects\:一个会话一个 .jsonl 文件,纯文本,每行一条 JSON——标题、我的话、Claude 的回复、思考过程、工具调用,全在里面。
实测这台机器:21 个会话,112 MB,19,758 条消息。打包压缩后不到 39 MB。
数据是我的,格式是开放的,只差一条通路。
设计:一条最短的路
整个系统就是一行话:
关掉 Claude → 守候进程发现 → 打包 JSONL → 签名上传 → 手机上看三端各司其职:
- Windows 端:一个守候脚本每 5 秒看一眼 Claude 在不在,退出了就等 6 秒(让文件锁释放),把所有
.jsonl打包、签名、传走; - 服务器:一个 Python 文件收 zip、解压、把两万条消息解析进 SQLite——上传是低频动作,解析成本在上传时一次付清,之后列表、分页、搜索全部走索引;
- 手机:一个单文件
index.html,无框架、无构建步骤,三个标签页:会话、搜索、摘抄。
数据库只是索引,真相永远是 sessions/ 里的原始 JSONL,删掉数据库重启服务就能重建。这个原则后来救了我不止一次。
开发记录五则
一、第一次上传,连报错都是乱码
8 月 24 日晚上 7 点 29 分,第一次真实上传,HTTP 403:
[2026-08-24 19:29:46] Server returned HTTP 403
[2026-08-24 19:29:46] response: {"error": "缁涙儳鎮曢幋鏍︽姢閻楀本妫ら弫}
[2026-08-24 19:29:46] hint: token/secret mismatch, or local clock is off签名算错了是正事,但我盯着那串乱码笑了很久——服务器返回的中文报错,在我的 GBK 终端里又变成了一团更深的谜。排错之前先解码。五分钟后修好:
[2026-08-24 19:34:22] Upload succeeded: {"status": "success", ...}从那天起这个项目立了规矩:Windows 脚本全部用纯 ASCII 英文。.bat 在中文 Windows 上按 GBK 解读,放进中文就是乱码或语法错;行尾还必须是 CRLF,否则 cmd 会把第一行吃掉,报出 'etlocal' 不是内部或外部命令 这种鬼畜错误。中文说明全部住在 docs/ 里。这是我给自己的伤口缠的绷带。
二、一行 sed,服务循环重启了 211 次
部署脚本要把令牌写进配置,最早的做法是 sed 一把梭。结果 sed -i "s|upload_token.*|...|g" 里那个 .* 加 g,命中了源码里每一处 upload_token,连函数体都被改成了这样:
if not token or not CONFIG["upload_token": "你的密码",
return FalseSyntaxError。服务起不来,systemd 忠实地一次次拉起它,重启计数涨到 211。表面症状是「网站打不开」,所有接口 502——我盯着证书和 Nginx 排查了半天,凶手却在一行我以为无害的 sed 上。
这条教训后来写进了部署手册,标题叫「一条铁律:先确认源码是最新的」。按功能特征核对,别比字节数——改几行注释字节数就变了。
最好玩的是,这段翻车现场我在自己的档案馆里还能搜到。搜「211 次」,当年和 Claude 排查时的对话原文就在那里,高亮着:

这个项目修自己的故事,被自己存了档。
三、一台机器上的两个 Nginx
404 是另一桩罗生门。我的服务器装着宝塔面板,而宝塔自己带一套 Nginx(/www/server/nginx),系统里还有一套(/usr/sbin/nginx)。我敲 nginx -t 检查的是 PATH 上那个,真正在服务的是另一个。更狡猾的是:配置文件有语法错时,reload 会静默失败——Nginx 继续跑着旧配置,HTTPS 照常通,只有新加的路径一直 404。
补刀还有两个:http2 on; 这个指令要 Nginx ≥ 1.25.1 才认识;basic auth 的密码文件属组,Debian 系的 worker 叫 www-data,宝塔编译的叫 www——属组不对的症状恰好是「输入密码之后才 500」。
后来我写了 fix_nginx.py:先 --report 诊断(自动找出真正在服务的那个 Nginx,列出哪些配置已被加载、哪些改了也白改),再 --dry-run 干跑一遍,最后才动手术,nginx -t 不通过就自动回滚。工具替我记住这些坑,我就不用再记第二次。
四、删除为什么要绕一大圈
「手机上删掉一个会话」听起来一句话的事,做起来绕了四步:手机点删除 → 服务器立刻隐藏并记账 → 下次 Windows 同步时删掉本地源文件 → 再下次上传时销账。
绕这一圈是因为每次上传都是整体替换服务器上的 sessions/——只删服务器,下次同步它会原样回来。删除必须是永久的,就得连源头一起删。
9 月 4 日晚上,我造了一个假会话做了次全链路测试:
[2026-09-04 21:59:40] Server asked to delete 1 local conversation(s)
[2026-09-04 21:59:40] deleted: ...\_deltest\ffffdead-0000-4000-8000-...jsonl
[2026-09-04 22:01:10] Upload succeeded: {"sessions": 21, "pendingDeletions": []}不可撤销,没有回收站。这是刻意选择的行为——删除就该有删除的样子。
五、守候进程:把自己从流程里去掉
自动同步的关键不是技术,是「我不想记得『记得上传』这件事」。守候脚本装成开机自启,平时完全无感:
[2026-09-07 21:46:03] Claude exited - uploading in 6s
[2026-09-07 21:46:20] Upload script finished with exit code 0那之后的日子,每次我关掉 Claude,它都在六秒后自动开工。四十 MB 的包,上传到解析入库一分钟左右。我一次都没有想起过它——好的工具大概就是这样,存在感越低,做得越好。
现在的样子
手机打开自己的域名,过两道门(Nginx basic auth + 页面密码),就是这方小小的档案馆:

列表按最后活动时间排序,每条左边有一道竖线,深浅和消息量挂钩——扫一眼就知道哪段聊得多。点进去是阅读页:

每页 50 条,可以直接填页码跳转——使用手册里记过一次实测,6876 条的会话分成 138 页,打开即用,不卡。回复上方有「层理轨」:那一条回复背后调用了什么工具、思考了多久,默认收起,正文干净。
搜索是找东西最快的路径:搜全部会话正文,点任意一条命中,直接跳到原文所在的那一页并高亮。
摘抄解决的是另一件事——读到值得留的段落,点「摘」,写上标签和批注。每条摘抄同时落两份:SQLite 里一份,excerpts/ 目录下一个带 YAML frontmatter 的 Markdown 文件,随时可以 scp 拉走扔进笔记软件。

安全边界,丑话说在前面
自己搭的东西,安全得自己兜底。做了的:上传用 token + 时间戳 + SHA256 签名,五分钟时间窗防重放;上传服务只监听 127.0.0.1,公网碰不到;解压时校验路径,防 zip 路径穿越;删除请求只接受纯 sessionId,Windows 端二次校验后才动本地文件。
也要坦白:页面里那个密码是明文写在 HTML 里的,看源码就能拿到,它只是第一道门,真正的防线是 Nginx basic auth。对话在服务器上是明文存放的——所以 SSH 密钥登录、禁 root 密码这些基本功,一样都不能少。
尾声:摘抄是唯一不可再生的部分
服务器上的数据库随时可以从原始 JSONL 重建,备份清单上几乎什么都可以省——唯一的例外是摘抄。
因为对话是原料,摘抄是产出。两万条消息里被我亲手挑出来、写上批注的那几十段,才是这个系统里真正属于「我」的部分。有一天我删掉一段对话,服务器上的数据真相没了,而被摘出来的那几句还在——我挺喜欢这个设定的。
写完这个项目,我想明白了一件事:这些对话不只是我和一个工具的来往。它们是我思考过程的化石——被推翻的方案、绕过的弯、凌晨一点突然想通的那一步。现在,它们每天晚上自己搬家,搬进一台我每月花几块钱养着的服务器里,安安静静地等我来翻。
如果你也想给自己的对话修一条回家的路,整个项目不大:
| Windows 端 | 5 个脚本:守候、打包上传、自启注册,纯 ASCII |
| 服务器端 | 1 个 Python 文件 + 1 个单文件 HTML 查看器 |
| 存储 | SQLite 索引 + 原始 JSONL + 摘抄 Markdown |
| 依赖 | Python 3.8+、Nginx,无前端构建步骤 |
| 体量 | 21 个会话 / 19,758 条消息 / 打包 39 MB / 一分钟同步完 |
不值钱,但好用。而它最好的一点是:数据从头到尾没有离开过我手里。
评论
抢个沙发还没有评论,来说点什么吧。