Biomimetic memory system for DeepSeek Harness: a single SQLite store (node:sqlite, WAL) whose Markdown tree is kept as a read-only mirror; memory tools, frozen-snapshot injection at session start, graded approval gating, on-demand extraction of the current session, near-duplicate merging, an archive and supersede lifecycle, memory metabolism (dream), memory pins, semantic recall over local embeddings, and the /memory command.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:KLRSL/dsh-biomemory
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
A memory layer for DeepSeek Harness: one local file, zero services, zero API calls — recall driven by trigger signals, so the right memory shows up at the right moment.
v0.11.3 · MIT License · DSH 0.2.x (>=0.2.0-rc.2 <0.3.0-0, tested on the 0.2.1-rc.3 desktop app) · Node >= 22.19.0
What it is
In one line: a memory layer, not a memory platform.
- Not: external service, vector search, embedding models, knowledge graphs, cloud sync, web UI.
- Is: one SQLite file plus a deterministic rule set for "when should what be recalled".
The difference from a memory platform is not the feature count — it is that there is nothing extra to run. Install the plugin; the data lives in .dsh/biomemory/biomemory.db on your machine, and copying that file migrates your memory.
Four layers
1. Storage: single-file SQLite
| Field | Meaning |
|---|---|
realm |
Isolation: user or project:<cwd> |
mtype |
Memory type: workflow / error / decision / fact |
trigger |
Trigger signal string (below) |
mkey |
Topic key used for same-key overwrite |
text |
The memory itself |
created_at / last_accessed / hits |
Lifecycle: created / last used / use count |
status |
active / archived / deleted (deletion is a tombstone) |
Two helper tables: chains (workflow chains) and trigger_counts (repetition counter for workflow promotion).
2. Recall: driven by trigger signals
The plugin does not wait for the model to "remember". It watches what is happening:
- Signals: the session working directory (
session.cwd) plus the last 12 tool calls (names and arguments — file paths, commands, error codes). - Three trigger shapes only, readable and explainable:
file:<name>— e.g.file:package.jsontool:<tool>— e.g.tool:pwsherr:<CODE>— e.g.err:MODULE_NOT_FOUND
- On a hit, memories are injected ordered workflow > error > decision > fact, then by last-used time; if a workflow chain matches, the whole chain is injected.
- Injection budget: at most 8 items / 1200 characters per recall. No signal, no injection — and no tokens spent.
3. Cleanup: five explainable rules
Run /memory compact; every eviction is written to compact.log:
- A newer memory with the same
realm + type + keyoverwrites the older one (tombstoned) on the write path; fact: unused (use count <= 1) for more than 30 days -> tombstone;workflow/error/decision: no TTL, but unused for more than 90 days -> half weight;erroranddecisionare never auto-deleted;- Every eviction/demotion is logged (time, fingerprint, rule, summary).
4. Adaptation: workflows emerge from repetition
When the same trigger appears more than 3 times, related memories are promoted to workflow and ordered into a chain:
when file:package.json: read package.json -> run tests -> then edit code
A chain records order, not causation — it does not pretend to know why, only what you actually did last time.
Install
Desktop app: install by package name (recommended)
- Open the DSH desktop app → Plugins in the sidebar → Add plugin;
- Type the package name
dsh-memory-layerand click Install (it is enabled automatically).
CLI equivalent:
# replace desktop with your profile name
dsh plugin --profile desktop add dsh-memory-layer
Local development (link)
dsh plugin --profile desktop add link:./dsh-memory-layer
Restart DSH afterwards (profiles with HMR hot-mount it).
Usage
Tool memory
| action | Description |
|---|---|
add |
Write a memory (text required; `track=user |
query |
Keyword query (text/topK/fragmentTypes/includeArchived) |
used |
Mark "this was actually used just now" (advances hits / last_used) |
list / update |
Browse / edit |
remove |
Tombstone (row stays; restore brings it back) |
purge |
Physical delete (irreversible; auto-backs-up the DB first) |
restore / pin / unpin |
Roll back / pin / unpin |
compact |
Run the five rules (dryRun=true to preview; only changes status, no backup copy) |
dump |
Export human-readable Markdown (keeps the latest 10) |
When add / update stores text containing a relative time word (today / yesterday / next week …)
without an absolute date anchor (YYYY-MM-DD, M月D日, 20xx年), the successful result's note gains
one reminder line. The write still succeeds — refusing would lose information.
A second tool, memory_recall, is available for explicit "do you remember..." lookups.
Command /memory
/memory list | query <words> | add <text> | edit <fp> <text> | entries [words]
/memory remove <fp> | purge <fp> | undo <fp> | unarchive <fp> | used <fp>
/memory pin <fp> | unpin <fp>
/memory stats | why <fp> | preview
/memory compact [--dry-run] | dump | help
stats reports health including trigger coverage (how many memories have no trigger and can therefore never be recalled proactively). why <fp> explains why a memory is (not) injected. preview shows what would be injected right now.
Write approval
Important memories (user preferences / decisions / corrections) go through DSH's official approval. Approval is required before storing, and when the approval service is unavailable writes are denied by default (fail-closed; set approvalFallback=auto to relax).
Data and privacy
- Fully local: no network requests, no external APIs, no telemetry.
- Database:
<DSH_BIOMEMORY_DIR || ~/.dsh/biomemory>/biomemory.db(SQLite, WAL). - Deletion is a tombstone (recoverable);
compactonly changes status inside the file. Usedumpwhen you want a Markdown copy. - Env vars:
DSH_BIOMEMORY_DIR(data dir),DSH_MEMORY_ROOT(Markdown backup/log dir). - Config location:
<DSH_MEMORY_ROOT || ~/.dsh/memory>/biomemory.config.json(v0.11 fix: the docs previously said~/.dsh/biomemory/, which does not match the code). - Local HTTP endpoints (
/biomemory/api, registered when the host exposes a web server): only local origins are accepted, cross-site requests get 403. UseDSH_MEMORY_API_ORIGINSto allow specific origins, orDSH_MEMORY_API_NOAUTH=1to disable the check (not recommended).
Configuration
<DSH_MEMORY_ROOT || ~/.dsh/memory>/biomemory.config.json (or bundle config) can override:
| Key | Default | Meaning |
|---|---|---|
nearDuplicateThreshold |
0.7 | Similarity threshold for write dedupe (0 = off) |
nearDuplicateAction |
merge | On near-duplicate: merge, or skip (report only) |
approvalFallback |
deny | Deny when approval is unavailable, or auto |
decayThreshold |
3 | "Low weight" warning threshold |
hotTokenLimit |
2000 | Token cap for the always-on snapshot (v0.11: 5000 → 2000) |
maxQueryResults |
20 | Query result cap |
weightCap |
20 | Weight ceiling |
sinkWindowMinutes |
5 | Window (minutes) for the "please summarise" nudge |
decisionChannelMax |
3 | Max items per turn in the preference/decision channel (0 = off) |
decisionChannelChars |
400 | Char budget for that channel (0 = off) |
coldStartFallbackMax |
3 | Cold-start fallback items (0 = off) |
injectSnapshot |
true | Host injection switch: always-on snapshot section (order -50). false = the section is not registered at all |
injectRecall |
true | Host injection switch: triggered-recall section (order -40) |
injectSummary |
true | Host injection switch: end-of-turn settle nudge section (order 200) |
The three inject* keys are host injection switches. They default to true (current behaviour);
set all of them to false to run as a pure data layer (store/query only, nothing enters the prompt).
They are read during apply, so a restart or plugin reload is required — editing biomemory.config.json
alone does not hot-switch them.
Deliberately not done
- No vector/embedding search: same input, same result; retrieval must be explainable.
- No automated "reflection": without a model it does not pretend to generalise; workflows only emerge from repetition.
- No delete-means-gone: every deletion leaves a tombstone and can be rolled back.
- No cross-machine sync: that is a different product; here the file itself is portable.
Version history
| Version | Date | Changes |
|---|---|---|
| v0.11.3 | 2026-10-31 | Preparing the data-layer-only mode + date check: added host injection switches injectSnapshot / injectRecall / injectSummary (default true = current behaviour; all false = store/query only, nothing enters the prompt; read during apply, reload required). When text contains a relative time word and no absolute date anchor (YYYY-MM-DD / M月D日 / 20xx年), add / update still succeed but the result gains a one-line reminder. "最近 / 目前" do not trigger it |
| v0.11.2 | 2026-10-31 | Repository re-baselined on the released 0.11.1 tarball (the 0.11.0/0.11.1 source tree was lost; module code is byte-identical to 0.11.1). Dev-side fixes: README version exposure, ARCHITECTURE test reference, SECURITY supported versions / false audit.log claim, CI Node 22.19 matrix, .gitignore; two pre-0.11 test cases removed and the same-key case switched to exact keys; stale pnpm-lock.yaml deleted. No functional change. See CHANGELOG.md |
| v0.11.1 | 2026-10-28 | No automatic DB copies on any write path + tests shipped: compact / purge / fingerprint migration all stop writing backup copies (tombstones are revived by restore; purge must not leave a copy behind; backupDb() stays as a manual entry point); files now ships tests/core.test.mjs so npm test works after install. See CHANGELOG.md |
| v0.11.0 | 2026-10-27 | Correctness & observability: fixed includeArchived returning deleted tombstones; remove is now a real tombstone (physical delete moved to purge); fingerprints are now full-text hashes (the old first-20-chars hash collided and silently dropped memories) with a one-shot re-migration; same-key overwrite is now an exact match (prefix matching tombstoned unrelated entries); injection and real usage are counted separately (last_accessed vs last_used) so cleanup rules are no longer starved by self-feedback; realm is inferred from the session cwd on write; session state and signals are per-session; local HTTP endpoints validate origin; selfHeal no longer throws; compact backs up before writing. Added: preference/decision channel, cold-start fallback, /memory stats (incl. trigger coverage) / why / preview / used / purge / unarchive / help, snapshot caching, dump rotation |
| v0.10.2 | 2026-10-25 | Rewrote the intro line; tested desktop version is now 0.2.1-rc.3. No functional change |
| v0.10.1 | 2026-10-25 | Rewrote the plugin card copy: localized title and one-line summary in locale meta, and a description without the version prefix or feature dump; no functional changes |
| v0.10.0 | 2026-10-05 | Rebuilt as a memory layer: trigger-driven recall (trigger/realm/mtype/mkey columns), type-priority ordering, five cleanup rules with tombstones and compact.log, workflow promotion and chains, injection budget (<=8 items / <=1200 chars), compact/dump; removed dream/reflect/conflict-adjudication/audit and the automatic Markdown mirror |
| v0.9.2 | 2026-09-29 | Removed dead modules and config keys; docs aligned with implementation |
| v0.9.1 | 2026-09-29 | Removed the management UI; plugin became host-only |
| v0.9.0 | 2026-09-29 | Removed embeddings and semantic/hybrid retrieval |
| v0.8.2 | 2026-09-20 | Compliance batch: audit fixes, typed config persistence, near-duplicate dedupe |
| v0.8.0 | 2026-09-16 | Write dedupe (bigram similarity) with merge/skip strategies |
| v0.7.0 | 2026-09-17 | Mirror-sync hook (removed in v0.10.0) |
| v0.6.4 | 2026-09-06 | Single source of truth: SQLite; Markdown became read-only backup |
| v0.6.0 | 2026-08-19 | Architecture split (shared/store/retrieve/snapshot/gate) + session sediment |
| v0.5.0 | 2026-08-15 | Data layer moved to SQLite (node:sqlite) |
License
MIT — see LICENSE.
Links
More in this category
vectorize-io/hindsight#coding-agents★ 60916
Hindsight, agent memory that learns: long-term project memory with auto recall and retain, knowledge pages, deep reflection, and per-repo memory banks.
volcengine/OpenViking#examples/dsh-memory-plugin★ 42209
OpenViking memory and context bundle for DeepSeek Harness: pre-step auto-recall and profile injection, session capture, `viking://` URI guarding, and recall/write memory tools backed by an OpenViking server.
MemTensor/MemOS#memos-local-plugin★ 12392
Local-first memory plugin for DeepSeek Harness: layered L1/L2/L3 memory with automatic capture, manual memos_* retrieval tools, and a built-in memory viewer.
agentscope-ai/ReMe#dsh★ 3799
Connects DeepSeek Harness to ReMe's local-first, self-evolving personal knowledge base: automatically captures completed main-agent conversations as user-owned Markdown memory, searches conversations and source material through reme_search with BM25, optional embeddings, and wikilink expansion, and schedules daily memory consolidation.
zilliztech/memsearch#MemSearch★ 2873
Shared Markdown memory for DSH and other coding agents, with automatic capture, pre-step context injection, searchable recall, and memory-to-skill self-evolution through a review panel.
vshulcz/deja-vu#extensions/dsh★ 1544
Cross-session memory and context recovery across forty-five other coding agents (45+) on this machine, reading session files they already wrote before install (Claude Code, Codex, Cursor, Windsurf, Trae, Antigravity, VS Code Copilot Chat, opencode, OpenClaw, Hermes, Kimi, Qoder, Cline, Zed, Magpie and more): six tools (deja_recall, deja_session, deja_blame, deja_fix, deja_how, deja_remember), a /deja command, and optional automatic recall injected into runtime context. Local BM25 CLI/MCP index, no LLM, no embeddings, no network (dsh plugin --profile web add dsh-deja).
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.