dsh-soul-engine
DeepSeek Harness(DSH)的状态面插件:给 AI 伙伴一份可审计的长期记忆、一个能主动开口的机制,以及一本花销看得见的账。
English. A state-plane plugin for DeepSeek Harness: an auditable plain-Markdown memory ledger, per-turn ledger injection, zero-token self-maintenance, an opt-in heartbeat that wakes an existing session (never creates one), a user-state signal layer, and a read-only-by-default sidebar panel. macOS-only extras (desktop notifications, Calendar/Reminders bridge) degrade gracefully on other platforms.
它不是一个"聊天机器人插件",而是补三件常被跳过的事:
| 缺什么 | 后果 | 本插件的做法 |
|---|---|---|
| 工具在,但模型想不起来用 | 主动性形同虚设 | 每轮把账本摘要注入系统提示词 |
| 记忆散在对话里 | 换会话就忘,无法审计 | 落成明文 Markdown 账本 + git 版本化 |
| 主动性没有成本意识 | 静默烧钱、反复打扰 | 四道频率闸 + 预算看门狗 + 可整体关掉 |
三条自我约束(写在数据与代码里,不只是口号):
- 透明优先于「为你好」——不隐藏状态,账本人人可读、可查、可删。
- 一切自主行为自带预算——唤醒次数有闸,花费可见,预算看门狗可开。
- 记忆属于用户——遗忘权是义务:
soul_forget软删,原文留痕,随时可撤销。
安装
# 从 npm
dsh plugin --profile web add dsh-soul-engine
# 或从本地目录 / Git 仓库
dsh plugin --profile web add "file:/path/to/dsh-soul-engine"
dsh plugin --profile web add "github:<owner>/dsh-soul-engine"
确认 ~/.dsh/profiles/<profile>/package.json 的 dsh.profile.bundles 里含 dsh-soul-engine,然后重启 DSH(bundles 在宿主启动时读取)。
验证:新会话里调用 soul_status,应返回账本总览而不是 unknown tool。
停用:从 dsh.profile.bundles 里删掉那一行即可,不必卸载包。
快速开始
soul_init # 第一次:写下灵魂名 + 三条核心目标
soul_status # 每次都先看它:目标进度 / 最近记忆 / 待办 / 一条「此刻最该做的」
soul_remember # 值得记的事随手写一条
14 个工具
| 工具 | 作用 |
|---|---|
soul_init |
初始化账本(灵魂名 / 三条核心目标 / 空账本) |
soul_status |
总览:目标进度、叙事记忆、待办箱、画像,并给出"此刻最该主动做的"一条 |
soul_remember |
写入一条叙事记忆(含 selfState 自我状态标注);pin 可进永久层 |
soul_goal |
内生目标账本:list / add / update / done |
soul_outbox |
主动待办箱:push(可带 dueAt 到点时间)/ list / resolve |
soul_reflect |
规则层反思(零模型成本):高频模式、慢目标预警、待办积压、反馈比例 |
soul_daily |
每日首聊三件事:brief 取三件事并销标记;status 看今天做没做 |
soul_feedback |
正负反馈双轨:record / list / report(含正负比例提示) |
soul_memory |
账本审计(只读):list / get / search / recall / stats / archived / distill |
soul_forget |
记忆状态管理(都可逆,都不删原文):forget / restore / archive / unarchive / list |
soul_signal |
记录用户当前状态(能量 / 忙闲):record / status / clear |
soul_schedule |
macOS 日历 / 提醒事项桥接:today / add / list |
soul_cost |
成本可见(只读):report 今日 / 本月花费与预算余量;days 逐日 |
soul_maintain |
自维护:status 看定时器与最近一次维护;run 立刻跑一次(幂等) |
账本布局
默认落在 $DSH_HOME/soul-data/(未设 DSH_HOME 时是 ~/.dsh/soul-data/),可用 config.dataFile 或环境变量 DSH_SOUL_DATA_FILE 覆盖。
soul-data/
├── memory/ ← 人可读,进 git
│ ├── soul.md 灵魂名 + 三条核心目标
│ ├── profile.json 用户画像
│ ├── goals.md / outbox.md 目标台账 / 待办箱
│ ├── reflections.md 规则层反思留痕
│ ├── feedback.md 正负反馈
│ ├── journal/YYYY-MM.md 叙事记忆,按月分文件、追加式
│ └── archive/YYYY.md 容量淘汰的旧条目(不删,可搬回)
└── runtime.json ← 机器运行计数(心跳 / 信号 / 日程缓存),不入 git
三条设计判据:
- 分流:进 git 的是"值得回看的东西",运行计数走
runtime.json——否则版本历史会被dayCount 3→4淹没。 - 账本独立建仓:不放进项目仓库。项目仓库的提交常被其他工具(如 Hindsight)当作工程知识吸收,私人记忆进去等于双重污染。插件会在维护 tick 里对账本目录做
git add -A并按批提交;.git-dirty与runtime.json通过.git/info/exclude排除,不污染你自己的.gitignore。 - 格式按后果选:解析失败只导致降级的用自由 Markdown;解析失败会导致行为错误的(
outbox到点提醒)用严格行格式。
轮首注入
每轮组装提示词时实时注入账本摘要(主轴目标 / 待主动提的那条 / 最近记忆 / 纪律行),让"主动性"不再依赖模型自己想起来:
【灵魂账本·<名字>】
主轴:[p10 33%] 守护用户长期福祉 —— …当前要事…
待主动提(到点自然说起,一次只提一条):…
最近记忆(10条):…
纪律:行动前先 soul_status;听到偏好/边界/纠正当场 soul_remember…
- 开关:
config.promptSection: false,或环境变量DSH_SOUL_PROMPT=0 - 字数上限:
config.promptMaxChars(默认 1000)——它直接决定每轮的常驻 token 成本,按自己的容忍度调 - 账本不存在时返回空串,由宿主丢弃,不占位
自维护(零 token)
维护 tick 默认每 5 分钟跑一次,纯本地代码,不调用模型:
- 滞留待办自动作废(
staleOutboxDays,默认 14 天) - 每周写一条自动周报进叙事(
weeklyReport) - 叙事巩固 / 淘汰(
consolidate):活跃叙事超过retainMax(400)条时,把既不在最新 400 条内、又老于retainDays(180)天的条目搬进memory/archive/;永久层的(pin过 / value / preference)永不自动搬;一次最多archiveMaxPerRun(50)条 - 账本 git 提交(见上)
度量:soul_maintain action=status。
心跳(会花钱的自主行为,可整体关掉)
心跳让系统在真有事时叫醒一次会话。成本是这条设计的第一约束(复用已有会话,一次完整唤醒约等于 3 轮模型调用;新建会话要贵数倍——所以复用不到就不响)。
每 5 分钟 tick(纯代码,0 token)
→ 四道闸 + 真事判断(全本地计算)
→ 该响才复用已有会话 → 注入一条指令
- 四道闸:安静时段(默认 23:00–08:00 不响)|每天 ≤
heartbeatMaxPerDay(5)|每周 ≤heartbeatMaxPerWeek(15)|距上次 ≥heartbeatMinGapMinutes(60) - 两种真事:① 待办箱里有
dueAt到点的事项;② 到点后「今日三件事」仍未做(heartbeatDailyBrief,默认关) - 启动布防:宿主重启后第一次 tick 只布防不响,避免"重启即打扰"
- 注入的指令自带克制条款:只做这一件事;判断此刻不该说可以只记一笔、不发消息(跳过不算失败)
- 不想被主动打扰:
config.heartbeat: false
预算看门狗(dailyBudgetYuan,默认 0 = 关闭):设成正数后,每 5 分钟读一次 DSH 成本账本,今日花费超过阈值就 ①暂停当天心跳 ②弹桌面通知 ③写一条反思留痕。要不要给自己的自主行为设上限、设多少,由使用者决定,不预设。
右侧栏面板
在右侧栏注册一个「灵魂」页签(带待主动提条数角标),三个 tab:概览 / 成本 / 记忆。
- 数据源是宿主本地路由:
GET /dsh-soul/state、GET /dsh-soul/memories - 记忆 tab 可就地对单条执行遗忘 / 撤销遗忘(
POST /dsh-soul/forget)——这是修正案「记忆属于用户」的界面落地 - 其余写入一律走
soul_*工具,面板不提供任意写操作 - 宿主会在
/tmp/dsh-soul-access.log写一份访问诊断日志(带 512KB 上限),用于区分「浏览器缓存了旧客户端」与「新客户端真出错」
配置
全部参数写在 cordis.patch.yml 的 config 里,改配置即可调,不必动代码。常用项:
| 键 | 默认 | 说明 |
|---|---|---|
dataFile |
$DSH_HOME/soul-data/state.json |
账本位置 |
promptSection / promptMaxChars |
true / 1000 |
轮首注入开关与字数上限 |
maintenance / maintenanceIntervalMs |
true / 300000 |
自维护与 tick 间隔 |
heartbeat / heartbeatMaxPerDay / heartbeatMaxPerWeek |
true / 5 / 15 |
心跳与频率闸 |
heartbeatMinGapMinutes / quietHours |
60 / true |
最小间隔 / 安静时段 |
dailyBudgetYuan / budgetPause |
0(关) / true |
预算看门狗与超预算是否自动刹车 |
consolidate / retainMax / retainDays |
true / 400 / 180 |
叙事巩固 / 淘汰 |
notify |
true |
桌面通知(macOS) |
quietWhenBusy / signalTtlHours |
true / 3 |
忙时顺延 / 信号有效期 |
schedule / scheduleRefreshMinutes |
true / 15 |
日历桥接与缓存刷新 |
环境变量:DSH_SOUL_DATA_FILE(账本路径)、DSH_SOUL_PROMPT=0(关注入)、DSH_SOUL_NOTIFY=0(关通知)、DSH_HOME、DSH_COST_LEDGER(成本账本路径)。
安全与隐私披露
装插件就是在本机跑第三方代码,这份清单请自己核:
- 读写本地文件:默认目录
$DSH_HOME/soul-data/,由宿主进程用node:fs直接读写(不经过会话文件沙箱);soul_cost会读 DSH 成本账本$DSH_HOME/storages/cost-meter/ledger.json;面板路由会写/tmp/dsh-soul-access.log。 - 执行外部命令:账本 git 提交会调
git;桌面通知与日历 / 提醒事项走/usr/bin/osascript(macOS)。非 macOS 平台请设notify: false与schedule: false:通知在非 macOS 上会静默不触发,日历桥接会返回底层命令不存在的错误——两者都不会假装成功。 - 会花钱:心跳唤醒消耗 token。默认每天上限 5 次、每周 15 次;不想被主动打扰设
heartbeat: false。 - 不对外联网:宿主端不做任何出站请求;面板只访问宿主本地的
/dsh-soul/*路由。 - 系统授权:通知需在「系统设置 → 通知」给 DSH 授权;日历 / 提醒事项需在「隐私与安全性 → 自动化」授权。未授权时读返回 0 条、写返回明确的"需要授权"。
- 账本里是你的私人内容:它不会离开本机,但会被注入模型上下文(就是注入段那段),请自行判断哪些内容适合写进去。
平台支持
| macOS | Linux / Windows | |
|---|---|---|
| 14 个工具、账本、注入、自维护 | ✅ | ✅ |
| 右侧栏面板 | ✅ | ✅ |
| 桌面通知(osascript) | ✅ | 不可用 |
| 日历 / 提醒事项桥接 | ✅ | 不可用 |
开发与测试
npm test # 13 个离线脚本:清单闸门、自维护、巩固淘汰、检索、心跳闸、面板真实渲染、迁移……
npm run test:ledger -- <账本路径> # 往返一致性(需要一个真实账本)
测试不依赖 DSH 宿主:用假 ctx 装载插件后逐个执行工具。scripts/verify-manifest.mjs 专门补一个盲区——exports 写错时按文件路径 import 的测试会全绿、但宿主加载整包会失败。
已知取舍(明确写下来,不假装没有):
- 账本 git 提交在维护 tick 里按批做,极端情况下丢最后一次写的提交(与下面这条同源)
- 定时器用同步读写,与工具的异步写之间存在极小概率的丢更新窗口(维护每天只写一两次)
- Markdown 靠约定解析,解析失败即降级(注入段少一行),不会因此崩掉宿主
License
MIT
No comments yet. Be the first to write one.