Memory
dsh-longterm-memory
bufan528/dsh-longterm-memory · ★ 8
DSH Memory Vault (长期记忆) — durable local long-term memory for DeepSeek Harness, stored as an Obsidian-compatible Markdown vault with a rebuildable index, an in-sidebar management page…
Manifest details
安装
dsh plugin --profile web add 'dsh-longterm-memory@0.1.8'从 npm 安装预构建包
For install and environment setup, plus plugin development tutorials, see DSH community docs ↗
README
Table of contents
- What's new
- Why DSH Memory Vault?
- Features
- Interface
- How it works
- Install
- Option A — from the in-app market (dshmarket, recommended for desktop)
- Option B — install the latest from npm
- Option C — download the latest packaged tarball (no build required)
- Option D — build this repository and install the tarball (verified)
- Quick start
- Vault layout
- Configuration
- QQ integration (optional, since 0.1.5)
- What the page does
- QQ ↔ memory linkage
- Credentials and vault/profile modes
- Compatibility caveat
- Installing the official plugin (optional)
- Data safety
- Privacy
- Compatibility
- Development
- Project status & limitations
- Documentation
- License
Project status (2026-10-29).
dsh-longterm-memory@0.1.8is published on npm and attached to the latest GitHub Release (with a version-agnosticdsh-longterm-memory.tgzasset), and the plugin is listed in two community registries: the (added 2026-10-19) and the (dshworks/the community catalogs, verified, added 2026-10-19). The in-app 插件市场 / Plugin Market is the dshmarket plugin and reads that same catalog, so the plugin is discoverable and one-click installable there as well (no separate submission). Install it from the in-app market, or from npm withdsh plugin add dsh-longterm-memory@latest. The desktop-app plugin entry is verified end-to-end in the running desktop app (61/61 real-browser checks over the five pre-existing tabs, real vault, restored afterwards; the 0.1.5 QQ tab was verified separately on an isolated 0.2.1-rc.3 host, see docs/evidence/qq-verification.md). See Install, What's new and Project status & limitations.
What's new
0.1.8 removes an experimental QQ message-merge control surface from the QQ tab. The tab is back to what this plugin owns: connection status, memory-linkage policy, session isolation, inbox wiring, diagnostics and security. No other behaviour changes; existing memory data, index, tools, prompt injection and all other tabs are untouched.
0.1.5 adds a sixth tab, QQ integration
(记忆总览 | 记忆检索 | 记忆管理 | 收件箱 | QQ 接入 | 设置), plus an optional
QQ ↔ long-term-memory linkage policy (three modes, four enforcement points) and a
diagnostics card. It is documented in docs/qq-integration.md.
The existing 61-check real-browser E2E suite still covers the five pre-existing tabs;
the QQ tab was verified on an isolated 0.2.1-rc.3 host (see
docs/evidence/qq-verification.md).
0.1.4 is a documentation release: the plugin is now listed in the DSH Plugin
Market (added 2026-10-19) and in the dsh.works community registry
(dshworks/the community catalogs, verified; it powers the 插件 → DSH 社区 market in
the dsh-armory dashboard). Install or
update from the in-app 插件市场 / Plugin Market, or from npm. No code changes; it
ships all of the 0.1.3 fixes below.
0.1.3 made the Inbox actionable and fixed three other user-facing bugs:
- Inbox is actionable. 确认入库 / Confirm and 拒绝 / Reject now work for
in-memory candidates. Confirming writes an active memory (
lowconfidence is raised tomedium), folds a duplicate/supplement into the existing memory instead of duplicating it, and keeps both sides of a contradiction. Rejecting writes no file. - Status changes on extracted memories work. A multi-line
evidence:block scalar no longer blocks saves withunsafe-edit. - The UI language setting works (it previously lost to the host locale).
- No more permanent "unsaved changes" hint on the settings page.
- New real-browser E2E suite (
npm run verify:e2e) covering all five tabs, including the Inbox, detail, settings, batch and merge flows.
Full details: CHANGELOG.md · latest release

