DeepSeek Harness plugin

dsh-memory-graph

Non-invasive SQLite hybrid memory and knowledge-graph plugin for DeepSeek Harness

Jump to install

Source facts

Repository
zmh2000829/dsh-memory-graph
Latest update
Aug 20, 2026
Category
Docs & Rendering
GitHub stars
0
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/zmh2000829/dsh-memory-graph
Plugin: dsh-memory-graph
Author: zmh2000829

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer4 files
README.mdSource · read only
README language

<div align="center">

dsh-memory-graph

Local-first long-term memory and a temporal knowledge graph for DeepSeek Harness.

![CI](https://github.com/zmh2000829/dsh-memory-graph/actions/workflows/ci.yml) ![Version](package.json) ![Node.js](package.json) ![License](LICENSE)

简体中文 · [Installation](#installation) · [Configuration](#configuration) · [Security](#data-and-security)

</div>

dsh-memory-graph gives a DSH agent durable, auditable memory without changing DeepSeek Harness itself. It is installed as a regular Cordis plugin, stores data in a private local SQLite database, recalls relevant facts before the first model step, and renders the resulting entity graph inside DSH Web.

Why dsh-memory-graph

  • Non-invasive by design. No Harness source patch and no agent-loop fork. Unloading the plugin removes its tools, listeners, route, and UI contributions.
  • Memory with history. Stable facts are superseded instead of overwritten, retain provenance, and can be reverted to the previous version.
  • A maintainable graph. Canonical names, non-destructive alias conflict reporting, duplicate suggestions, entity merge/rename/delete, orphan discovery, reference-aware garbage collection, and normalized predicates keep the graph usable after months of conversations.
  • Chinese retrieval that works. FTS5 trigram indexing plus a short-query fallback handles continuous CJK text without relying on whitespace tokenization.
  • Hybrid relevance. Recall combines lexical match, graph proximity, importance, time decay, and explicit access reinforcement. Automatic recall is read-only and does not artificially keep old memories alive.
  • Optional semantic recall. An OpenAI-compatible embedding endpoint can add cosine similarity to the local hybrid ranker. It is off by default and falls back to lexical/graph recall when no key or endpoint is available.
  • Bounded hot paths. Write-side embedding runs in a deduplicating background queue. Query-side embedding uses a short timeout, TTL cache, and failure cooldown instead of exposing the 20-second indexing timeout to tools or first-step injection.
  • A real per-turn control. DSH Web exposes Default, On this turn, and Off this turn beside the composer. The choice is latched for the next turn only and then resets.
  • Recoverable source archives. Completed turns can retain bounded local source text, optionally including bounded tool results. Failed extraction can be retried without replaying the conversation.
  • Durable failure handling. Retryable SQLite writes enter a private file outbox and replay at startup; malformed or permanent failures move to a dead-letter directory.
  • Inspectable, not opaque. Every automatic memory can retain session, turn, event sequence, model route, extraction request, and extraction response.
  • Local-first and fail-open. The database stays on the host. Background summarization failures are logged but never replace or block the original agent response.

Architecture

flowchart LR
  T["Conversation turn"] --> C["Per-turn policy"]
  C --> X["Local turn archive"]
  X --> S["Background summarizer"]
  S --> M["Temporal memory store"]
  M <--> G["Canonical entity graph"]
  M --> R["Hybrid recall"]
  E["Optional embedding endpoint"] -.-> R
  G --> R
  R --> A["First agent step"]
  M --> V["DSH Web graph"]
  G --> V
  B["JSONL backup"] <--> M

The plugin uses DSH lifecycle extension points only. Model-visible recalled context is written to the session log, so a recorded session remains reconstructable.

Requirements

  • DeepSeek Harness with a configured profile such as web
  • Node.js ^22.19.0 or >=24.0.0
  • Git and npm

Confirm that the CLI and profile are available:

dsh --version
dsh plugin --profile web list

Installation

The project is currently distributed directly from GitHub. Clone it, validate it, then link the local checkout into a DSH profile:

git clone https://github.com/zmh2000829/dsh-memory-graph.git
cd dsh-memory-graph
npm ci
npm run check
dsh plugin --profile web add "$PWD"
dsh web

Open the DSH Web interface and expand Memory in the sidebar. The default patch enables automatic recall, automatic turn summarization, and visualization.

The dashboard leads with what DSH remembers and how it can affect later answers. Before a response, relevant durable preferences, facts, constraints, decisions, and lessons can be recalled into context. After a successful turn, reusable information can be extracted without treating every message as memory. This usually works quietly and only for a relevant future question.

The Knowledge graph is a collapsed advanced view over the profile-wide database shared by all conversations, not a diagram of the open conversation. Nodes are extracted entities, edges are relationships, and ×N means N memories support the same relationship. It is useful for inspecting associations, duplicate entities, and incorrect relationships; the memory list is the primary view for understanding what may influence an answer. Use a separate profile or database path when isolation is required.

New summaries default to summaryLanguage: auto, which follows the dominant user language and emits Simplified Chinese for Chinese conversations while preserving established proper names. Existing English records are not silently translated or rewritten during upgrade.

Before submitting a prompt, the native-style Memory · On, Memory · Off, or Memory · Mixed control shows the effective profile defaults directly. Its menu can use that profile default or override the next turn only. On once forces recall, archive, and summarization even when their global defaults are off; Off once suppresses those automatic actions. The override resets after the turn, and manual memory_* tools remain available. Delete buttons permanently remove a selected memory and its provenance-owned relations after confirmation.

Verify the installed link at any time:

dsh plugin --profile web list dsh-memory-graph

Upgrade

The profile points to the local checkout, so an upgrade does not require reinstalling the plugin entry:

cd /path/to/dsh-memory-graph
git pull --ff-only
npm ci
npm run check

Restart the running DSH process after the check completes. Database schema migrations run transactionally when the plugin starts.

Uninstall

dsh plugin --profile web remove dsh-memory-graph

Uninstalling removes the profile link but deliberately preserves the database and JSONL backups. Delete those files separately only when permanent data removal is intended.

Configuration

[cordis.patch.yml](cordis.patch.yml) contains a production-ready local profile. Change the plugin entry in your profile and restart DSH for updates to take effect.

- id: memory-graph
  name: dsh-memory-graph
  config:
    enabled: true
    path: !!js dshHomePath('memory-graph.sqlite')
    backupDirectory: !!js dshHomePath('memory-graph-backups')
    outboxDirectory: !!js dshHomePath('memory-graph-outbox')

    autoRecall: true
    autoRecallLimit: 4
    autoRecallMinScore: 0.18
    maxContextTokens: 1200
    recallPreviewTokens: 220

    predicateAliases:
      created_by: developed_by

    autoSummarize: true
    archiveTurns: true
    archiveMaxInputTokens: 30000
    archiveRetentionDays: 30
    archiveMaxTurnsPerSession: 200
    captureToolResults: false
    summarizeEveryTurns: 1
    summaryConcurrency: 2
    summaryMaxAttempts: 2
    summaryRetryBaseMs: 1000
    summaryRetryFailedOnStart: 3
    summaryLanguage: auto
    summaryMaxInputTokens: 6000
    summaryMaxOutputTokens: 3200

    semanticEnabled: false
    semanticEndpoint: https://api.openai.com/v1/embeddings
    semanticModel: text-embedding-3-small
    semanticApiKeyEnv: OPENAI_API_KEY
    semanticQueryTimeoutMs: 3500
    semanticQueryCacheMs: 300000
    semanticFailureCooldownMs: 60000

    visualizationEnabled: true
    visualizationAutoOpen: true
    visualizationRefreshMs: 5000

The major switches are independent:

OptionDefault patchPurpose
enabledtrueMaster switch for the entire plugin
autoRecalltrueRecall relevant memory before the first step of each turn
autoSummarizetrueExtract structured memory after successful turns
archiveTurnstrueRetain a bounded local source transcript for enabled completed turns
archiveRetentionDays30Delete turn archives older than the retention window
archiveMaxTurnsPerSession200Keep only the newest bounded archive count per session
captureToolResultsfalseInclude bounded tool result text in archives and extraction input
summaryLanguageautoFollow the user's dominant language, or force zh-CN/en
semanticEnabledfalseAdd optional embedding similarity; lexical/graph fallback remains available
visualizationEnabledtrueRegister the dashboard, turn selector, tool views, and protected action route
visualizationAutoOpentrueExpand the sidebar graph when DSH Web starts

summaryProvider and summaryModel may be configured together to route extraction to a lower-cost or local model. When omitted, summarization uses the current session route. summaryReasoningEffort is optional and must be supported by that exact model; leave it unset unless the model advertises the chosen effort. Summary calls are serialized per session, bounded globally by summaryConcurrency, and retried only up to summaryMaxAttempts; startup also retries the oldest failed archives up to summaryRetryFailedOnStart. predicateAliases maps deployment-specific predicate spellings to one normalized vocabulary. Ranking weights, graph depth, limits, decay, timeouts, and summary thresholds are all configurable in [cordis.patch.yml](cordis.patch.yml).

maxContextTokens and summaryMaxInputTokens use a conservative CJK-aware estimate (approximately 1.5 tokens per CJK character and one token per four other characters). Character limits remain hard size ceilings. Preference and temporal signals, lexical overlap, normalized-content deduplication, graph proximity, and optional semantic scores feed the same bounded ranker.

Semantic recall requires an OpenAI-compatible embeddings endpoint. Set semanticEnabled: true, configure the endpoint/model, export the key named by semanticApiKeyEnv, restart DSH, and run memory_semantic_reindex once for existing memories. Use an empty semanticApiKeyEnv only for a trusted keyless local endpoint. Write indexing runs in the background; query fallback is bounded by semanticQueryTimeoutMs, semanticQueryCacheMs, and semanticFailureCooldownMs. At least one non-semantic ranking weight must remain positive so endpoint failure always produces finite scores.

For non-loopback Web deployments, add the exact host or host:port values to visualizationTrustedHosts. Remote access is denied by default.

Tools

ToolPurpose
memory_rememberAtomically write a memory, canonical entities, aliases, and directed relations
memory_recallRun hybrid ranked retrieval with optional graph context
memory_expandExpand one layered recall preview to full stored text
memory_graphExplore a bounded neighborhood or the global graph overview
memory_forgetDelete one memory and relations produced by it
memory_archive_expandRead the bounded retained tail for one turn and report clipping explicitly
memory_archive_retryRetry extraction from a failed turn archive
memory_semantic_reindexEmbed existing active memories when semantic recall is configured
memory_entity_mergeMerge duplicate nodes and redirect relations
memory_entity_find_duplicatesPreview conservative duplicate candidates without changing the graph
memory_entity_renameChange an entity's canonical display name
memory_entity_deleteRemove an entity with explicit reference handling
memory_entity_orphansList graph nodes with no active memory references
memory_revertRestore the previous superseded version of a stable fact
memory_backupExport or restore an exact JSONL database snapshot

Entity and relation counts returned by write tools represent net-new records. Supplemental aliases never cause an implicit destructive merge: a conflicting alias remains with its existing owner and is reported to the caller. Manual rename records a preferred display spelling separately from occurrence counts. Predicates normalize to lowercase snake_case, with optional configured aliases.

Visualization

DSH Web receives an interactive graph with search, drag, zoom, memory details, permanent deletion, effective configuration status, and periodic refresh. Repeated source-provenanced facts are aggregated into one visible relation with a mention count. The sidebar reads the store directly through /memory-graph/snapshot; opening the graph never requires a model call. ETag revalidation avoids unchanged state updates, and polling pauses while the page is hidden. Explicit mutations use a same-origin, token-protected POST endpoint.

Visualization failure is isolated from tool rendering. If the dashboard route is unavailable, historical memory_graph tool results still replay normally.

Backup and recovery

Use memory_backup with operation: "export" before migrations, experiments, or manual cleanup. A restore is accepted only when the target database is empty, preventing an import from silently overwriting existing memory.

Backup paths are confined to the real backupDirectory, import rejects file symlinks that resolve outside it, and file names cannot contain directory components. The JSONL importer applies database defaults for columns absent from an older compatible backup. The format captures memories, embeddings, turn archives, entities, aliases, relations, provenance, and summary history.

Data and security

  • The default database is $DSH_HOME/memory-graph.sqlite and is created with mode 0600.
  • The store rejects an incompatible schema and databases owned by another application.
  • Dashboard reads return Cache-Control: no-store; writes require POST, JSON, a process-random token, and validated Host, Origin, and Fetch Metadata.
  • Recalled memory is explicitly framed as reference data rather than instructions.
  • Automatic summarization sends the selected conversation excerpt to the configured model route. Disable autoSummarize or use a local route when that data must not leave the host.
  • archiveTurns stores a bounded turn tail locally and applies both age and per-session count retention. memory_archive_expand.truncated says explicitly whether the archive is complete. captureToolResults is off by default because tool output may contain sensitive data.
  • Semantic recall sends memory/query text to semanticEndpoint only when explicitly enabled. Use a local endpoint when those texts must not leave the host.

Current scope

  • The plugin consumes an embedding service but does not ship one. New memories are indexed automatically; existing memories require memory_semantic_reindex.
  • Storage uses synchronous node:sqlite DatabaseSync. It is appropriate for a personal local memory store, not a multi-host database or a high-concurrency write service.
  • A single DSH process should own a writable database. SQLite WAL and a bounded busy timeout protect normal transactions, but this plugin does not provide distributed writer coordination.
  • node:sqlite may emit an experimental API warning on supported Node.js releases.
  • JSONL restore intentionally requires an empty database.

Development

npm ci
npm run typecheck
npm test
npm run build
npm pack --dry-run

npm run check runs type checking, all unit tests, and the production build. See [CONTRIBUTING.md](CONTRIBUTING.md) before proposing a change.

Release history is recorded in [CHANGELOG.md](CHANGELOG.md). The reviewed improvement decisions and remaining roadmap are maintained in [IMPROVEMENTS.md](IMPROVEMENTS.md). The source-level comparison with OpenViking's DSH adapter is in [COMPARISON.md](COMPARISON.md).

License

[MIT](LICENSE) © dsh-memory-graph contributors.