DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

TheCarey /

TheCarey/Dsh-GuLu-diary

Verified

A DSH diary plugin that only writes on days worth remembering.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@cefd9d33

dsh-gulu-diary 🐋📔

一个跑在 DSH(DeepSeek Harness)里的独立情感日记插件:每天在自己设定的日界(默认 04:00)之后读一个「04:00 → 次日 04:00」窗口里的会话,先判断这天值不值得写,值得才用完整人格 + 只读记忆写一篇给自己看的日记,存进独立的 diary.db,并导出一份可以直接双击打开的 Markdown。

它不创建、不恢复、不 steer 任何会话;写日记是一次独立的模型调用。

当前版本:0.9.1 | Node ≥ 24 | MIT


它做什么

  • 按窗口采素材:把一天的会话转录(session.v4.jsonl.zstd)解出来,按时间戳逐条过滤,只留 04:00 → 次日 04:00 的内容。
  • 先判定,再动笔:用一次很短的模型调用回答 YES / NO / WAIT。判 NO 就只留一条判定和理由,不生成正文;窗口没结束不判;说话太少不调模型。
  • 三段式记忆注入:先宽召回候选,再让模型挑真正和这天有关的几条,最后动笔前先让模型把那天想明白(四小节,内部留档)。
  • 独立存储:日记写在自己的 diary.db,正文另存 日记/YYYY-MM-DD · 标题.md;和记忆库完全分离。
  • 可审计:每次生成的素材、信号、两段提示词、模型原始返回、记忆挑选记录、场景理解都留在 pending/<日期>/,生成日志另记一份。
  • 素材自动清理:pending/<日期>/ 默认保留 7 天,到期只删素材目录,不碰日记正文和 .md。
  • 设置页:DSH 设置里的「日记本」可以按日期阅读、切模型、看待写日期和本次注入了几条记忆。

它不做什么

  • 不创建 / 恢复 / steer 会话,请求里不带 sessionId。
  • 不写记忆库:memory.db 一律 readOnly: true + PRAGMA query_only 打开,读完即关。
  • 不联网上传日记,不发消息,不做云同步。
  • 不保证每天一篇——「不值得写」是这个插件的正常结论之一。

工作链路

DSH 启动 / 每 15 分钟
  → prepareDue:日界后缺哪天 → 采素材 + 拼基础提示词 + 压一份 ≤2000 字判定信号
  → judgeDay:只在窗口关闭后判;说话 < 3 句直接跳过,不调模型
  → WAIT:素材像半截,不记判定,下个 tick 再问(连续两次后要求给结论)
  → NO:写判定结果,素材留着,不写正文
  → YES:
      loadPersona(完整读取人格文件,不改写、不概括)
      recallMemoryCandidates(只读 memory.db,soul 全收 + 关键词/项目名/标题打分,上限 60)
      selectMemoriesWithModel(素材摘要 + 候选清单 → 挑 5–12 条)
      buildUnderstanding(素材 + 挑中的记忆 → 四小节场景理解,内部留档)
      buildGroundedPrompt(system = 人格 + 挑中的记忆;user = 写法 + 素材 + 场景理解)
      ctx.llm.stream(独立调用,不带 sessionId)
      校验 frontmatter / 日期 / 视角
  → diary.db + 日记/YYYY-MM-DD · 标题.md + pending/<date>/ 留档
  → 每个 tick 末尾:清理超过 retentionDays 天的 pending 素材

每一天只判一次:判定结果落在 diary_verdicts,下个 tick 甚至重启之后都直接复用。想重判用 CLI 的 judge --force。

两个降级,不挡成篇

  • 记忆挑选失败(超时、读不懂、id 全对不上)→ 降级成「soul 全部 + importance 最高的 3 条 user」。
  • 场景理解失败或四小节不齐 → 丢掉它,直接拿素材写。

两种降级都会写进 generation.log 和 pending/<date>/meta.json 的 degradedSteps,设置页详情能看到。


安装

