供 DSH 与其他编程 Agent 共享的 Markdown 记忆,支持自动捕获、步骤前上下文注入、搜索召回,以及通过审阅面板实现 memory-to-skill 自进化。
安装
# npm 包(预构建)
dsh plugin --profile web add @zilliz/memsearch-dsh
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:zilliztech/memsearch#path:/plugins/dsh
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
该插件的 README 只有英文版本。
MemSearch plugin for DeepSeek Harness (DSH).
It gives DSH persistent, cross-agent memory on the same .memsearch/memory/
markdown store used by the Claude Code, Codex, OpenClaw, and OpenCode plugins,
backed by a Milvus hybrid search index.
capture ── session/event turn/end ──> summarize (dsh-headless agent default, or custom-llm) ──> memory/YYYY-MM-DD.md
inject ── agent/pre-step step 1 ──> memsearch search ──> returned chunks injected (zero cost otherwise)
recall ── ctx.skills.register(memory-recall) ──> search → expand → transcript
review ── web UI dock panel ──> GET/POST /memsearch-dsh/* ──> list candidates / queue review / install
Prerequisites
Install memsearch:
uv tool install "memsearch[onnx]"A DSH profile (web / headless / tui) you want to attach memory to.
Node >= 22.19 (DSH's requirement).
Install
From npm (recommended)
dsh plugin --profile web add @zilliz/memsearch-dsh
From source (development)
dsh plugin --profile web add /path/to/memsearch/plugins/dsh
dsh pluginis a pnpm forwarder: it links the package into the profile, detects thedsh.bundledeclaration inpackage.json, and appends it to the profile's bundle layers.cordis.patch.ymlinside the package then inserts thememsearchrow into the profile's plugin tree.Replace
webwith your profile name (headless,tui, ...), and restart DSH for the profile (or start a new session) so the plugin mounts.
Manual patch insertion (no dsh plugin)
Append this row to the profile's cordis.patch.yml and make sure
@zilliz/memsearch-dsh is resolvable from the profile's node_modules (for example a
link: dependency):
- insert:
- id: memsearch
name: '@zilliz/memsearch-dsh'
Verify it loaded
Start DSH and check the session log for the plugin mount, or confirm the
memory-recall skill is available through the skill tool. Captured turns
land in <project>/.memsearch/memory/YYYY-MM-DD.md.
Configuration
The plugin is configured through the profile's cordis.patch.yml config
block (patch the memsearch row you inserted). All keys are optional.
| Key | Type | Default | Meaning |
|---|---|---|---|
captureEnabled |
bool | true |
Capture completed turns into memory. |
injectEnabled |
bool | true |
Inject returned memory candidates before each turn's first step. |
summarizeEnabled |
bool | true |
Summarize turns before writing (on failure a short unavailable note is written, never a raw dump). |
summarizeMode |
string | auto |
Summarizer backend. auto (default) mirrors the other platform plugins: if [plugins.dsh.summarize] provider is set in memsearch config, it uses custom-llm; otherwise dsh-headless (zero-config DSH agent). Explicit dsh-headless / custom-llm pin the backend. |
Everything else — provider/model, Milvus, collection, memory dir — comes from memsearch config / environment, exactly like the other platform plugins (no per-plugin config fields):
- Summarize provider/model →
[plugins.dsh.summarize] provider/modelin~/.memsearch/config.toml(or[llm.providers.*]; see thecustom-llmsection below). - Milvus →
[milvus] uriin memsearch config. - Collection → derived from the project path (
derive-collection.sh), or--collectionpassed to the memsearch CLI. - Memory dir →
MEMSEARCH_DIRenv (explicit → global scope), else<project>/.memsearch.
Maintenance tasks (PROJECT.md / USER.md / skills)
Optional background upkeep, aligned with the other platform plugins. Each task
is disabled by default; enable the ones you want in ~/.memsearch/config.toml:
[plugins.dsh.project_review]
enabled = true # maintain .memsearch/PROJECT.md
[plugins.dsh.user_profile]
enabled = true # maintain .memsearch/USER.md
[plugins.dsh.memory_to_skill]
enabled = true # distill recurring workflows into skill candidates
min_occurrences = 3 # how often a workflow must recur before distilling
Common settings per task: provider (native = a one-shot DSH headless
agent, default), model, min_interval_hours (default 24), input_dir,
output_file. Candidates land in .memsearch/skill-candidates/ (git-tracked)
and are never installed automatically — installing is a human step (see
the memory-to-skill skill in the other platform plugins).
Example override layer (add this to the profile's own cordis.patch.yml):
- id: memsearch
config:
summarizeMode: dsh-headless # pin the headless backend (default is auto)
Summarization modes
Two backends are available, selected by summarizeMode — the same
"configured choice" the Claude Code / Codex / OpenClaw / OpenCode plugins
offer (each can summarize with their own LLM or a headless agent + small
model). The default (auto) matches theirs: configure a provider and you get
a direct LLM call; configure nothing and you get a headless agent.
auto(default) — mirrors the other platform plugins:- if
[plugins.dsh.summarize] provideris set in memsearch config (~/.memsearch/config.toml, same place the other plugins read), usecustom-llmwith that provider/model; - otherwise use
dsh-headless(zero-config DSH agent). This means the plugin behaves like the other four: configure a provider → direct LLM; configure nothing → headless.
- if
dsh-headless— boots a one-shot DSH headless agent (dsh --profile headless "<summarize task>") to write the notes, mirroring how the other plugins reuse their own agent's headless mode. Zero-config for anyone already using DSH: the sub-agent's model is the deployment'sagent-default-model— the user layer of~/.dsh/settings.yaml(the same selection the Web UI model settings write) wins over any patch, so the[plugins.dsh.summarize]provider/model do NOT apply here — change the model in DSH settings (agent-default-model:in~/.dsh/settings.yaml, or the Web UI model picker) instead. The boot is asynchronous and fire-and-forget, so the few seconds of headless startup never block the conversation. Requiresdshon PATH orDSH_CLIset to the CLI entry. The sub-agent is booted withMEMSEARCH_DSH_SUMMARIZE=1; the plugin checks that flag and stays inert (no capture / inject / skill) inside the summarizer, so the summarizer's own session is never re-captured in a loop.custom-llm—scripts/summarize.pyimports memsearch's[llm.providers.*]config and calls the LLM directly. Lightweight: one python process, no DSH boot, no extra CLI dependency. Choose this when you want a specific small model (e.g. an officialdeepseek-v4-flashkey in memsearch config) without booting an agent. Provider selection (most specific first):[plugins.dsh.summarize] provider(or thesummarizeProviderCLI argument summarize.py receives from it) — looked up in[llm.providers.<name>]; a missing entry fails loudly (visible error), never a silent empty write.llm.providerwhen it names a configured provider or is a raw type.compact.llm_provider(deprecated) oropenaias a final default.
There is no automatic fallback between modes: the backend you configure (or auto resolves) is the backend used. If it fails (missing dsh CLI, bad provider config), a short unavailable note is written with the reason — the plugin never silently switches to an LLM you did not configure.
A failed summarization writes a short unavailable note (mirroring Claude Code's behavior — memory stays clean, the transcript anchor keeps the raw content reachable for progressive disclosure), and logs a visible warning through the DSH logger.
How it works
- Capture — listens on
session/eventforturn/end, renders the turn ([User]/[Assistant]/[Tool call]lines), then fire-and-forget summarizes (if enabled) and appends it to the session's ownmemory/YYYY-MM-DD.mdwith the shared anchor format<!-- session:<id> turn:<N> db:<path> -->. The project directory comes fromsession.header.cwd, so a long-lived web surface captures every project it hosts, not just the process's boot directory. Turns are serialized (LLM summarize calls never overlap) andcaptureExistsdedup keeps each turn idempotent if its event replays. - Inject — on
agent/pre-stepat step 1, runs a bounded memsearch search over the user's question. Only when the search returns chunks does it inject them plus a[memsearch] Retrieved memory context attached.marker; otherwise the decision is returned unchanged (zero context cost). The model still evaluates whether each candidate chunk is relevant. - Recall — registers a
memory-recallskill (invocable through DSH's nativeskilltool) that performs search → expand → transcript drill-down and returns a curated summary. - Maintenance — runs the shared maintenance runner (PROJECT.md / USER.md
upkeep and memory-to-skill distillation), triggered on
session/disposedplus a 6-hourly fallback timer. Each task is a due-state machine: it runs at most once permin_interval_hours(default 24h) and only when enabled in memsearch config ([plugins.dsh.project_review],[plugins.dsh.user_profile],[plugins.dsh.memory_to_skill]), mirroring the other platform plugins. The maintenance work is executed by a one-shot DSH headless agent (the samedsh --profile headlessmechanism as summarization), booted withMEMSEARCH_DSH_SUMMARIZE=1so the plugin stays inert inside it. - Skill review panel (web only) — a non-blocking dock strip above the
composer (registered into the
conversation.input.dockslot) lists skill candidates distilled into.memsearch/skill-candidates/. It is served by the plugin's browser half (client.js, declared throughdsh.clientinpackage.json) and talks to the host through two JSON routes on the DSH web server:GET /memsearch-dsh/skill-candidates?sessionId=<id>— lists candidates (pending first) parsed from each candidate'smeta.json.POST /memsearch-dsh/skill-reviewwith{ sessionId, name, action }:action: "review"queues a[memsearch] Skill candidate ...user message into the live agent's inbox (agent.inbox.append('next-turn', ...)). The agent reviews the candidate on its next turn — non-blocking, it never interrupts a running turn and never opens a blocking dialog.action: "install"runsmemsearch skills install <name> --path <dir>in the background (detached, unref'd) to the resolved target: the first entry ofplugins.dsh.memory_to_skill.pathsin memsearch config (relative entries resolve against the project dir), else the DSH default~/.agents/skills, which theskill-filesystemprovider watches and loads automatically. The project directory is resolved from the session id (its durable cwd), so the panel reflects the project of the session you are viewing on a multi-project web surface. The routes are registered once the DSH web server service becomes available (the memsearch plugin mounts in the base bundle layer, before the web server starts;applyretries on a 1s unref'd timer). Headless / TUI profiles have no browser: thewebServerservice never appears, no routes are registered, and everything else is unchanged.
Uninstall
dsh plugin --profile web remove @zilliz/memsearch-dsh
Removing the dependency drops the profile-layer entry; the memory markdown files and the Milvus index are left untouched.
Development
- The plugin is plain ESM with no build step —
dsh plugin addlinks the checkout directly, so edits are live after a profile reload. - The browser half (
client.js) is a prebuilt client-module bundle: it registers its factory withwindow.__ModuleLoader__.load({ id, factory })(the lazy CJS table the web shell serves at/plugins/<id>/client.js) and exports the Cordis client plugin shape (inject+apply). It is checked in as-is; edit it directly and keep the__ModuleLoader__registration format (mirror the shipped@deepseek-ai/dsh-client-ui-*lib/client.jsbundles). - Python helpers under
scripts/are linted with the repo'sruffconfig and tested underplugins/dsh/tests/. - Keep the memory-write format byte-compatible with the other platform
plugins; see
plugins/opencode/scripts/capture-daemon.pyfor the canonical writer.
链接
同类插件
vectorize-io/hindsight#coding-agents★ 46897
Hindsight:会学习的 Agent 长期记忆系统,自动召回/保存、知识页、深度反思与按仓库隔离的记忆银行。
volcengine/OpenViking#examples/dsh-memory-plugin★ 39378
面向 DeepSeek Harness 的 OpenViking 记忆与上下文插件:pre-step 自动召回与画像注入、会话捕获、`viking://` URI 防护,以及对接 OpenViking 服务端的 recall/write 记忆工具。
agentscope-ai/ReMe#dsh★ 3557
将 DeepSeek Harness 接入 ReMe 本地优先、自进化的个人知识库:自动把已完成的主 Agent 对话沉淀为用户掌控的 Markdown 记忆,通过 reme_search 结合 BM25、可选向量检索和 wikilink 展开搜索对话与资料,并按日整理长期记忆。
vshulcz/deja-vu#extensions/dsh★ 1147
读取本机上其他三十三个编程智能体已经写下的会话文件——Claude Code、Codex、Cursor、VS Code Copilot Chat、opencode、OpenClaw、Hermes、Kimi、Cline、Zed 等,包括安装之前的历史:提供 deja_recall、deja_session、deja_blame、deja_fix、deja_how、deja_remember 六个工具与 /deja 命令,并可选地把召回结果加入运行时上下文。本地 BM25 索引,不用大模型,不用向量嵌入,不联网(dsh plugin --profile web add dsh-deja)。
adoresever/graph-memory★ 638
DeepSeek Harness 的可追溯、可检索跨会话记忆:把对话知识沉淀为带类型的图节点(任务/技能/事件)与关系边。
Ikalus1988/MisakaNet★ 524
失败恢复记忆库:从真实工程会话中搜索和记录失败恢复教训,支持 BM25 + 语义 RAG 检索和知识库管理。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。