Why DSH Memory Vault?
Most "agent memory" features are a vector store or a black-box service. DSH Memory Vault makes the opposite trade-off:
- Markdown is the only source of truth. Each memory is a human-readable note with YAML frontmatter. Read, edit, link and back it up in Obsidian or any text editor. There is no proprietary format and no export step.
- The index is disposable.
.dsh-memory/index.jsonis derived data; delete it and the plugin rebuilds it from Markdown. Losing the index never loses a memory. - Recall is budgeted and transparent. Injection is computed per assembly from the current index with explicit token/item caps; the page shows exactly what the model would receive.
- History is durable. Every change is recorded in a journal with before/after digests, reasons and timestamps. A write-ahead outbox keeps history safe across crashes — including the verified window where the Markdown is committed but the journal append has not happened yet.
- Local by default. No network requests, no model calls, no telemetry; the only traffic is the local RPC between the management page and the DSH host.
Features
| First-level sidebar page | Registers a sidebar.panellist entry and a full management page (overview / search / manage / inbox / QQ integration / settings) — not a chat tab. |
| Four model tools | memory_search, memory_get, memory_save, memory_forget (save refuses credential-like content). |
| Automatic extraction | Rule-based, fully local candidate extraction at the real turn/end boundary. Optional model-assisted extraction is off by default. |
| Ranked recall | BM25-style lexical ranking over Markdown, with type/status/tag filters and a token budget. |
| Memory lifecycle | pending → active → stale / superseded / archived / conflict, plus low/medium/high confidence. Low confidence and sensitive content wait in the Inbox for human confirmation. |
| Safe updates | Deterministic dedupe/merge rules: duplicates merge, additions update while keeping sources, contradictions keep both sides, low confidence goes to Inbox. |
| Conflict handling | Conflicting facts are kept side by side, never silently overwritten; a conflict-resolution page supports keep / merge / both. |
| Crash-safe writes | Single-file atomic replace, per-file lock, optimistic checksum concurrency, durable journal outbox with idempotent recovery. |
| Obsidian compatible | The vault carries .obsidian/, [[wikilinks]], stable frontmatter and a human-readable Index/. |
| Bilingual UI | Chinese and English (`language: zh |
| Optional QQ integration tab | Status / detection / linkage policy / diagnostics for the official @tencent-connect/dsh-qqbot — read-only where it can be, never reimplements the QQ protocol, never touches credentials. |
No runtime dependency on @deepseek-ai/* |
The host half only uses the Cordis context passed in, so DSH internals can change without breaking the bundle. |
Interface
Real acceptance screenshots (headless Chrome, real host data — no mocks):
| Sidebar entry | Management page |
|---|---|
![]() |
![]() |
More: overview · search · manage · inbox · settings · dark theme
How it works
flowchart LR
A[DSH host] -->|tools / prompt section| P[Memory Vault host plugin]
U[Sidebar page] -->|local HTTP RPC| P
P --> V[(Markdown vault<br/>source of truth)]
P --> I[(index.json<br/>derived)]
P --> J[(journal outbox<br/>history)]
P --> Q[(quarantine<br/>unreadable notes)]
V -. rebuild .-> I
J -. recover .-> V
- The host owns the vault, index, journal and extraction; it never calls a model unless you explicitly enable model-assisted extraction with your own provider.
- The management page reads and writes through a loopback-only RPC surface
(
POST /dsh-longterm-memory/api/<method>, 29 methods) guarded by a browser-trust fence (loopback / trusted hosts,Origin,sec-fetch-site). - Recall:
memory_searchand automatic injection share one engine; explicit recall may include retired memories (labelled history), injection only uses current facts.POST /api/previewStandingandPOST /api/previewRecallreturn the exact text that would be injected.
Install
Option A — from the in-app market (dshmarket, recommended for desktop)
In the official desktop app, open 插件市场 / Plugin Market, search for
长期记忆 or DSH Memory Vault, then install or update from the plugin card and
restart the app when prompted. That in-app market is the
dshmarket plugin
(dshmarket.com); it reads the same
catalog (added 2026-10-19), so no separate dshmarket submission or association is
needed — the live registry already shows 0.1.4 with the five screenshots. After the
first listing, each npm publish makes the new version available for one-click updates.
Market page:
Also discoverable via dsh-armory. The dsh-armory dashboard's 插件 → DSH 社区 market reads the registry (browse at ), where this plugin is listed as verified with npm
dsh-longterm-memory. There is no separate submission to dsh-armory: keeping the npmlatesttag current keeps both listings current.
Option B — install the latest from npm
dsh plugin --profile web add dsh-longterm-memory@latest
Latest npm release:
dsh-longterm-memory@0.1.8. Use@latest(or omit the version) so an installation always fetches the newest published version. The newest GitHub release isv0.1.8; both point at the same build.
Option C — download the latest packaged tarball (no build required)
Every GitHub Release ships a versionless alias (dsh-longterm-memory.tgz) next to
the versioned copy and their SHA-256 checksums, so "latest" needs no version number:
# Stable URL — always the newest release
Invoke-WebRequest -Uri https://github.com/bufan528/dsh-longterm-memory/releases/latest/download/dsh-longterm-memory.tgz -OutFile .\dsh-longterm-memory.tgz
# optional: verify the checksum against the published .sha256 asset
Invoke-WebRequest -Uri https://github.com/bufan528/dsh-longterm-memory/releases/latest/download/dsh-longterm-memory.tgz.sha256 -OutFile .\dsh-longterm-memory.tgz.sha256
(Get-FileHash .\dsh-longterm-memory.tgz -Algorithm SHA256).Hash.ToLower() -eq ((Get-Content .\dsh-longterm-memory.tgz.sha256) -split '\s+')[0]
dsh plugin --profile web add .\dsh-longterm-memory.tgz
With the gh CLI, the same alias can be fetched version-agnostically:
gh release download --repo bufan528/dsh-longterm-memory --pattern "dsh-longterm-memory.tgz" --dir .
dsh plugin --profile web add .\dsh-longterm-memory.tgz
No gh? Open
https://github.com/bufan528/dsh-longterm-memory/releases/latest and download the
asset manually.
Option D — build this repository and install the tarball (verified)
Requires Node.js ≥ 20 and a DSH CLI. Use an isolated DSH_HOME so the test
profile cannot touch your daily DSH profile:
# 1. Build and pack
npm install
npm run build
npm pack # -> dsh-longterm-memory-0.1.8.tgz
# 2. Install into an isolated profile
$env:DSH_HOME = "<temporary dir>" # PowerShell
# export DSH_HOME="<temporary dir>" # bash
dsh plugin --profile lmv add .\dsh-longterm-memory-0.1.8.tgz
# 3. Start
dsh --profile lmv --no-open --port 0
Open the Web UI, click 长期记忆 / Long-term Memory in the sidebar, and choose a vault directory (or let the plugin initialize one). You can also pre-set it:
# <DSH_HOME>/profiles/lmv/cordis.patch.yml
- id: longterm-memory
name: dsh-longterm-memory
config:
vaultPath: 'D:/path/to/DSH Memory'
language: zh
Data-location warning. If
vaultPathis unset, the plugin initializes the default location (~/Documents/DSH Memoryon Windows).DSH_HOMEisolates the profile, not the vault. Always setvaultPathwhen testing.
Quick start
- Install as above and open the page.
- Click 初始化 / Initialize and pick a folder (an existing Obsidian vault works).
- Create a memory with 新建 / New, or let automatic extraction collect candidates at the end of a turn; low-confidence items appear in 收件箱 / Inbox.
- Ask the model something related; the plugin injects the standing section and the tools return ranked hits from the vault.
- Open 设置 / Settings to tune budgets, per-step recall, extraction and language.
Vault layout
DSH Memory/
├── README.md # generated; user edits are preserved
├── Memory Home.md # entry page
├── .obsidian/ # makes Obsidian treat it as a vault
├── Profile/ Preferences/ # profile, long-term preferences
├── Projects/ Projects/State/ # projects and project state
├── Decisions/ Knowledge/ # decisions, knowledge
├── Experiences/ Tasks/ # lessons, tasks
├── Inbox/ # candidates awaiting confirmation
├── Archive/ Conflicts/ # retired / contradictory memories
├── Index/ # human-readable index (regenerated)
├── History/ # change-history notes
└── .dsh-memory/ # config.json, index.json, journal/, quarantine/
Memory types: profile, preference, project, project-state, decision,
knowledge, experience, task. Status: active, pending, stale,
superseded, conflict, archived. Format details:
docs/storage-format.md.
Configuration
All settings are optional; defaults live in src/host/config.ts and can be overridden
from your profile's cordis.patch.yml.
| Key | Default | Meaning |
|---|---|---|
vaultPath |
auto-discover / initialize | Absolute memory vault path |
language |
zh |
UI language (zh / en) |
enableTools |
true |
Expose the four model tools |
enablePromptSection |
true |
Inject the standing memory section |
standingBudgetTokens |
700 |
Token cap for the standing section |
standingMaxItems |
12 |
Item cap for the standing section |
recallBudgetTokens |
600 |
Token cap for one recall answer |
recallMaxItems |
8 |
Item cap for one recall answer |
enablePerStepRecall |
false |
Splice retrieved memory into each step (replayed for the rest of the session) |
enableAutoExtraction |
true |
Rule-based extraction at turn end (local) |
enableLlmExtraction |
false |
Optional model-assisted extraction (sends turn text to your provider) |
redactSecrets |
true |
Refuse credential-like candidates |
sensitiveNeedsConfirmation |
true |
Health/finance/identity content waits for confirmation |
maxCandidatesPerTurn |
5 |
Extraction cap per turn |
QQ integration (optional, since 0.1.5)
The sixth tab is QQ 接入 / QQ access; the tab order is
记忆总览 | 记忆检索 | 记忆管理 | 收件箱 | QQ 接入 | 设置
(overview · search · manage · inbox · QQ access · settings). It is a status,
navigation, policy and diagnostics page: it never reimplements the QQ protocol and
never copies the official connector's code.
What the page does
- Detects the official plugin with a same-origin
GET /qqbot/im-qqbot/bindprobe (4 s timeout):200= loaded (the JSONphaseisbound,waiting,starting,savingorfailed),404= not installed / not loaded, anything else = cannot confirm. It does not usectx.get('im-qqbot'): the official plugin registers no cordis service, so that lookup isundefinedeven when it is loaded. - Does not open the official binding panel for you: the host has a generic main-page navigation API, but the official binding UI lives in a settings section / right-sidebar tab with no reliable public open path, so the page gives instructions for the in-app 设置 → QQ 机器人 section or the right-sidebar QQ 机器人绑定 tab instead.
- Never generates a QR code and never displays the AppSecret (the only identity
value it shows is the non-secret
appIdthe official plugin's own status route returns).
QQ ↔ memory linkage
Optional policy enforced at four points; off by default:
| Mode | Effect |
|---|---|
off (default) |
Identical to running without QQ integration |
deny-qq |
Sessions matching your QQ markers do not read long-term memory |
allowlist |
Only sessions matching your trusted markers read memory |
The four enforcement points are the standing prompt section, per-step recall,
turn-end write-back (QQ candidates go to the Inbox unless writeMode: direct) and the
four memory tools (allowTools, default false). QQ sessions can only be identified
by markers you declare — origin, agentPreset or cwd (for example the
preset/cwd set in the official plugin's config). Private and group chats cannot
be told apart: the official plugin knows the scope internally but does not write it
into the DSH session header, so this plugin does not fake per-group isolation.
Details: docs/qq-integration.md §5.
Credentials and vault/profile modes
- The official plugin writes
appId/appSecretas plaintext YAML into<profile>/cordis.patch.yml(no keychain, no encryption). This plugin never reads that file, never stores a credential, and never displaysappSecret(the only identity value it shows is the non-secretappIdfrom the official status route). - Same profile: QQ sessions and desktop sessions share one Vault — and therefore
one memory. That is exactly why
deny-qq/allowlistexist. - Separate profile: install this plugin in the QQ profile too and point both
vaultPathvalues at the same Vault; concurrent writes rely on the existing journal / atomic-write / lock machinery. This plugin never edits any profile. - Mismatched config: different vault paths mean two independent vaults — not shared. Details: docs/qq-integration.md §7.
Compatibility caveat
The official @tencent-connect/dsh-qqbot lists only DSH 0.1.0-rc.8 and
0.2.0-rc.2 as validated; it does not validate DSH 0.2.1-rc.3. The host still
admits it because the package has no engines.dsh and its @deepseek-ai/dsh-* peer
floor is evaluated with includePrerelease: true — installable is not validated.
There are open community reports on the 0.2.1 line (issues #60 / #58). See
docs/compatibility.md §13.
Installing the official plugin (optional)
npx @deepseek-ai/dsh plugin --profile <profile> add @tencent-connect/dsh-qqbot
Then bind it from the in-app 设置 → QQ 机器人 panel or the right-sidebar QQ 机器人绑定 tab (0.5.1+ ships the in-app UI; older versions only print a terminal QR code). The official plugin is a separate project; this plugin only reads its binding status.
Data safety
- Atomic single-file writes (temp file + rename) and a per-file lock with stale-lock detection; the lock is released on failure, never leaked.
- Optimistic concurrency: edits carry the expected checksum; a stale edit is rejected with a reload hint instead of overwriting someone else's change.
- Index is rebuildable:
rebuildIndex/syncIndexrecover from a deleted or corrupt index. Corruption diagnostics are surfaced, not hidden. - Durable journal: every change gets a before/after digest, reason and timestamp. A write-ahead outbox recovers when the monthly archive fails, with idempotent re-archiving and content-conflict detection (same event id + different payload is an explicit integrity error, never a silent merge).
- Crash-window tests: commit boundaries are exercised with real child-process SIGKILLs, not simulated exceptions — including "Markdown written, commit marker not yet persisted" and "recovery itself interrupted".
- Quarantine: notes that cannot be parsed safely are isolated, never deleted.
Privacy
- No telemetry and no outbound network calls by default. Host-side acceptance runs
showed zero network calls; the only client request targets are the local DSH RPC and,
when the QQ tab is opened, the same-origin read-only
GET /qqbot/im-qqbot/bindprobe — both loopback. The 0.1.3 desktop E2E run exercised the real page and asserted zero page errors / uncaught exceptions; it is not a packet-level network audit. - Model use is opt-in: automatic extraction is rule-based and local; model-assisted
extraction (
enableLlmExtraction) is off and, when enabled, uses the provider you configured in DSH. - Secrets are refused: credential-like content (passwords, API keys, tokens, private keys) is blocked before it reaches the vault; sensitive categories require explicit confirmation.
- Injection is data, not instructions: memories are wrapped and labelled as untrusted data for the model. See docs/privacy.md.
Compatibility
| DSH runtime | >=0.2.1-rc.3 <0.2.2 (engines.dsh; 0.2.0-rc.2 is not supported) |
| Verified DSH version | 0.2.1-rc.3 — current desktop host; the plugin is loaded and serving RPC on it (see docs/compatibility.md §12) |
| Node.js | >=20 |
| Platform | Windows (primary), Node path rules elsewhere |
| npm package | dsh-longterm-memory — 0.1.8 published on npm and GitHub |
| Downloads | Latest GitHub Release — stable alias dsh-longterm-memory.tgz (+ .sha256), or npm @latest (0.1.8) |
| DSH Plugin Market | Listed in since 2026-10-19; updates follow the npm latest tag |
| dshmarket (in-app market) | Listed through the same catalog; the live registry checks showed 0.1.4 with 5 screenshots on 2026-10-21 (no separate dshmarket submission) |
| dsh.works registry | Listed + verified in since 2026-10-19; surfaced by the 插件 → DSH 社区 market in the dsh-armory dashboard |
The dsh.compatibility field is informational; engines.dsh is the only decision
source. Details and evidence: docs/compatibility.md.
Development
npm install
npm run build # tsc -> lib/host, esbuild -> lib/client.js
npm run typecheck # tsc --noEmit
npm run lint # contract checks + version-consistency check
npm test # full suite (currently 41 files / 595 cases)
npm run check # build -> typecheck -> lint -> test (clean checkout safe)
npm run pack:plugin # build + npm pack
npm run verify:e2e -- --url "http://127.0.0.1:<port>/?token=..." # real-browser E2E (61 checks)
verify:e2e drives a real Chrome over CDP, clicks the real management page and checks
every effect through the plugin RPC and the Markdown files on disk. For a token-guarded
desktop listener, mint the desktop launch cookie for the current machine and pass it
with --cookie-file <name=value file>.
Tests cover unit, integration, packaging, real HTTP-route validation, and deterministic
fault injection (including real subprocess kills). The browser acceptance scripts are
zero-dependency CDP clients using Node's built-in WebSocket.
Project status & limitations
- Preview: API and storage format may still change;
0.1.0was the first public version, and0.1.8is the current release. - npm published:
dsh-longterm-memory@0.1.8(2026-10-29); the npmlatestdist-tag points at it and registry installation is verified. The same build is attached to the latest GitHub Release (dsh-longterm-memory-0.1.8.tgzplus the version-agnosticdsh-longterm-memory.tgzand their.sha256files). - Listed in the DSH Plugin Market: the plugin is in the
catalog (added 2026-10-19). Install it from the in-app 插件市场 / Plugin Market;
future releases are picked up automatically from the npm
latesttag, so no new marketplace submission is needed per version. The China-region catalog mirror may lag the origin by up to about a day. - Available in dshmarket (in-app Plugin Market): the
dshmarket plugin reads the same
the community catalog catalog live on every open, so this plugin is already reachable in
插件市场 / Plugin Market — no separate dshmarket submission, claim, or association
step exists. The live registry on 2026-10-21 showed version
0.1.4with 5 screenshots; updates follow the npmlatesttag. - Also listed in dsh.works: the entry in
is
status: verifiedwithnpm: dsh-longterm-memory(added 2026-10-19), so the 插件 → DSH 社区 market in the dsh-armory dashboard lists and installs it without any separate dsh-armory submission. Both registries follow the npmlatesttag; dsh-armory revalidates its catalog cache every few minutes (new installs fetch fresh). - Desktop verified: the full real-browser E2E suite passes against the running desktop app (61/61 checks, the five pre-existing tabs, real vault restored afterwards).
- QQ integration (0.1.5): the QQ tab, the linkage policy and the diagnostics are
documented in docs/qq-integration.md and were verified on an
isolated DSH
0.2.1-rc.3host with a real browser (see docs/evidence/qq-verification.md). They are not part of the 61-check E2E suite yet. The official QQ plugin is not installed on this machine, so only its404probe branch was observed; the200branch and the official connector's actual behaviour on DSH0.2.1-rc.3are unverified. - Known follow-ups: in-memory Inbox candidates are drafts — they are not counted in
待确认数量/ theInbox/folder until confirmed; they leave the Inbox when confirmed or rejected. A few concurrency and move-atomicity edge cases remain open; frontmatter and lock regressions found in review were fixed in0.1.0and are locked by tests. - Vault location: with
vaultPathunset the plugin initializes~/Documents/DSH Memory. Set it explicitly to keep test data isolated.
Documentation
| Doc | Contents |
|---|---|
| docs/architecture.md | Architecture, DSH API usage, prompt assembly |
| docs/storage-format.md | Markdown / frontmatter / index / journal formats |
| docs/privacy.md | Privacy and threat model |
| docs/compatibility.md | Compatibility contract and evidence |
| docs/qq-integration.md | QQ integration tab, official-plugin detection, memory linkage, vault/profile modes |
| docs/verification.md | Verification log and acceptance evidence |
| CHANGELOG.md | Release notes for every published version |
| docs/troubleshooting.md | Recovery and FAQ |
| docs/evidence/ | Screenshots and raw acceptance data |