1. 依赖

  • Node ≥ 24:用到 node:sqlite、node:zlib 的 zstd 解码。
  • 一个能跑 DSH 插件的 profile,并具备 llm、tools、webServer、settings 这几项服务。
  • 可读的会话转录目录(sessionsDir)和人格文件(persona.path,默认 ~/.dsh/AGENT.md)。
  • 一个 meow-memory 风格的 memory.db(见下面「记忆库约定」)。

2. 放进 profile

手动三步:

  1. profile 的 package.json:dependencies 里加 "dsh-gulu-diary": "link:<这个目录的绝对路径>",并把 dsh-gulu-diary 加进 dsh.profile.bundles。
  2. profile 的 cordis.patch.yml:加一条 entry(可以参考仓库根目录的 cordis.patch.yml)。
  3. 在 profile 的 node_modules/ 里建一个指向本目录的链接(Windows 下是 junction)。

或者用脚本(会先备份 profile 的 package.json / cordis.patch.yml,再写配置、建链接、检查 BOM):

node scripts/install-profile.mjs --profile "$HOME/.dsh/profiles/desktop" --package-path .

脚本不会重启 DSH,也不会碰 memory.db。

3. 配置

参考仓库根目录的 cordis.patch.yml。最小可用配置:

- insert:
    - id: dsh-gulu-diary
      name: 'dsh-gulu-diary'
      config:
        enabled: true
        dataDir: '~/.dsh-gulu-diary'
        sessionsDir: '~/.dsh/sessions'
        windowStartHour: 4
        persona:
          path: '~/.dsh/AGENT.md'
        memory:
          enabled: true
          dbPath: '~/DSH-Memory/memory.db'
        schedule:
          enabled: true

~ 会展开成当前用户的家目录。配置里支持相对路径,最终都会解析成绝对路径。

4. 重启并确认

inject、工具、路由都是模块级注册,必须重启一次 DSH。重启后看 <dataDir>/plugin-load.log:

  • 有 apply.done;
  • 有 routes.registered 且 failed 为空;
  • 工具列表里出现 diary_*。

再刷新 DSH 设置 → 日记本,能看到库路径和篇数就说明 Host 和前端都挂上了。


配置项

键 默认 说明
enabled true 总开关,关掉后不注册工具/路由/调度
dataDir ~/.dsh-gulu-diary 日记库目录(diary.db、pending/、日记/、日志都在这里)
sessionsDir ~/.dsh/sessions DSH 会话转录根目录,只读
windowStartHour 4 一天从几点开始算(0–23),默认凌晨 4 点
persona.path ~/.dsh/AGENT.md 人格文件,整篇原样进 system prompt
memory.enabled true 关掉会拒绝生成(不允许裸模型写日记)
memory.dbPath ~/DSH-Memory/memory.db 记忆库路径;也可用环境变量 DSH_DIARY_MEMORY_DB 指定
memory.maxEntries 20 最终注入的记忆条数上限
memory.maxChars 6000 最终注入的记忆总字数上限
memory.recallLimit 60 第一段召回候选的上限,只求不漏
memory.pickMin / pickMax 5 / 12 第二段让模型挑几条
memory.pickerMaxTokens 1200 挑选那一次调用的 token 上限
memory.pickerTimeoutMs 120000 挑选超时
understanding.maxTokens 900 场景理解的 token 上限
understanding.timeoutMs 180000 场景理解超时
schedule.enabled false 定时器;cordis.patch.yml 里默认开成 true
schedule.checkMinutes 15 多久检查一次缺哪天
schedule.maxCatchUpDays 7 关机期间最多补几天
generation.enabled true 关掉后仍准备素材,但不调模型、不判定
generation.provider / model 留空 留空 = 跟随 DSH 当前主模型;填的话两个都要填
generation.reasoningEffort 留空 可选推理档
generation.maxTokens 4096 正文最大 token
generation.timeoutMs 180000 正文超时
generation.retries 2 失败重试次数
judge.minUserMessages 3 当天用户说话少于这个数就不调模型,直接跳过
judge.maxSignalChars 2000 判定信号硬上限
judge.maxTokens 400 判定回答很短,给少一点
judge.timeoutMs 60000 判定超时
retentionDays 7 pending 素材保留天数;0 = 不自动删

CLI

不走 DSH 进程也能核对素材、调判定标准、手动补写。所有命令默认只写 --data-dir 和必要的 output/,不碰 memory.db。

