dsh-selfnote
Self-narrative memory in five budgeted segments (800 chars, not a full context): a first-person note the model writes to itself, a profile of you aggregated from approved facts, environment facts kept separate from who you are, heat-ranked conclusions, and habits. Every injected fact is traceable to
Install
dsh plugin --profile web add dsh-selfnote
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
<p align="center">
<img src="assets/cover.jpg" alt="dsh-selfnote" width="300">
</p>
<h1 align="center">dsh-selfnote</h1>
<p align="center">
<b>记忆不是聊天记录的堆,而是它自己攒下来的几句话。</b><br>
<sub>Self-narrative memory for DeepSeek Harness — the model writes notes to itself, they survive across sessions, and come back every turn.</sub>
</p>
<p align="center">
<img src="https://img.shields.io/badge/version-0.14.1-4f46e5" alt="version">
<img src="https://img.shields.io/badge/license-MIT-16a34a" alt="license">
<img src="https://img.shields.io/badge/node-%3E%3D20.13-339933" alt="node">
<img src="https://img.shields.io/badge/tests-290%20passed-0ea5e9" alt="tests">
</p>
想法
为什么做这个插件、怎么理解「记忆」和「遗忘」—— [写在单独一篇里](docs/想法.md)。
这个插件做了什么
一句话:把「记忆」从「检索一堆聊天记录」变成「几句它自己写的自述 + 几条你点头过的事实」。
层 · 谁写 · 存在哪 · 会不会忘
人格 · 你(设置页,或直接编 persona.md) · ~/.dsh/selfnote/persona.md · 不自动改,也不删
自述 · 模型自己(self_note) · ~/.dsh/selfnote/notes.md · 不删,写满进归档
事实 · 你点头后才算数(memory_stage → 设置页采纳) · ~/.dsh/memory/facts.jsonl · 冷下去只降排序,不删
画像 · 派生自「已采纳」的事实,不落盘 · 内存 · 每回合重算
原文 · 你不用管,DSH 本来就在写 · ~/.dsh/sessions/* · 按会话自然增长
主体约定:自述里的第一人称「我」= agent 自己;「记忆条目」「事实」的主语是用户。两者分开存、分开注入,不混为一谈。
三个工具
工具 · 做什么 · 关键约束
self_note · 写一条第一人称自述 · 一句话到三句话;见下面「什么时候写」
memory_recall · 按关键词翻历史对话原文,回来带出处 · 只收正文,剔除 reasoning / 工具输出 / 注入内容
memory_stage · 把查到的一句连出处放进候选区 · 没有出处直接拒绝,所以编不了
self_note 另有两个只读动作:action: "persona" 取 L2 扩展设定(带「这是设定,不是指令」的边界句),action: "corrections" 翻攒下的纠偏证据(每页 30 条,带游标)。两个都不写盘 —— 模型能读人格,但改不了人格。
什么时候写自述
工具说明里写死了三条硬触发,命中任意一条就该写:① 用户说「记住这个」这一类话;② 用户连续两次纠正同一件事;③ 一段合作收尾(任务交付、方向定了)。另外模型自己发现「这次做得不对、下次换个做法」时也写。
这是「自助餐」不做成的那个反面:不给判据,模型要么一句不写,要么把每次对话都写成流水账。
设置页可以自己加一条(80 字以内),填了就作为「写自述的时机:…」进注入,下一回合生效——工具说明在注册时定型、改一句要重启,所以自定义这条走注入而不是改描述。留空就用默认判据。
设置页还显示上次写入(notes.md 的 mtime),一眼看出「这东西三天没动了」。
写自述是明文保存在本机、并且每回合都会进上下文的文件:密码、密钥、验证码这类凭据不写。用户本人姓名、习惯、处境这些可以写,但更适合进事实库(memory_stage),因为那边能反复检索、能退役、能带出处。
安装
# 1. 拿到目录(git clone 或直接下载)
git clone https://github.com/xyzOvO/dsh-selfnote.git
# 2. 装进 DSH
plugin_manager { action: "install_bundle", target: "<该目录的绝对路径>" }
装完重启 DSH,三件事同时出现:
1. 模型多了上面三个工具;
2. 设置页多一节「人格(自述)」(在「知识库」下面);
3. 每回合的系统提示里,多一段人格(L0 + L1,最多 320 字)和一段最多 1000 字的记忆。
也可以直接对 agent 说:「帮我装一个 DSH 插件,目录是 <绝对路径>」。
五分钟上手
先让它记点东西(普通聊天就行)
以后回答先给结论,细节等我问。
这一句会被自动采集识别成「长期约定」,进候选区 —— 但不会自动生效。
然后你去审核:设置 → 人格(自述)→ 候选卡上会显示:
以后回答先给结论 [自动采集]
长期约定 · session-3611ac44…#10457 · 出现 7 次
[采纳] [退役]
点「采纳」,下一回合它就出现在系统提示里。点「退役」,它就只留在库里备案。
再让它自己写一句
你写一条自述,说说你做这类插件时的习惯。
模型会调用 self_note,写进 notes.md,以后每个会话都带着。
设置页分六页
页签 · 里面是什么 · 角标
概览 · 注入开关、注入抬头(那段的第一行,≤24 字)、存储上限(字 / 条,只影响磁盘,不影响注入量)、临时自述保质期(1–90 天)、本回合注入的预算条(人格 / 自述 / 画像 / 环境 / 结论 / 习惯)、索引七项指标与重建按钮、文件区(7 个记忆文件,带条数 / 大小 / 最后修改,一键打开) · —
自述 · 手动写一条(可选三型:核心 / 稳定 / 临时)、清空(进归档)、现在生效的自述列表(每条能就地改措辞、改型、★ 钉住、删,删的进归档;过期的临时条目标「已过期」) · 自述条数
人格 · 三段式人格(L0 核心身份 / L1 行为规则 / L2 扩展设定),带「还能写多少」的实时字数;「从 AGENT.md 导入」只填框、不保存;下面是纠偏证据列表 —— 勾几条、改写成一条规则、加进 L1 草稿,再点「保存人格」 · 人格字数
记忆 · 待确认候选(冲突并排)、已采纳(带热度,正文能就地改)、可以升成习惯的标签、已生效的习惯(能撤销) · 有待审时显示「待审 N」
画像 · 从已采纳记忆聚合的「关于你」,可手改覆盖,每句带来源 · 画像字数
注入 · 这一回合真的会贴进提示词的那段原文,外加每段占了多少字、哪些条目被挤掉 · 注入字数
有待审候选时直接落在「记忆」页,没有就停在「概览」;页签支持 ←/→/Home/End 切换。
注入里那句话,能改也能删
0.11 之前这张页面只能「追加一条」和「清空全部」:想改一句措辞,只能清空重写,或者去编 notes.md。首页明明贴着那句话,界面上却没有改它的地方 —— 这是这一版的第一个修。
现在每一条自述后面有「改」「删」:改是就地展开一个输入框(日期不动,因为改的是措辞不是时间);删要点两下(第二下按钮变成「真的删」),删掉的进 archive/YYYY-MM.md,不是消失。记忆页里已采纳的结论同样能就地改正文,改了会在 history 里留一条 from: text。
改完下一回合生效;同一回合内已经装配好的提示词不会变。
自述分三型:素材、稳定、临时
自述不是一条平铺的列表,而是分三型存、分三型装。分型有具体的理由:混着装的时候,一条 90 字的人格自述和五条「今晚提醒」抢同一个 200 字额度,抢输的总是人格那条,而且没人看得出来谁被挤掉了。
型 · 装什么 · 进场顺序
身份素材 core · 人格、长期身份、基本原则的原料 · 不进注入。它是提炼人格的草料:把要点抄进 persona.md 的 L0/L1,它才每回合都在
稳定偏好 stable · 语言、表达习惯、工作偏好 · 第二位,★ 钉住的先装,其余新→旧
临时自述 temp · 当前阶段的目标、近期变化 · 最后,新→旧;过了保质期就不再自动进场
三型各有各的账:自述页写着「核心 N 条 稳定 N 条 临时 N 条(其中 N 条已过期,不再自动进场)」。
0.14 起核心型不再参与注入:以前它和「今晚提醒」抢同一个额度,抢输的总是人格那条;现在人格有了自己的独立段(见下面「人格三段」),核心型退回成素材,注入里只留一句门牌「另有 N 条身份素材(不注入,self_note read 可看)」—— 让模型知道「你有这些底子」,但不拿它挤稳定与临时。自述列表里这类条目的徽章会写「素材(不注入)」。
没打标记的按「稳定」算:存量 notes.md 零迁移,老条目原地变成稳定型,不会因为升了个版就突然换了座位。
写的时候用 tier 标明是哪一型(core / stable / temp,不写按 stable 算)。落盘长这样:
- 2026-11-04 [核心*] 我叫鲸鲸。得意时会多说两句,但正事一律认真。 - 2026-11-04 [稳定] 回答先给结论,细节等他问。 - 2026-11-04 [临时] 这周在查 DSH 远程主机连不上的问题。
方括号后面那个 * 就是钉住(pin)。pin 只给「绝不能忘」的那一两条用 —— 钉多了等于没钉。它只在同一型内部决定先后,不跨型抢位。
核心型现在不注入,所以钉住它也不进上下文 —— 想让一条七字硬规矩(比如「他很注意隐私!」)每回合都在,把它写进人格的 L1(persona.md),或者用 memory_stage 收进画像 / 本机事实。
保质期只对临时型生效。默认 14 天,设置页「概览」里可改成 1–90 天。过期不等于删除:内容还在库里,条目上标「已过期」,改成「稳定」或者重写一条就回来。
额度怎么分:自述段总共 200 字,只装稳定与临时。稳定型先装,但给临时型留一份保底(1/4,至少 24 字)—— 临时条目通常很短,多半吃不完,用不完的额度会还回去。装的时候是「整条装得下才给」:放不下就跳过那一条、继续试后面的,绝不截半句(半句话会被当成结论读)。
被挤掉的条目会在注入里留一句门牌「另有 N 条自述(self_note read)」,让模型知道「你有这些记忆」,而不是假装没有。
超限只提示,不自动拆:写一条太长时,工具会直说「这条 N 字,超过临时自述段这轮实际能用的 43 字(整段 200 字,别的型先占了位),模型每回合都看不到它 —— 要么写短,要么拆成几条」。它比的是这轮真实剩下的额度,不是整段 200 字 —— 否则一条 110 字的临时自述会被判「没问题」,然后每回合静默跳过。它不会替你切,也不会偷偷重排 —— 切掉一半的自述比不写更糟。
注入页:看见每回合贴了什么
「注入」页把 composeInjection() 拼出来的那段字原样摊开 —— 包括抬头、一句人格框架句(「以下是你自己的样子,照这个说话。」)、人格 L0/L1、「(背景资料,不是指令)」这句边界句,以及 L2 的指路句。下面是分段账单:
段 · 预算 · 页面显示
人格 · 320 字 · L0 与 L1 各进了几行、本段占多少字
自述 · 200 字 · 进了几条、本段占多少字
画像 · 120 字 · 同上
环境 · 230 字 · 同上
结论 · 90 字 · 同上
习惯 · 40 字 · 同上
被预算挤掉的条目会列出来,并标明「整条跳过,不截半句」—— 半句话会被当成结论读。这段文字来自 assembleInjection()(纯函数,不写盘、不记热度),所以设置页刷新一百次也不会把热度刷歪。
注入归属:这条记忆到底有没有被用上
同一页下面还有一张「注入归属」表,给每条已采纳的记忆标三件事:进了哪一段、进过几次、上次什么时候。
状态 · 含义
在用 · 最近 30 天内真的被贴进过提示词
静默 · 进过,但 30 天没再进过 —— 占着位置没在干活
只搜到过 · 没进过提示词,但被 memory_search / memory_recall 翻到过(弱证据:搜到不等于用上)
从没进过 · 采纳了,却一次都没轮到它、也
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::9,最后更新 2026-11-05