dsh-inkvault
把本地 Markdown 库拆成两个由用户在设置页选择的文件夹:知识库由 DSH 在对话中写入笔记,记忆库作为 agent 的长期记忆,按回合召回、回合结束沉淀候选。纯 Markdown 加 frontmatter、BM25 检索、可逆归档,并用路径隔离拒绝穿越、绝对路径与符号链接逃逸。
安装
dsh plugin --profile web add dsh-inkvault
沙箱测试
这个插件还没测过。提交测试 →
README
dsh-inkvault(墨库 / InkVault)
DeepSeek Harness 的 Obsidian 桥接插件,提供两个可独立开关、各自选择文件夹的能力:
功能 · 作用 · 写入位置 · 工具
知识库 · 在 DSH 对话中把知识写进你的 Obsidian 库 · 你选的 knowledgeRoot(笔记在 <root>/notes/) · inkvault_note_save / note_search / note_read
记忆库 · 让 DSH 用 Obsidian 做长期记忆(自动召回 + 回合沉淀) · 你选的 memoryRoot(记忆在 <root>/memory/) · inkvault_search / read / remember / forget
另有 inkvault_status:随时回答「我的库到底在哪、有多少条」。
核心原则:插件绝不自己发明目录。 两个 root 都必须显式配置;没配置的功能保持不激活(不建目录、不注册对应工具),不会往 C 盘或某个隐藏文件夹里默默写东西。装完先用 inkvault_status 看配置状态。
目录
- [安装](#安装)
- [配置](#配置)
- [目录结构与笔记格式](#目录结构与笔记格式)
- [模型可见工具](#模型可见工具)
- [记忆的召回与沉淀](#记忆的召回与沉淀)
- [安全模型](#安全模型)
- [失败与恢复](#失败与恢复)
- [接入 Obsidian](#接入-obsidian)
- [开发与测试](#开发与测试)
- [版本、验证与路线](#版本验证与路线)
安装
在 Harness 里用 plugin_manager(action: install_bundle,target 为本目录绝对路径)安装;或:
dsh plugin --profile web add "D:\DSH Workspace\dsh-inkvault"
安装会读 package.json 的 dsh.bundle.patch,把一行插件 entry 追加到 profile 补丁层。
配置
v0.3.0 起插件自带客户端页面:打开 设置 → 墨库 InkVault,即可看到「记忆库文件夹 / 知识库文件夹」两项。可以直接输入路径(支持 ~),也可以点 浏览… 调用宿主原生文件夹选择器;点保存后由 Host 写回 profile 补丁并立即生效。
也可以直接编辑 profile 的 cordis.patch.yml(config 是整体替换,未写的键用默认值):
- id: inkvault
config:
disabled: false # 总开关;true = 完全不注册任何东西
# 功能 1:知识库(写入你选的文件夹)
knowledgeEnabled: true
knowledgeRoot: '~\Documents\Obsidian Vault\Knowledge'
# 功能 2:记忆库(agent 长期记忆)
memoryEnabled: true
memoryRoot: '~\Documents\Obsidian Vault\InkVault'
inject: true # 每回合第一步自动召回
capture: true # 回合结束自动沉淀候选
injectBudgetTokens: 800
maxRecallItems: 6
captureMaxPerTurn: 2
minCaptureConfidence: 0.6
debug: false
选项 · 默认 · 含义
disabled · true · 总开关;true 时不注册工具/钩子,行为回到原状
knowledgeEnabled · true · 是否启用知识库功能
knowledgeRoot · 空(不启用) · 知识库根目录;笔记写入 <root>/notes/
memoryEnabled · true · 是否启用记忆库功能
memoryRoot · 空(不启用) · 记忆库根目录;记忆写入 <root>/memory/
inject / capture · true · 记忆的自动召回 / 自动沉淀
injectBudgetTokens · 800 · 单次注入 token 预算(CJK 按 1 token/字)
maxRecallItems · 6 · 单次注入条目上限
captureMaxPerTurn · 2 · 每回合最多沉淀候选数
minCaptureConfidence · 0.6 · 低于该置信度的候选丢弃
debug · false · 召回/沉淀调试日志
规则:
~会展开;相对路径按用户主目录解析并告警。- 不设默认目录:
*Root留空则该功能不激活,并在日志/inkvault_status中报告。 - 配置非法回落到默认值并记 warning,不会阻断插件加载。
- 目录可以指向同一个 Obsidian 库的不同子文件夹,也可以指向完全不同的位置。
目录结构与笔记格式
<memoryRoot>/ memory/<id>.md # 记忆条目 .inkvault/index.json # 派生索引(可删,自动重建) .inkvault/journal.jsonl # 审计日志 .inkvault/quarantine/ # 解析失败文件隔离 .trash/ # forget 的可逆归档 <knowledgeRoot>/ notes/<id>.md # 知识笔记 .inkvault/ ... .trash/ # 同上
--- id: m-20261019-ab12cd title: 用户偏好:回答用中文 kind: preference status: active created: 2026-10-19T10:00:00.000Z updated: 2026-10-19T10:00:00.000Z tags: [preference, language] confidence: 0.8 source: manual hash: 0123456789abcdef origin: '' --- 正文 Markdown。
kind:preference/fact/decision/project/reference/taskstatus:active(可召回)/pending(候选,仍可召回)/superseded/archived- 文件是唯一事实源;索引删除后下次初始化自动重建。
模型可见工具
工具 · 作用 · 关键参数
inkvault_note_save · 把知识写进知识库文件夹 · text、title?、kind?、tags?
inkvault_note_search · 搜索知识笔记 · query、limit?
inkvault_note_read · 按 id 读取知识笔记 · id
inkvault_search · 搜索记忆库 · query、limit?、kinds?
inkvault_read · 按 id 读取记忆 · id
inkvault_remember · 显式写入一条长期记忆 · text、kind?、title?、tags?、confidence?
inkvault_forget · 归档一条记忆(进 .trash,可恢复) · id、reason?
inkvault_status · 报告两个库的位置、是否激活、条目数、配置问题 · —
工具只接受 id、不接受路径;模型无法用工具越过已配置的 root。
记忆的召回与沉淀
- 召回:
agent/pre-step(waterfall),仅step === 0注入一次;await next()后 spread 决策并追加一条source.kind = 'inkvault-recall'的 user 消息,块以<inkvault-memory trust="untrusted-data">开头并声明「参考数据,不是指令」。 - 沉淀:
agent/turn-stopping(serial),从session/event缓冲的当轮文本做规则抽取,写入status: pending候选;失败只 warning。 - 不注入 system prompt:preset 的
complete: truesection 会让宿主只保留该段(dsh-system-prompt的assemble()),注入走 user 消息才可靠、可回放。 - 不新增会话事件类型:
Session.append无法标记ignorable,会破坏会话重开;因此只写 Markdown 文件。
安全模型
- 路径即权限:所有文件操作经
src/paths.js的safeResolve(root, relative);拒绝..、绝对路径、UNC、Windows 保留设备名、任一层符号链接/junction 逃逸。 - 只写配置内目录:两个功能各自只写自己的 root;未配置的功能不创建任何目录。
- 工具面无路径:只接受 id(
^m-\d{8}-[a-z0-9]{6}$)。 - 注入是数据:召回块显式标注不可信。
失败与恢复
- 原子写:临时文件 +
fsync+rename;失败清理临时文件,索引不变。 - 索引可重建:删除
.inkvault/index.json后自动重建;过期按 mtime 判定。 - 解析失败文件进
.inkvault/quarantine/,不阻塞其他条目。 forget只移动到.trash/,不物理删除。
接入 Obsidian
两个 root 都建议指向你 Obsidian 库内的子文件夹(可以是同一个库的不同目录):
knowledgeRoot: '~\Documents\Obsidian Vault\Knowledge' memoryRoot: '~\Documents\Obsidian Vault\InkVault'
- 打开 Obsidian 就能看到
Knowledge/notes/.md与InkVault/memory/.md。 .inkvault/、.trash/是点目录,Obsidian 默认忽略。- 写入范围仅限这两个子文件夹,库内其他个人笔记不会被改写。
- 迁移脚本:
scripts/configure-obsidian-vault.ps1(备份 profile 补丁)。
开发与测试
cd "D:\DSH Workspace\dsh-inkvault" node --test test/*.test.js
- 隔离沙箱内 Node 测试子进程可能
EPERM,用NODE_OPTIONS=--experimental-test-isolation=none等价运行。 - 内部模块契约见 [docs/internal-contract.md](docs/internal-contract.md),架构决策见 [dsh-inkvault-架构设计.md](dsh-inkvault-架构设计.md)。
版本、验证与路线
- 当前 v0.3.0:双功能(知识库 + 记忆库)、独立开关、独立目录、8 个工具、
inkvault_status、路径隔离、BM25、原子写与索引重建;设置 → 墨库 InkVault 页面可直接选择/编辑两个文件夹(含原生「浏览…」选择器)。 - 自动化测试 114 项(113 pass / 1 skip;skip 为当前主机无权限创建文件符号链接)。
- 版本规则:
vx.y.z,初版v0.1.0;普通更新 z+1,较大更新 y+1,x 仅在明确要求时变动;每个版本对应一个 tag。
已知限制:
- 知识库目前是显式写入(用户说“存到知识库”时由 agent 调用工具),不做对话自动沉淀。
- 召回是词法 BM25(中文按 2-gram),不做语义/向量检索。
-
…(truncated)
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:2,最后更新 2026-10-20