DeepSeek Harness Plugin

qwert702/dsh-memory

Stars ★ 2 Category Memory Added 2026-09-12

Project+global long-term memory for the dsh web GUI: split POST /items endpoints, tool-call context merged into memory items as compact summaries, with deduplication and session-scoped persistence.

Install

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:qwert702/dsh-memory

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

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.

Highlights

  • 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/assemble waterfall 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.

Install

dsh plugin --profile web add <repo-or-local-path>
dsh web   # restart, then refresh the page

Configuration (profile cordis.patch.yml)

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+.

Layout

  • lib/index.js — host half: Config export + 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): additive conversation.view entry, 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).

Known limitations

  • 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 removed session.events getter). 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" calls uiWorkspace.openSession() and silently does nothing when that service is absent.
  • Semantic embeddings need @huggingface/transformers resolvable 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

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.