为 DeepSeek Harness 补上有界、分层、带审批门、可审计的跨会话记忆:本地 SQLite 存储、memory 工具与每次会话启动注入的冻结快照。
- 语言
- JavaScript
- License
- Apache-2.0
- 分支
- main
安装
$ dsh plugin --profile web add github:PerryLink/dsh-memento在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程
一句话定位
dsh-memento 是 DeepSeek Harness 的跨会话记忆能力接缝插件。它把记忆做成一项类型化服务(ctx.memory),让 DSH 在每次新会话启动时自动把过往偏好与项目约定注入系统提示词,并在每次写入前强制走人类审批门。
核心能力
- 通过
memory工具在会话内新增、改写、删除、整合或检索记忆条目,全部写入路径走统一审批门 - 在每个会话首次组装提示时,把当前记忆的快照冻结并注入 systemPrompt,会话内不再变化
- 每条写入都落审计行(含被拒绝的情况),并通过审批对把完整载荷写入会话日志,可事后重建
- 维护两个轨道(user / agent)×两个层(user-global / workspace)×按 agent 隔离的记忆空间,硬字符预算防止溢出
- 通过
ctx.memoryAdapters注册表接入第三方记忆格式(mem0、Hermes memory.md、CLAUDE.md),导入导出均经审批 - 会话压缩成功后自动生成待审批记忆提案,需用户确认才会落地
技术实现
- 语言: JavaScript(纯 ESM,
.mjs;无 TypeScript 编译步骤,类型契约由.d.ts提供) - 关键依赖:
@deepseek-ai/cordis、@deepseek-ai/dsh-tools、@deepseek-ai/dsh-session、node:sqlite(Node 内置 SQLite 同步驱动) - 架构模式: 三角色 seam —— Service Definition(
ctx.memory,index.mjs中的MemoryService)+ Provider(lib/store.mjs本地 SQLite,WAL 模式,权限 0600)+ Consumer(memory工具 +systemPrompt.section冻结快照);通过inject: ['tools', 'systemPrompt', 'approval']接入宿主,禁用(enabled:false)时整套能力整体消失 - 入口文件:
index.mjs(插件唯一面向宿主的文件,lib/保持零 DSH 依赖)
适用场景
当你希望 DSH 跨会话记住用户偏好(语言、风格、雷区)、项目约定(构建命令、目录结构)和已学到的教训,但又不想让模型自己悄悄往系统提示里塞东西时,本插件提供"先审批、后落盘、可审计"的工作流。它尤其适合需要长期维护同一项目的开发者和团队——下次打开 DSH 时无需重复交代背景,所有上下文都已按层就绪。
前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DeepSeek Harness | 0.1.0-rc.6+ | package.json#dshWorkshop.compatibility.dshVersions 声明 |
| Node | ^22.19.0 || >=24.0.0 | package.json#engines.node |
| 平台 | 跨平台 | Windows / macOS / Linux 均可,零原生代码编译 |
| 原生模块 | node:sqlite | Node 内置 SQLite 同步驱动,零外部原生依赖 |
| Peer 依赖 | @deepseek-ai/cordis ^4.0.1、@deepseek-ai/dsh-tools >=0.1.0-rc.6、@deepseek-ai/dsh-session >=0.1.0-rc.6、@deepseek-ai/schemastery >=3.0.0 | 由宿主提供 |
安装方式
dsh plugin --profile web add github:PerryLink/dsh-memento
配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
enabled | 布尔 | 总开关;设为 false 后工具、注入、服务、审批 answerer 全部消失 | true |
dbPath | 字符串 | 记忆库文件绝对路径;留空走 $DSH_HOME/dsh-memento/memory.db(Windows 上 $DSH_HOME 缺失时回退到 ~/.dsh) | '' |
budgets.user.userGlobal | 数字 | 用户相关事实的"全局"层硬字符预算 | 2000 |
budgets.user.workspace | 数字 | 用户相关事实的"工作区"层硬字符预算 | 2000 |
budgets.agent.userGlobal | 数字 | 环境/项目事实的"全局"层硬字符预算 | 4000 |
budgets.agent.workspace | 数字 | 环境/项目事实的"工作区"层硬字符预算 | 4000 |
writePolicy | ask | auto | off | 全局写审批策略(模型不可见、不可改) | ask |
writePolicies | 字典 | 粒度写策略,键可为 track/scope 或 source:<name> | {} |
language | en | zh | 快照文案、/memory 命令、工具描述、面板的语言 | en |
snapshotOrder | 数字 | 快照段在 systemPrompt 中的顺序(数值越小越靠前) | -50 |
maxEntriesPerQuery | 数字 | memory query 单次默认返回上限(Provider 硬钳 1000) | 20 |
commandListLimit | 数字 | /memory list / query 单次渲染条数 | 50 |
commandAuditLimit | 数字 | /memory audit 单次渲染审计行数 | 10 |
recall.historyLimitDefault | 数字 | memory_recall 工具默认扫描的历史会话数 | 8 |
recall.snippetCap | 数字 | 每个会话返回的历史片段上限 | 5 |
recall.snippetChars | 数字 | 每个片段字符数上限 | 300 |
recall.windowDays | 数字 | 历史片段回看天数 | 30 |
panelEntriesLimit | 数字 | Web 面板条目分页大小 | 200 |
panelAuditLimit | 数字 | Web 面板审计默认条数 | 20 |
auditRetentionDays | 数字 | 审计行保留天数,0 表示永久保留 | 0 |
proposals.enabled | 布尔 | 会话压缩后是否自动生成待审批提案 | true |
proposals.maxChars | 数字 | 单条提案字符上限 | 2000 |
proposals.maxPending | 数字 | 待审批提案数量上限 | 8 |
常见问题
Q: 写满了会怎样?会自动压缩吗?
A: 不会自动压缩。超过预算会抛 BUDGET_EXCEEDED 结构化错误(携带当前用量与上限)。请先用 consolidate 把多条合并,或用 remove 删掉不需要的条目,再重新写入。Provider 层从不静默截断。
Q: 模型能绕过写入审批吗?
A: 绕不过。审批门做在 ctx.memory 服务的写方法内部(MemoryProtocolCore),不在工具层。任何路径(memory 工具、/memory 命令、未来其它插件)只要调 add/replace/remove/seed 都必须经过 ctx.approval.request;writePolicy 是模型不可见的配置。
Q: 记忆数据存放在哪里?会上传网络吗?
A: 默认存放在 $DSH_HOME/dsh-memento/memory.db,POSIX 权限 0600,纯本地 SQLite。插件 manifest 显式声明 network:none / credentials:none,整个生命周期不发起任何网络请求。
Q: 卸载插件会丢失记忆数据吗?
A: 不会丢失。dsh plugin --profile web remove dsh-memento 仅卸载插件,SQLite 数据库与会话日志都保留。插件也从不向会话日志 append 未注册类型的事件,因此旧会话可以正常加载。
Q: 会话中途修改记忆,模型的快照会立刻更新吗?
A: 不会。快照在每个会话首次组装 systemPrompt 时冻结一次,会话中途的写入只落盘和审计,不回写到已注入的 system 段——这是为了稳定前缀缓存,也是"模型可见即会话日志可重建"的一部分。
Q: 支持中文(CJK)记忆条目的子串搜索吗?
A: 支持。检索使用大小写不敏感的 instr 而非 FTS5,因为 SQLite 内置分词器对单字 CJK 字符索引不友好;instr 对中文场景天然正确,且对插件零依赖。
Q: 同一个 $DSH_HOME 下两个 DSH 进程同时写会怎样?
A: SQLite 通过 busy_timeout 串行化单进程内的写入;跨进程一致性不保证,先写者赢。这是 SQLite 文件共享的固有行为,与 Hermes 等终端记忆的官方警告一致。
Q: 和官方推荐的 MCP 记忆服务器是什么关系?
A: 可以共存。dsh-memento 是 DSH 原生的本地第一方实现(零网络、不依赖外部进程),MCP 记忆是官方文档建议的外部服务器路线;两者同目标、不互斥,用户可按场景任选其一或同时启用。
上手难度
进阶 — 配置项较多(预算、审批策略、适配器),但默认配置即可直接使用;进阶用户需要理解"轨道 × 层 × agent 隔离"模型与审批 waterfall 才能调出最贴合的策略。
已知问题与限制
- rc.6 会话事件未实际发出:插件在
types.d.ts声明合并了memory/added|updated|removed|recalled|snapshot五种 SessionEventMap 词汇,但 DSH 0.1.0-rc.6 没有插件事件注册面,运行时默认不 append;审计链由审批对的approval/asked+approval/decided与插件自有审计表承担,等 harness 收录memory/*后自动开启。 ask策略需要人类 answerer:当 profile 未配置 UI/ACP 形式的审批回答者时,ask策略下的写入会失败关闭;如需无人值守写入请改为auto,或显式用off整体关停。- 无 FTS5 索引:检索走
instr子串匹配(大小写不敏感,对 CJK 友好);大数据量场景下查询效率低于全文检索,可通过limit参数缩小范围。 - 跨进程共享同一
$DSH_HOME时存在竞态:SQLite 文件锁保证单进程内串行,但跨进程一致性不保证;多终端同时编辑同一目录需要自行协调。
dsh-memento
Bounded, layered, approval-gated, auditable cross-session memory for DeepSeek Harness.
A typed ctx.memory seam, a write-approval gate no model path can bypass, and audit trails rebuilt from the session log.
Compatibility
| Surface | Status |
|---|---|
| Harness | DeepSeek Harness 0.1.0-rc.6 |
| Node | `^22.19.0 |
| Platforms | Windows / macOS / Linux (pure host; no native code, no network) |
| Model | Any |
What you get
dsh-memento is a capability seam, not another memory warehouse: a typed ctx.memory service, a local SQLite provider (node:sqlite, WAL, 0600, at $DSH_HOME/dsh-memento/memory.db), and its consumers — the memory tool and a frozen snapshot injected into the system prompt.
- The approval gate cannot be bypassed. Every write path (
add/replace/remove/seed) is forced through the approval waterfall inside the service, not in the tool layer.writePolicy: ask | auto | offis model-invisible configuration;replace/remove/consolidatecarry the full text of the entries they change in the approval payload, and a denied write still lands a*-deniedaudit row. - Model-visible ⟺ logged. The injected snapshot lands verbatim in
request/header.system; every write is reconstructable fromapproval/asked+approval/decided+ the plugin's own audit table. - Bounded and honest. Hard per-track/per-layer character budgets (default user 2000 / agent 4000). A full store fails with a structured error (usage + limit) — never truncated, never auto-compacted.
Two tracks × two layers × per-agent key: a user track (facts about the user) and an agent track (environment facts and conventions), each split into user-global and workspace layers, isolated per agentPreset. The snapshot is frozen once per session at first prompt assembly and never changes mid-session.
Quick start
# 1. install the bundle into your profile
dsh plugin --profile web add "github:PerryLink/dsh-memento#main"
# or from npm (published releases)
dsh plugin --profile web add dsh-memento
# 2. restart and verify the row
dsh --profile web --dump-config | grep -A3 'id: memento'
Install & uninstall
- git channel (latest
main):dsh plugin --profile web add git+https://github.com/PerryLink/dsh-memento.git. - npm channel (published releases):
dsh plugin --profile web add dsh-memento. - tarball channel:
npm packin this repo, thendsh plugin --profile web add ./dsh-memento-<version>.tgz. - uninstall:
dsh plugin --profile web remove dsh-memento(the memory database and session logs are kept).
Configuration
All tunables are Schemastery Config fields (changeable from cordis.yml). Invalid values fail loudly at load. Override under the memento row.
| Key | Default | Meaning |
|---|---|---|
enabled | true | Master switch; false removes the service, tools, snapshot, command, panel, and answerer |
dbPath | '' → $DSH_HOME/dsh-memento/memory.db | Absolute, or relative to $DSH_HOME (falls back to ~/.dsh on Windows) |
budgets.user.userGlobal | 2000 | Hard character budget for the user track's user-global layer |
budgets.user.workspace | 2000 | Hard character budget for the user track's workspace layer |
budgets.agent.userGlobal | 4000 | Hard character budget for the agent track's user-global layer |
budgets.agent.workspace | 4000 | Hard character budget for the agent track's workspace layer |
writePolicy | 'ask' | Default write policy: ask / auto / off (model-invisible) |
writePolicies | {} | Per-track/scope or per-source overrides (e.g. user/workspace, source:claude) |
language | 'en' | Model-visible and command output language: en / zh |
snapshotOrder | -50 | Snapshot section order (after harness identity, before persona) |
maxEntriesPerQuery | 20 | Default per-query result cap (hard-capped at 1000) |
commandListLimit | 50 | Entries rendered per /memory list / query |
commandAuditLimit | 10 | Audit rows rendered per /memory audit |
recall.historyLimitDefault | 8 | memory_recall sessions scanned by default |
recall.snippetCap | 5 | memory_recall snippets per session |
recall.snippetChars | 300 | memory_recall snippet characters |
recall.windowDays | 30 | memory_recall recency window in days |
panelEntriesLimit | 200 | Web panel entries page size |
panelAuditLimit | 20 | Web panel audit rows by default |
auditRetentionDays | 0 | Audit retention (0 = keep forever) |
proposals.enabled | true | Auto-capture a memory proposal after each successful compaction |
proposals.maxChars | 2000 | Proposal character cap |
proposals.maxPending | 8 | Pending proposal cap |
Tools & surfaces
| Surface | Kind | Notes |
|---|---|---|
memory | tool | add/replace/remove/consolidate/query with Save/Skip guidance; writes ride the approval gate |
memory_recall | tool | Bounded memory matches plus recent session-history matches |
/memory | command | list · query · add · remove · consolidate · proposals · budgets · audit · export · import <path> · adapters |
| web panel | client drawer | Read-only: browse entries, search, budget bars, audit tail |
How it's different
| Plugin | What it is | dsh-memento's difference |
|---|---|---|
| dsh-memory-evolve | memory warehouse / evolution loops | a typed service seam, approval gate, and session-log audit; no warehouse ambition |
| dsh-mnemon | memory store helper | protocol + gate + audit, not another store |
| dsh-kb-sieve | knowledge-base sieving | no retrieval engineering: small-corpus substring search, cross-session recall via session_search/sessionQuery |
| dsh-tdai-memory | task-driven memory tooling | budgets are per track×layer and enforced in the service, not best-effort |
| claude-bridge | Claude Code bridging | DSH-native; a future seed(source:'claude') path lets a bridge feed the same store |
| dsh-external/Recall | external agent memory | local-first, zero-network, rides DSH's own approval seam |
| Official MCP memory examples | DSH's stated "memory = external MCP" position | the native first-party complement: same goal, no external server; both coexist |
The name is dsh-memento (published on npm and GitHub). Not dsh-recall (confusable with dsh-external/Recall), not the deleted legacy name dsh-memory.
dsh-memory-protocol v1
dsh-memento is the community rehearsal of the DSH memory protocol — a candidate shape for an official ctx.memory seam. The protocol normalizes this plugin's seam into a cross-plugin contract:
-
Entry spec — two tracks × two layers × per-agent key, plus short
tags(≤16 × ≤32 chars) and a per-entryversionthat increments on everyreplace. -
Write semantics — idempotent unique-substring conditional writes; approve-what-you-see payloads (
replace/remove/consolidatecarry the full text they change). -
Audit contract — every write reconstructable from
approval/asked+approval/decided+ the provider ledger. -
Budget model —
BUDGET_EXCEEDED/AMBIGUOUS_MATCHsemantics. -
Schema versioning — migration rules with loud version checks.
-
Spec — docs/protocol-v1.md (中文: protocol-v1.zh.md); normative JSON Schema at docs/schemas/dsh-memory-protocol-v1.schema.json.
Adapter registry — ctx.memoryAdapters (register / list / adapt / export) lets third-party memory plugins speak the protocol by registering a pure data converter (reversible register(); import rides the approval-gated seed, export is read-only). Onboarding: docs/adapters-guide.md (中文: adapters-guide.zh.md).
| Built-in adapter | External format | Notes |
|---|---|---|
mem0 | mem0 fact collections ({facts: [{memory, metadata?}]}) | metadata.category / metadata.tags become tags; raw messages arrays are rejected — adapters convert, never extract |
hermes-memory-md | Hermes memory.md (## section + bullets) | section names become tags; non-bullet prose fails loudly |
claude-code-memory-md | CLAUDE.md-style markdown (headings, bullets, paragraphs) | bullets and paragraphs become entries; section names become tags |
Conformance suite — test/protocol-conformance/: a distributable case set any provider claiming compatibility runs (node test/protocol-conformance/run.mjs --provider ./your-factory.mjs); this repo's CI runs it against its own provider as the golden reference (npm run test:conformance).
- Upstream proposal — docs/upstream-proposal.md (中文: upstream-proposal.zh.md): why the official
ctx.memoryseam should adopt the protocol, the differences, and the migration path.
Permissions & data
- Permissions: declares
harness:tool,filesystem:read,filesystem:write, andnetwork:none/subprocess:none/shell:none/python:none/credentials:nonein its workshop manifest. Write approval rides the official approval seam. - Data: local SQLite database (
0600), zero network, zero credentials. - Session log: audit completeness comes from the approval pair (
approval/asked+approval/decided) plus the plugin's own audit table.
Security boundaries
- Public services only. Consumes
tools,systemPrompt, and the approval seam; no engine / agent-loop / apiproxy / official-UI changes. - Zero network, zero credentials. Local database with POSIX file mode
0600. - Fail loud. Corrupt DB, newer schema, or invalid config fails at load; full budgets and ambiguous substring matches fail with structured errors.
- One process, one store. Multiple sessions share the SQLite store; two processes sharing one
$DSH_HOMEwrite the same file (last-writer-wins under SQLite locking).
Known limitations
- Session events are declared, not yet emitted (rc.6).
memory/added|updated|removed|recalled|snapshotare merge-declared, but rc.6 has no registration surface for out-of-repo event types; emission turns on once a harness build registers them. askpolicy needs an answerer. With no UI/ACP answerer composed, writes fail closed.- No FTS5 indexing. Substring search runs on case-insensitive
instr(correct for CJK).
What we learned from the terminal memories
dsh-memento is not a port of Claude Code, Codex, or Hermes — but its design deliberately absorbed the parts each got right, and refused the parts that hurt:
| Terminal memory | What it got right | What dsh-memento adopted |
|---|---|---|
Claude Code — CLAUDE.md | hierarchical plain-text memory files (user-level → project-level), human-readable and human-editable, merged automatically into every session | plain-text entries; user-global / workspace layers merged per session; a store you can browse, export, and audit — transparency as a feature |
Codex — AGENTS.md | per-directory scoped instructions auto-discovered and injected with zero model friction | the workspace layer keyed by the session cwd (Windows case-insensitive); the frozen snapshot injected automatically at session start |
Hermes — memory.md | proactive memory saves and the security lesson that a gate enforced only in the tool layer is bypassable by late tool injection | the memory tool with Save/Skip guidance + approval-gated auto-capture proposals; the gate lives inside ctx.memory's write methods, not in the tool layer |
Sources: Claude Code memory · Codex AGENTS.md · Hermes memory · Hermes #48181.
And the parts deliberately refused: hidden auto-summarization into model-private state (compaction summaries here become pending proposals that wait for a human approve/dismiss), warehouse/vector-store ambitions, and any write that lacks a human-visible approval or audit trail. Also adopted: Hermes's documented caveat that two processes sharing one home directory write the same memory file — see Security boundaries.
Development
npm install # node ^22.19 || >=24
npm test # node --test: 133 tests
npm run test:conformance # dsh-memory-protocol v1 conformance suite
npm run typecheck # tsc --checkJs gate
npm run check:coverage # line-coverage gate
npm run check:readmes # five-language README consistency gate
lib/ is zero-DSH-dependency (node: builtins only); DSH imports exist only in index.mjs.
Topics
dsh, dsh-plugin, deepseek-harness, memory, agent-memory, approval, audit, sqlite, cordis, llm
Contributors
- @Niuniu-Sir — the boot-crash report in issue #1 that led to the
~/.dshfallback shipped in 0.3.1.
PerryLink DSH Plugin Family
This project is one of the 15 DeepSeek Harness plugins maintained by PerryLink. If this one helps you, the others likely will too:
| Plugin | One-liner |
|---|---|
| dsh-mcp-panel | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors |
| dsh-doublecheck | Engineering-discipline guard: requirements grill, test gates, adversary review |
| dsh-background-agents | Durable background child agents with a Web UI sidebar, messaging and interrupt |
| dsh-lsp-actions | LSP diagnostics, formatting, completion, code actions and rename over language servers |
| dsh-output-styles | Claude Code outputStyles-equivalent runtime style switching |
| dsh-checkpoint-rewind | Claude Code /rewind-equivalent: snapshots, session forks, one-shot restore |
| dsh-permission-rules | Claude Code-style declarative allow/deny/ask permission rules with audit |
| dsh-auto-review | Second-model auto-review on the approval chain, fail-closed by default |
| dsh-memento | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool |
| dsh-skill-pack-security | Security-audit skill pack: secret scan, dependency and supply-chain review |
| dsh-session-pin | Pin sessions in the Web sidebar with durable ordering |
| dsh-composer-history | Terminal-style input history for the web composer: arrows, Ctrl+R search |
| dsh-github | GitHub PR/issues integration for DSH, every write gated by approval |
| dsh-plugin-guide | Plugin-development knowledge base as an on-demand agent skill |
| dsh-claude-move | Migrate Claude Code sessions, memory, skills and CLAUDE.md into DSH |
License
Apache License 2.0 © 2026 dsh-memento contributors