$NODE = "node"
$DATA = "$HOME/.dsh-gulu-diary"
$SESS = "$HOME/.dsh/sessions"

# 采素材(只读转录,不写日记)
& $NODE src/cli.js collect --date 2026-11-01 --sessions-dir $SESS --print-prompt

# 把素材和提示词放进 pending/
& $NODE src/cli.js prepare --date 2026-11-01 --sessions-dir $SESS --data-dir $DATA

# 只判定,不写正文;--force 忽略已有判定重判
& $NODE src/cli.js judge --date 2026-11-01 --force --data-dir $DATA --sessions-dir $SESS `
    --base-url http://127.0.0.1:8080/v1 --model your-model --api-style chat

# 手动写一篇:先判定,判 skip 就不写;--force 无视判定强写
& $NODE src/cli.js generate --date 2026-11-01 --data-dir $DATA --sessions-dir $SESS `
    --base-url http://127.0.0.1:8080/v1 --model your-model

# 只跑记忆筛选,打印挑中/丢掉和原因(不写日记、不写 pending)
& $NODE src/cli.js select --date 2026-11-01 --data-dir $DATA --memory-db "$HOME/DSH-Memory/memory.db"

# 素材保留期:先干跑,再真删(只动 pending/<日期>/)
& $NODE src/cli.js cleanup --dry-run --data-dir $DATA
& $NODE src/cli.js cleanup --days 7 --data-dir $DATA

# 其他
& $NODE src/cli.js pending --data-dir $DATA
& $NODE src/cli.js list --data-dir $DATA
& $NODE src/cli.js read 2026-11-01 --data-dir $DATA
& $NODE src/cli.js search 关键词 --data-dir $DATA
& $NODE src/cli.js hooks --data-dir $DATA
& $NODE src/cli.js plan --now 2026-11-05T10:00:00+08:00
& $NODE src/cli.js doctor --data-dir $DATA

judge / generate / select 都需要一个 OpenAI 兼容端点(--base-url、--model、--api-key、--api-style chat|responses);也可以在环境变量里给 DSH_DIARY_JUDGE_URL / DSH_DIARY_JUDGE_MODEL / DSH_DIARY_JUDGE_API_KEY。


设置界面「日记本」

重启后出现在 设置 → 日记本(client 端的 settings.section)。只读为主:

  • 顶部:库路径、日记/ 路径、总篇数、素材保留天数。
  • 写日记用的是谁:默认「跟随 DSH 当前主模型」,也可以按 provider 挑具体模型和推理档;选中即写回 profile 配置,热生效。
  • 列表:按日期倒序,只取元数据,不点开不加载正文。
  • 被跳过的日子:列表里一行淡字(11-03 无值得一提的事 · 理由),不会被误看成漏写。
  • 详情:按标题 / 段落 / 引用渲染;有 pending 时顶部可以「现在生成一篇」。
  • 日记正文只读,不提供编辑/删除,也不自动打开资源管理器。

HTTP 接口(列表/详情只读;生成和模型切换是显式写操作):

GET  /gulu-diary/api/list
GET  /gulu-diary/api/detail?date=YYYY-MM-DD
GET  /gulu-diary/api/pending
POST /gulu-diary/api/generate   {"date":"YYYY-MM-DD"}
GET  /gulu-diary/api/models
GET  /gulu-diary/api/model-info?provider=...&model=...
POST /gulu-diary/api/model      {"mode":"follow"} 或 {"mode":"explicit", ...}
GET  /gulu-diary/api/health

list 不返回 content,只带 pending 和 skipped;detail 才返回全文。模型接口只接受 ctx.llm 当前目录里真实存在的组合。


数据在哪

