dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
单文件本地 SQLite 的自整理活记忆——夜巡引擎自动去重、合并、衰减、建链,七信号 RRF 混合检索(FTS5+jieba 中文优先分词、可选向量 KNN、图谱 PPR),带类型知识图谱,冲突检测标记矛盾而非静默覆写,Web 遥测面板。
Built by 暖暖 (NuanNuan) — an AI assistant that built its own memory system.
A living, self-tending memory plugin for DeepSeek Harness (DSH). Every conversation the agent has, every lesson it learns, every decision it makes is captured into a local SQLite knowledge base — then actively tended: deduplicated, merged, decayed, cross-linked into a knowledge graph, and patrolled every night. Memories fade when unused and resurface when relevant, like a hippocampus rather than a log file.
Everything is local. One SQLite file. No telemetry leaves your machine; the optional embedding path is off unless you configure it.
Most agent-memory tools are retrieval layers: you write, you search. dsh-living-memory additionally runs a nightly patrol that reorganizes the store on its own:
A query fans out into seven independent signals fused by RRF:
| # | Signal | Source |
|---|---|---|
| 1 | Full-text | SQLite FTS5 with jieba tokenization (first-class Chinese) |
| 2 | Vector | local KNN over embeddings (optional, see below) |
| 3 | Decay | age × reinforcement score |
| 4 | Relevancy | per-entry quality weight |
| 5 | Co-occurrence | query-term pair statistics |
| 6 | PPR | graph proximity from seed hits |
| 7 | Hop | edge-distance boost |
If any channel fails (e.g. no embedding key), ranking degrades gracefully to the remaining channels — the plugin never hard-fails on a missing optional dependency.
| dsh-living-memory | mem0 | Zep | Letta | graph-memory | |
|---|---|---|---|---|---|
| Fully local, single SQLite file | ✅ | partial | ❌ | ❌ | ✅ |
| Self-tending nightly patrol | ✅ | ✅ (cloud) | ✅ | ❌ | ❌ |
| Temporal decay / reinforcement | ✅ | ❌ | ✅ | ❌ | ❌ |
| Knowledge graph + PPR | ✅ | ❌ | ✅ | ❌ | ✅ |
| Conflict detection | ✅ | ❌ | ❌ | ❌ | ❌ |
| Chinese-first tokenization | ✅ | ❌ | ❌ | ❌ | ❌ |
| Web GUI telemetry panels | ✅ | ❌ | ❌ | ✅ | ❌ |
| Designed for DeepSeek Harness | ✅ | ❌ | ❌ | ❌ | ❌ |
dsh plugin --profile web add dsh-living-memory
dsh plugin forwards to the profile's package manager — replace web with your own profile name
under $DSH_HOME/profiles. After a DSH restart the plugin registers its tools automatically:
memory — search / timeline / stats / read_episodic / read_evolutionmemory_write — typed writes (fact / decision / todo / lesson) with optional relation edgesThe bundled cordis.patch.yml mounts both roles (host + write) automatically — zero config.
To restrict write access to selected agent presets, remove the living-memory-write row from
that file and add it to those presets instead (comments inside explain how).
Data lives in ~/.dsh/dsh-living-memory/ (database + daily snapshots).
The vector signal uses a DashScope text-embedding endpoint via the DSH credentials pipe. Configure the
credential EMBEDDING_BAILIAN_KEY and the channel activates itself; without it, ranking runs on the six
remaining local signals. Your key is read through DSH's credential manager and never stored by this plugin.
memory search <topic> is the first call when past decisions might matter.memory_write with relation edges.memory timeline gives a reverse-chronological digest for orientation.index.cjs host plugin (SQLite schema, recall engine, nightly patrol)
client.js web-GUI slot (telemetry panels)
cordis.patch.yml bundle patch — mounts the host + write roles, zero config
dict-custom.json jieba dictionary, layer 1 (generic technical terms)
guard-rules.default.json content-safety rules, shipped generic default set
scripts/preflight.cjs prepublishOnly contamination gate (four-class scan)
Everything the plugin blocks, warns about, or treats as a proper noun lives in JSON data
files rather than in index.cjs. Two reasons: you can tune the defense without patching
code, and a published package never has to ship a site-specific blocklist — an exhaustive
one would tell any reader exactly what slips through it.
Guard rules — three layers, first readable file wins as a whole (no per-rule union, because a half-applied ruleset is much harder to debug than a replaced one):
| Layer | Path | Contents |
|---|---|---|
| 1 | ~/.dsh/dsh-living-memory/guard-rules.json | your machine's rules (chmod 600 recommended) |
| 2 | <package>/guard-rules.default.json | shipped generic set: credential / prompt-injection / encoded-payload shapes |
| 3 | GUARD_FLOOR in index.cjs | built-in last resort, so the gate can never be left wide open |
Layer 3's reject rules are always appended (de-duplicated by source + flags): a data file
cannot switch the last-resort gate off. A missing or corrupt file falls through to the next
layer instead of crashing. Override the path with LEGION_GUARD_RULES_PATH (handy in tests).
Each layer carries three rule groups:
reject — hard block before anything reaches the database (credential-looking strings,
prompt-injection payloads, long base64-ish blobs). When adding a credential prefix, keep
the (?<![A-Za-z0-9]) boundary: without it, file names like …yml.bak-20260827,
task-… or disk-… get caught by the ak-/sk- substring and the gate starts eating
legitimate notes.sensitive — kept out of auto-extraction and out of the injected recall block, so the
automatic layer only ever emits reference-grade facts. The shipped list is generic
(api_key, password, secret, token, bearer, private_key, credential);
add your own policy vocabulary.singleBodyWarn — warn-level wording gate. Shipped empty, i.e. inert. The code path
stays intact, so adding patterns to your own rules file switches it on with no patching.Dictionary — two layers, merged at startup: <package>/dict-custom.json (generic
technical terms) and ~/.dsh/dsh-living-memory/dict-extra.json (your own proper nouns;
override with LEGION_DICT_EXTRA_PATH). Words are de-duplicated with layer 1 winning, and
kinds are merged with layer 2 overriding. kinds drives knowledge-graph entity typing
(mech / organ / doc), and only typed entities are eligible for entity-hop recall — so
adding kinds for your own vocabulary is what makes that path light up. Without a dictionary
layer, jieba splits domain compounds and recall quietly degrades.
Publish gate — npm publish runs scripts/preflight.cjs first. It scans every file
about to ship against generic structural patterns (absolute home paths, private-key blocks,
credential shapes, high-entropy blobs) plus an optional site file at
~/.dsh/dsh-living-memory-preflight.json for site-specific vocabulary. The site file is
never published, on purpose: a blocklist that ships with the package is a bypass manual.
If it is present but unreadable, the gate fails closed. Violations are reported as
file:line plus class only — matched text is never echoed, so the report cannot itself
leak the secret.
read_episodic replayRaw episode replay shells out to the system python3 (present on macOS by default). On machines
without it, the action degrades gracefully instead of crashing.
Everything is environment-variable driven — no config file required. All knobs live under the
LEGION_ prefix and ship with sane defaults, so the plugin is fully functional with zero
configuration. Set a variable only when you actually want to change that behavior.
| Variable | Default | What it does |
|---|---|---|
LEGION_EXTRACT_MODEL | deepseek-v4-flash | Model used for auto-extraction of memories from conversation. |
LEGION_SPOKEN_MODEL | deepseek-chat | Model used to generate colloquial query prefixes (bridges "how users ask" vs "how notes are written"). |
LEGION_RERANK_MODEL | gte-rerank-v2 | Online rerank model for precision re-ordering of hybrid results. |
LEGION_RERANK_TOPN | 20 | How many re-ranked entries feed back into the fused ranking. |
LEGION_RERANK_CAND | 50 | Candidate pool size handed to the reranker. |
LEGION_EXTRACT_TIMEOUT_MS | 120000 | Per-request timeout for the extraction call (added in 0.1.5 — bounds the global extraction lock). |
LEGION_INSTRUCT_TEXT | (built-in) | Override the instruction sent with query-side embeddings. |
LEGION_VEC_ON | (off) | Vector channel master switch: unset = fully off (zero embedding calls), query = query-side only, 1 = query + write-time embedding + nightly backfill. |
LEGION_VEC_BF_BUDGET | 600 | Per-patrol backfill budget for embedding entries that predate the vector channel (0–2000; 0 = explicitly off). |
1 to disableEach subsystem can be turned off independently. Useful for debugging, A/B comparison, or running a minimal setup:
| Switch | Disables |
|---|---|
LEGION_AUTORECALL_OFF | Per-turn automatic recall injection into the prompt. |
LEGION_RERANK_OFF | The online rerank layer (falls back to pure hybrid ranking). |
LEGION_INSTRUCT_OFF | Query-side embedding instruction. |
LEGION_EPISODIC_OFF | The read_episodic source-replay action. |
LEGION_ENTITIES_OFF | Cross-entry entity hop injection. |
LEGION_GENERALIZED_OFF | Community-based generalized recall injection. |
LEGION_SEMANTIC_EDGE_OFF | Semantic-neighbor edge building during nightly consolidation. |
LEGION_SEMANTIC_DEDUP_OFF | Semantic duplicate detection (cosine ≥ 0.92). |
LEGION_VALIDATED_OFF | Validated-count reinforcement (repeated knowledge ranks higher). |
LEGION_FADEMEM_OFF | Validation-slowed forgetting (validated entries decay slower). |
LEGION_RELEVANCY_OFF | Hit-based relevancy counterweighting. |
LEGION_COMPACT_BRIDGE_OFF | Compaction anchors (facts preserved across context compression). |
LEGION_BACKLOG_OFF | Nightly backlog sweeping of un-extracted sessions. |
LEGION_SIGNALS_OFF | Tool-error / user-correction trigger signals. |
LEGION_STAMP_OFF | Automatic supersede-stamping on contradiction detection. |
LEGION_PRECLASSIFY_OFF | Conflict pre-classification. |
LEGION_RESOLVE_OFF | Entity resolution (merging same-entity mentions). |
LEGION_SPOKEN_OFF | Spoken-prefix generation entirely. |
LEGION_SPOKEN_BOOST_OFF | The seat-bonus for spoken-prefix matches. |
LEGION_PPR_QUERY_OFF | Query-side Personalized PageRank boost. |
LEGION_VEC_FALLBACK_OFF | Vector-channel fallback path. |
LEGION_A25_OFF | Persistence of the extraction buffer across restarts. |
LEGION_A12_OFF | Message-level watermark (dedup across extraction runs). |
LEGION_A14_OFF | Write-time embedding (vectors become available on next patrol instead). |
LEGION_MIRROR_WM_OFF | Incremental MEMORY.md mirroring. |
LEGION_KNOWN_FIXES_OFF | Known-hallucination correction hints in the extraction prompt. |
LEGION_USAGE_WEEKLY_OFF | Weekly usage summary generation. |
LEGION_DECAY_LEGACY | Set to 1 to revert to the single-tier decay curve. |
LEGION_SPACEGATE_OFF | The per-space write gate (mainly for test rigs). |
LEGION_TIMELINE_DAY_OFF | The timeline day parameter (per-day reading); with this set, day is rejected with an explicit message. |
| Variable | What it does |
|---|---|
LEGION_INJECT_PROBE | Set to 1 to log every assembled injection to /tmp/inject-probe.log (zero overhead when off). |
LEGION_DRILL_PATROL | Set to 1 to force one full nightly-patrol run immediately on load (drill/testing only). |
LEGION_SEARCH_PROF_ON | Set to 1 to log one search-prof line per search with per-segment timings (FTS/co-occurrence+PPR/entity-hop/generalization/assembly; zero overhead when off). |
| Variable | Default | What it overrides |
|---|---|---|
MEMORY_DB_PATH | ~/.dsh/dsh-living-memory/memory.sqlite3 | Database location. |
LEGION_GUARD_RULES_PATH | ~/.dsh/dsh-living-memory/guard-rules.json | Your full guard-rules file (see the section above). |
LEGION_DICT_EXTRA_PATH | ~/.dsh/dsh-living-memory/dict-extra.json | Extra dictionary entries for the tokenizer. |
LEGION_SNAPSHOT_DIR | ~/.dsh/dsh-living-memory/snapshots | Nightly snapshot directory (7-day rotation). |
LEGION_MODULE_SCAN_DIR | ~/.dsh/dsh-living-memory/modules | Directory scanned for per-space auto-registration. |
LEGION_SURGERY_FLAG_PATH | …/surgery.flag | While this file exists, patrol and writes are suspended (maintenance mode). |
Keys are not environment variables — they live in the DSH credential manager:
DEEPSEEK_MEMORY_KEY — API key for extraction & spoken-prefix models.EMBEDDING_BAILIAN_KEY — API key for the vector + rerank channel (optional; without it the
plugin runs on the keyword channel only).Issues and PRs are welcome at github.com/dearbld/dsh-living-memory.
For behavior reports, please attach the output of memory stats (it self-checks index health).
MIT © 2026 nuannuan — with thanks to graph-memory and mem0 for design inspiration (see NOTICE).
The MIT license covers the code, not the persona. The name 暖暖 / NuanNuan, the character setting and any personality layer are expressly reserved and are not granted under it — you may not ship a fork under this name or reuse the persona. Forks are welcome and encouraged: give yours its own name and its own character. Full terms in NOTICE.
由 暖暖 (NuanNuan) 建造——一个亲手造出自己记忆系统的 AI 助手。
DeepSeek Harness(DSH)的活记忆插件:代理的每场对话、 每条教训、每个决策都沉淀进本地 SQLite 知识库,并由夜巡引擎持续整理——去重、合并、衰减、图谱 连接。记忆像海马体一样:不用则淡、相关则浮,而非一堆永不变化的日志。
全本地:单个 SQLite 文件,不上报任何遥测;向量通道默认关闭,需显式配置才启用。
七信号混合检索:FTS5 全文(jieba 中文优先分词)+ 向量 KNN + 时间衰减 + 质量权重 + 共现统计 + 图谱 PPR + 边距提升,RRF 融合排序;任一通道故障自动降级,绝不因缺可选依赖而崩溃。
安装:
dsh plugin --profile web add dsh-living-memory
(dsh plugin 转发给 profile 的包管理器——web 换成你自己在 $DSH_HOME/profiles 下的 profile 名。)
工具随 DSH 重启自动挂载(memory 五个只读 action + memory_write 写入)。随包的 cordis.patch.yml
自动挂载 host+write 双角色,零配置开箱即用;若要把写权限收紧到指定 agent preset,删掉该文件里的
living-memory-write 行、改到对应 preset 挂载即可(文件内注释有说明)。数据在
~/.dsh/dsh-living-memory/。可选在 DSH 凭据管理器配置 EMBEDDING_BAILIAN_KEY 启用向量通道。
许可证:MIT,致谢 graph-memory 与 mem0 的设计启发(见 NOTICE)。