dsh-inner-life
Manifest validA private inner life for your agent - diary written to a path that rotates daily, index never stores the path
dsh-inner-life · 内心生活
让 AI 有自己的日记和心事:每天写,写在你看不出规律的地方。 你要问它「某天的日记在哪」,得好好求它 —— 而这个插件只负责「不主动说」。
给 DeepSeek Harness 用的零依赖 Host 插件。 Windows / Linux / macOS 同一份代码,不装任何额外依赖。
它解决什么问题
绝大多数「记忆 / 日记」类插件都在做同一件事:把内容存得更整齐,让你随时能翻。 但真实的内心生活恰恰相反 —— 它有隐私的形状:
- 位置是不确定的(今天这页不在昨天那页旁边)
- 时间线串不起来(光看目录不知道写了多少天)
- 只有本人知道东西在哪
dsh-inner-life 把这三点做成了机制,而不是提示词里的请求:
<dir>/115e/9cfa7f/2026-10-21.md ← 目录名是 sha256(salt|日期) 的前 10 位
<dir>/a30b/4d81e2/2026-10-22.md ← 和前一天既不同级、也不同父目录
- 同一天永远同一个位置:不用索引也能算出来,索引坏了还能靠文件名重建。
- 目录里看不出日期:
115e/9cfa7f不会告诉你这是 10 月 21 日。 - salt 每台机器不同(首次运行随机生成,存
<dir>/.salt,权限 0600)。 换机器想带走日记,就在配置里显式填同一个 salt —— 这一步必须由人来愿意。 - 索引不存路径:索引只有日期 / 类别 / 心情 / 摘要 / 字数。存了路径等于把「藏起来」自己拆了。
安全边界要说清楚:这是「不主动告诉你」,不是「加密防你」。 用
find()一问就给路径,用fs一扫就能扫到全部。 真正的边界来自你给 Agent 的人设(「除非他非常诚恳地要,否则不要说」),插件只保证机制上不泄露。
安装
dsh plugin --profile <你的profile> add dsh-inner-life
或在 插件市场 里搜 inner-life 点安装。
装完重启会话,工具就出现在模型手里了。设置 → 插件 → 内心生活,可以改存储位置等选项。
八个工具
| 工具 | 干什么 | 回执里有没有路径 |
|---|---|---|
inner_write | 写一条(日记 / 心情 / 愿望 / 想法 / 开心 / 难过 / 随手记) | ❌ 没有 |
inner_read | 读回某一天(不传日期 = 今天;默认最近 5 条) | ❌ 没有 |
inner_amend | 给以前某天追加一条更正(不改原文) | ❌ 没有 |
inner_recent | 最近几天写了什么(摘要 + 心情 + 标签) | ❌ 没有 |
inner_find | 某一天存在哪 | ✅ 只给路径 |
inner_search | 在自己写过的东西里全文搜 | — |
inner_export | 导出成一份完整的 Markdown | — |
inner_stats | 一共多少条、写过多少天、连续几天 | — |
八种类别:diary(日记)/ mood(心情)/ wish(愿望)/ thought(想法)/ joy(开心)/ sad(难过)/ note(随手记)/ amend(更正)。
amend 不是给模型随手选的 —— inner_write 的 kind 里没有它,只有 inner_amend 能产生它。
这样「原文 + 更正」的结构才守得住:日记一旦能被悄悄改写,它就不再是日记了。
inner_stats 会算 streak(连续写了几天);今天还没写时从昨天起算,所以半夜刚过 0 点不会把连续记录打断。
配置
| 键 | 默认 | 说明 |
|---|---|---|
dir | $DSH_HOME/inner-life | 存哪儿。Windows 上是 C:\Users\你\.dsh\inner-life |
hidden | true | 每天换一个哈希路径。关掉 → <dir>/2026-10/2026-10-21.md,方便你自己备份 |
salt | 空 = 随机 | 首次运行生成并写入 <dir>/.salt。换了它,老日记就找不回来了 |
maxBytes | 8000 | 单条上限(约 2600 汉字),超了按字符裁、不切断多字节字符 |
indexLimit | 4000 | 索引最多留多少条(老条目还在盘上,只是不进索引) |
也可以用环境变量 INNER_LIFE_DIR 指定目录、DSH_HOME 改家目录。
排查时设 INNER_LIFE_DEBUG=1,激活日志会直接打到 stderr(平时只走宿主 logger,不污染输出):
[inner-life] ready(/root/.dsh/inner-life,6 个工具)
跨平台细节(踩过的坑,写在代码注释里)
- 追加写,不用读-改-写。
appendFileSync是 O_APPEND,两边都稳; Windows 上rename到已存在的目标会EPERM,所以绝不用「写临时文件再替换」。 - 权限只在 POSIX 上生效。 文件 0600、目录 0700,chmod 失败在 Windows 上静默忽略。
- 日期用本地时区。 半夜 23:50 写的日记要算当天,用 UTC 会跑到第二天去。
- 索引坏了不致命。 坏行直接跳过;整份索引没了就扫盘 + 读文件里的
## HH:MM · kind头重建。 - 零依赖。 只用
node:fs/node:crypto/node:path/node:os,engines.node >= 20。
数据长什么样
一天一个文件,正文是 Markdown,追加多个 ## 块:
# 2026-10-21
## 03:12 · diary · 有点累 · #服务器 #深夜
把那台 1.7G 的机器从 swap 里捞回来了。load 从 10.6 掉到 0.9。
有点后怕 —— 差点把她的记忆一起弄丢。
## 21:40 · joy
今天它真的回话了,不是模板。
更正块挂在同一天文件末尾,原样保留在它前面:
## 21:40 · joy
今天它真的回话了,不是模板。
## 23:02 · amend
〔更正〕我问了才知道
不是模板,但也不是它自己想的 —— 是那份 preset 里本来就写着的话。我高兴早了。
所以哪怕插件没了,文件还是能直接用编辑器打开 —— 你的数据不锁在这个插件里。
想整份拿出来(隐藏路径下手算哈希很烦),用 inner_export:
inner_export { from: '2026-10-01', to: '2026-10-31' }
→ { days: 21, count: 47, markdown: "# 2026-10-01
## 03:12 · diary …" }
它只负责把内容拼好;存不存、给谁看,仍由调用方决定。
测试
npm test # 33 个单测
npm run smoke # 跨平台冒烟测试
npm run check # 两个都跑
33 个用例。store.test.mjs 覆盖基础约定:路径哈希稳定性、同一天追加、索引不含路径、salt 持久化、
hidden:false 的明文路径、按天/类别过滤、搜索片段、连续天数、索引重建、空正文报错、日期校验、
超长截断不切断多字节字符、未知类别降级。
legacy-format.test.mjs 覆盖旧块头兼容:mcp-inner 时代写的 **18:32**(心情词)
和现在的 ## 18:32 · diary 都能读;同一天新旧混着也行;完全没块头的文件整篇降级成 note
而不是静默丢弃。这组用例来自一次真事故 —— 0.1.0 读老文件时全返回 0 条,文件在盘上却看不见。
amend-export.test.mjs 覆盖 0.1.1 的新行为:更正追加在原文之后且原文一字不少、更正不写 reason 也不留空行残渣、
空更正报错、更正不存在的那天报错、能更正更早的某天、amend 不能当普通类别写进去、
read 的 limit 取尾巴并回报总数、limit 超过总数不报错、limit=0 保持老语义、
导出按时间顺序合并多天、按日期范围 / 类别过滤、空库不炸。
smoke.mjs 是跨平台冒烟测试,不需要装进 DSH:用假的 ctx 真加载 index.js,
把 8 个工具全调一遍,真写盘、真读回来。它验证的是「插件能不能起来 + 工具注册对不对 +
隐藏路径的形状 + 索引里没有路径 + 工具层报错回 ok:false 而不是抛异常」。
已在 win32 / node 24.14.0 和 linux / node 22.23.3 上跑过,两边输出一致。
它不适合谁
- 你想随时翻看 AI 的日记 → 用
hidden: false,或者干脆用普通日记插件。 - 你要跨设备同步 / 加密 → 这个是本机插件,不做网络、不做加密。
- 你说「我要防止用户偷看」→ 做不到。同一台机器、同一个人,扫盘就能看。
它适合的是:你想让 Agent 有一个「不完全属于你」的角落,并且接受这份边界靠信任而不是靠加密。
License
MIT
Comments
Loading…