<dataDir>/
├── diary.db                 日记库(独立 SQLite,不是记忆库)
├── 日记/
│   └── YYYY-MM-DD · 标题.md  可直接双击阅读的正文
├── pending/<日期>/          素材与留档,默认保留 7 天
│   ├── materials.md          素材原文
│   ├── signal.md             判定用的 ≤2000 字信号
│   ├── prompt.md             基础写作提示词
│   ├── prompt.system.md      实际注入的人格 + 记忆
│   ├── prompt.user.md        实际注入的写法 + 素材
│   ├── prompt.grounded.md    system + user 合并
│   ├── response.md           模型原始返回
│   ├── understanding.md      动笔前的四小节场景理解(内部)
│   ├── memory-selection.json 候选 / 挑中 / 丢掉 + 理由
│   ├── attempts.json         重试记录
│   ├── error.json            终态错误
│   └── meta.json             status / diaryId / 模型 / 各种 hash
├── generation.log            每次判定与生成
└── plugin-load.log           插件加载与路由注册

diary.db 里除了日记本身,还存了生成记录(人格文本与 hash、注入的记忆 id、候选/挑中/丢掉、两段提示词 hash、模型原始返回 hash、是否降级),用来回答「这篇到底是怎么写出来的」。


记忆库约定

插件只读,不 import meow-memory,也不调用任何写方法。需要的是一份 meow-memory 结构的 SQLite:

表 需要读的列
soul id、title、content、importance、keywords、status、created_at
user 同上
project 同上,另加 project、subcategory

只取 status = 'active' 且 created_at <= 当天窗口结束 的条目。没有 soul 条目、或者 memory.db 里一条 active 记忆都没有时,生成会明确报错而不是悄悄写一篇没有记忆的日记。

不想用记忆注入的话,别把 memory.enabled 设成 false——那会直接拒绝生成。正确做法是准备一个只有一条 soul 的最小库,或者改代码。


提示词

prompts/ 下四个文件都是纯文本,改提示词不用改代码:

文件 用在哪
diary-zh.md 写正文
judge-zh.md 判「值不值得写」
memory-picker-zh.md 从候选里挑记忆
understanding-zh.md 动笔前的四小节场景理解

它们默认是中文、并且带着一套具体的人设(咕噜 / 主人)。人设来自你自己的 AGENT.md,代码不硬编码称呼;把这四个文件换成你自己的人设和口吻即可。


隐私与隔离

  • 会话转录只读,不复制进仓库;测试夹具全是合成数据。
  • memory.db 只读打开,读取前后会记文件 hash,生成记录里如实写 memoryUnchanged。
  • 素材清理只删 <dataDir>/pending/<YYYY-MM-DD>/:目录名必须是真实日期、解析后必须仍在 pending 根下、符号链接跳过;diary.db、日记/*.md、memory.db 不在删除逻辑的任何分支里。
  • .md 文件名会过滤 Windows 非法字符,中文标题保留。
  • 生成失败保留 pending 和错误日志,不写空日记、不写「占位」正文。
  • 视角自检:正文里出现「用户说」「作为 AI」「第三人称提自己」这类口径错位会重试一次;仍然不对就标记 needs-review,不写库,等人工看。

测试

npm test          # 等价于 node --test --test-isolation=none

当前 132 项,全过(Node 24.21.0)。覆盖采集窗口与 04:00 日界、判定闸门与 WAIT、信号压缩、三段记忆链路、降级路径、场景理解四小节、保留期删除边界、HTTP 路由、CLI 端到端、Zstd 多帧解码、插件配置与工具接口。


已知限制

  • 必须有记忆库:设计上不允许「没有记忆的裸模型」写日记,缺库/空库会报错。
  • 只在 DSH 里验证过:插件依赖 DSH 的 ctx.llm、tools、webServer 和 settings.slot;DSH 改接口签名需要跟着改。
  • 安装脚本偏 Windows:install-profile.mjs 用 junction;核心逻辑是普通 Node,跨平台,但安装那一步在 Windows 上最顺。
  • 提示词是中文的:想写别的语言,需要自己换四个 prompt 和校验规则。
  • 成本:一次成功生成 = 判定 + 记忆挑选 + 场景理解 + 正文,共四次模型调用;判定为 NO 时只有一次。端点慢的时候挑选/理解会降级,不会挡住成篇。
  • 定时器只在 DSH 运行时工作:关机期间漏掉的日期,启动后按 maxCatchUpDays 补,补写同样先判定再写。

许可

MIT。见 LICENSE。

—/ 5

No ratings yet

Verified DSH bundle

Commit cefd9d33d6a5

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout