Long-term memory for the DeepSeek Harness Web GUI: project-scoped + global memory stores with automatic extraction, automatic briefing injection, small-model periodic consolidation, and an Obsidian-style memory graph.
See README.zh.md for the full Chinese documentation.
Compatibility: this release is 2.1.0, adapted to harness 0.2.0 / 0.2.0-rc.2 — configuration travels through the package's Config export and apply(ctx, config), the session log is read with snapshotEvents(), and dsh.client.inject lists the owner packages of every seat. Harness 0.1.7+ removed settings.register(), so there is no hot-reloadable settings namespace or generated settings panel any more: configuration lives in the profile's cordis.patch.yml.
- Two scopes: per-workspace project memories (keyed by a hash of the session cwd) plus one global store; plain JSON under
~/.dsh/memory/(respects$DSH_HOME), atomic writes. - Memory view tab beside Chat/Trajectory: one-card-per-row list (type dot, tags, origin, reinforcement count, links) with inline edit/archive/link/delete, search, and a canvas force-directed graph with zoom/pan/drag, neighbor highlighting and a detail card.
- Auto injection: a global
system-prompt/assemblewaterfall listener appends the top-K memories (freshness x reinforcement x degree, interleaved scopes, char-capped) as a dynamic context; agentless assemblies get globals only; failures never touch the assembly. - Auto extraction: on
turn/end, new events are replayed as a transcript and distilled by the model into JSON candidates; near-duplicates (bigram Jaccard >= 0.65) reinforce instead of duplicating; 3 consecutive failures pause auto-extraction until a manual run recovers. - Periodic consolidation: every N extracted turns per scope (default 20) or on manual trigger, the model proposes merge/link/archive/retag ops that are id-validated and applied transactionally.
dsh plugin --profile web add <repo-or-local-path>
dsh web # restart, then refresh the page
Override the entry the plugin's own patch inserts (id: ui-memory). A profile patch replaces the entry's config wholesale, so write only the keys you want to change — the rest fall back to the Config schema defaults (and to the plugin's built-in DEFAULTS):
# ~/.dsh/profiles/web/cordis.patch.yml
- id: ui-memory
config:
enabled: true
injectEnabled: true
autoExtract: true
extractProvider: '' # pair with extractModel to pin a small model
extractModel: ''
manageProvider: '' # consolidation model provider (empty = fall back to extract*)
manageModel: ''
consolidateEveryTurns: 20
topK: 8
maxInjectChars: 1500
maxInputChars: 12000
maxTokens: 1024
autoArchiveDays: 90 # heuristic auto-archive age in days (0 = off)
memoryLocale: '' # force memory language: '' = follow the conversation, or zh/en
embeddingsEnabled: true # local semantic embeddings (needs the optional dependency)
embeddingRemoteHost: '' # HuggingFace mirror, e.g. https://hf-mirror.com
autoLinkThreshold: 0.78 # cosine threshold for auto-linking during consolidation (0 = off)The old ~/.dsh/settings.yaml namespace form no longer works on 0.1.7+.
lib/index.js— host half:Configexport +apply(ctx, config), injection/extraction listeners, consolidation pipeline, routes.lib/store.js— two-scope JSON store + durable cursors/counters.lib/util.js— pure helpers (scope keys, similarity, parsers, transcript builder, message-source classification).lib/embeddings.js— optional local embeddings (transformers.js WASM): vector sidecar + serial inference queue.lib/client.js— browser half (hand-written bundle): additiveconversation.viewentry, per-message remember action, global toast.test/smoke.cjs—node test/smoke.cjs.test/e2e-flow.cjs— six-stage end-to-end business flow (node test/e2e-flow.cjs).
- No hot configuration: with
settings.register()gone there is no equivalent live channel — a config change means editing the profile patch and reloading. snapshotEvents()is marked deprecated upstream (0.2.0 still ships it and it is the exact equivalent of the removedsession.eventsgetter). The plugin uses it to replay extraction transcripts; a future removal would require reading logs through an asynchronous session-query service.- Session navigation needs the Workspace UI:
sessions.open()was removed, so "open source session" callsuiWorkspace.openSession()and silently does nothing when that service is absent. - Semantic embeddings need
@huggingface/transformersresolvable from the plugin install (the 0.2.0 desktop asar no longer bundles it); otherwise retrieval degrades to lexical scoring. - Relevance recall approximates the current topic with the tail of recent human input (~2000 chars).
MIT