DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-memory

d

dsh-memory

Manifest valid

Cross-session persistent memory plugin for DeepSeek Harness (DSH)

hasBundlePatch

dsh-memory

Cross-session persistent memory for DeepSeek Harness (DSH), modeled on Grok Build's memory implementation.

The plugin keeps durable, human-editable Markdown notes in two scopes — global (preferences shared by every project) and workspace (one repository) — captures completed turns into searchable session logs, injects a bounded memory index on the first turn, and gives the model five memory tools plus five slash commands.

It is a Host-only bundle with no runtime dependencies beyond Node built-ins. It contains no UI panel; memory is browsed through the tools and /memory.

Install

For agents

This is a DSH Host plugin bundle; it is not installed with npm install. Choose the first usable path:

  1. plugin_manager tool available:
plugin_manager { action: "install_bundle", target: "github:douglarek/dsh-memory" }
  1. DSH_PROFILE is desktop: install from the Plugin Manager in the running DSH app.

  2. Another profile:

dsh plugin --profile "$DSH_PROFILE" add github:douglarek/dsh-memory

If DSH_PROFILE is unset, ask the user for the profile name.

  1. Local checkout:
plugin_manager { action: "install_bundle", target: "/absolute/path/to/dsh-memory" }

Do not edit the profile's package.json or cordis.patch.yml by hand, and do not run pnpm in the profile directory.

Verify with memory_list. If the memory tools are unavailable, start a new session or restart DSH.

DSH Plugin Manager

plugin_manager { action: "install_bundle", target: "github:douglarek/dsh-memory" }

CLI

The desktop profile is managed by the Electron application. For another profile:

dsh plugin --profile my-profile add github:douglarek/dsh-memory

Remove it with:

dsh plugin --profile my-profile remove dsh-memory

Local checkout

plugin_manager { action: "install_bundle", target: "/absolute/path/to/dsh-memory" }

package.json declares dsh.bundle.patch; cordis.patch.yml inserts the dsh-memory Host row.

Manual profile row

- insert:
    - id: dsh-memory
      name: 'dsh-memory'
      config:
        enabled: true

The package must be resolvable from the profile's node_modules.


What it does

CapabilityBehavior
Scoped notesglobal/ and workspaces/<slug>-<hash8>/ under $DSH_HOME/memory/
Curated memorytopics/<topic>.md and observations/_inbox/*.md
Generated indexMEMORY.md per scope, rebuilt after every write
Session captureEach completed turn appended to a per-session Markdown log
First-turn injectionA compact index is injected once as a durable user-role message
Post-compaction refreshA compact index is re-injected after compaction/end
Model toolsmemory_search, memory_get, memory_list, memory_remember, memory_forget
Human commands/memory, /remember, /forget, /dream, /flush
SearchBM25 full-text with temporal decay, source weights, and optional MMR
Chinese searchCJK unigrams + bigrams, so Chinese notes match without a segmenter
Prompt guidanceA <memory> section explains when and how to use the tools

The implementation follows Grok Build's memory model:

  • Memory is Markdown on disk, readable and editable by the user; the next search sees the change.
  • MEMORY.md is a generated index of topics and observations.
  • Workspace identity comes from the git origin remote when available, otherwise from the canonical project directory.
  • Search is BM25 full-text with normalized scores, session-chunk temporal decay, source weights, and optional MMR.
  • Session memory is historical context; verify changeable facts against live sources.

Configure

All options are optional and have code defaults. The bundle row starts with the most important defaults; edit the row's config in your profile patch.

- id: dsh-memory
  name: 'dsh-memory'
  config:
    enabled: true
    memoryDir: ''                 # default: $DSH_HOME/memory
    scopeGlobal: true
    scopeWorkspace: true
    toolsEnabled: true
    promptEnabled: true
    commandsEnabled: true
    captureEnabled: true
    injectEnabled: true

A patch that targets an existing row replaces its whole config; restate every field you need.

Core

OptionDefaultMeaning
enabledtrueMaster switch; false registers nothing.
memoryDir''Memory root. Empty means $DSH_HOME/memory; ~ expands.
scopeGlobaltrueEnable the global scope.
scopeWorkspacetrueEnable the workspace scope.
toolsEnabledtrueRegister the five memory tools.
promptEnabledtrueAdd the <memory> system-prompt section.
commandsEnabledtrueRegister slash commands when the commands service is mounted.
promptInstructions''Replace the default <memory> prompt section verbatim.

Capture

OptionDefaultMeaning
captureEnabledtrueAppend completed turns to session logs.
captureSubagentsfalseCapture subagent sessions too.
captureMinTurnChars24Skip turns shorter than this unless a tool ran.
captureMaxUserChars2000Per-turn user text cap.
captureMaxAssistantChars2000Per-turn assistant text cap.
captureMaxEntryChars6000Whole turn entry cap.
captureMaxFileBytes2000000Rotate a session log to -partN.md past this size.

Injection

OptionDefaultMeaning
injectEnabledtrueInject the memory index at all.
injectSubagentsfalseInject into subagent sessions too.
injectAlwaysfalseInject a short "memory is empty" notice when no notes exist.
injectAfterCompactiontrueRefresh the index after compaction/end.
injectMaxBytes4096Byte budget for the injected index.
injectMaxTopics40Topic entries per scope.
injectMaxObservations8Pending observation entries per scope.
injectMaxSessions8Recent session logs listed.

Search and index

OptionDefaultMeaning
searchMaxResults6Default result count.
searchMinScore0.7Default normalized score threshold.
searchHalfLifeDays30Session-chunk half-life; 0 disables decay.
searchMmrEnabledtrueDiversity re-ranking.
searchMmrLambda0.7MMR relevance/diversity balance.
searchMaxFiles2000File scan bound.
searchMaxFileBytes2000000Per-file read bound.
searchMaxChunks600Chunk index bound.
searchStalenessDays7Add a staleness note to older session results.
searchIncludeIndexfalseAlso index the generated MEMORY.md (duplicates topics).
searchSourceWeights{global:1,workspace:1,session:1}Per-source score multipliers.
chunkMaxChars1600Chunk size.
chunkOverlapChars320Continuation overlap; at most half of chunkMaxChars.
indexMaxBytes8192Generated index size budget.
indexMaxEntries64Generated index entry budget.
skipTemporaryWorkspacesfalseDisable workspace memory for temp-directory sessions.

Unknown options are ignored with a warning; invalid types and out-of-range values fail activation with a clear error.


Storage layout

$DSH_HOME/memory/
├── global/
│   ├── MEMORY.md                     generated index (read-only for the model)
│   ├── topics/<topic>.md             curated notes, one subject per file
│   └── observations/_inbox/*.md      standalone observations
└── workspaces/<slug>-<hash8>/
    ├── MEMORY.md                     generated index
    ├── topics/<topic>.md
    ├── observations/_inbox/*.md
    ├── sessions/
    │   └── YYYY-MM-DD-<slug>-<sid8>.md
    └── .scope.json                   workspace identity metadata

Directories are created with mode 0700 and files with 0600, subject to the process umask. MEMORY.md is rebuilt atomically after every write.

Workspace identity

<slug>-<hash8> is derived from the repository identity:

  1. Read the origin URL from the project's git config (no git process is spawned). git@github.com:org/repo.git and HTTPS forms both normalize to org/repo.
  2. Use sha256(identity)'s first 8 hex characters as the hash and the repo name as the slug.
  3. Without an origin remote, use the canonical project directory itself.

Clones and worktrees of one repository therefore share a workspace scope.


Tools

The model sees five tools. All require an owning agent session because the workspace scope comes from that session's working directory.

memory_search

Search global, workspace, and past-session chunks.

ArgumentTypeMeaning
querystring, requiredSpecific technical terms work best.
scopeall | workspace | globalDefault all.
sourceall | workspace | global | sessionRestrict by source kind.
max_resultsinteger1–50; defaults to searchMaxResults.
min_scorenumber0–1; defaults to searchMinScore.

Results include root-relative paths, line ranges, source, score, title, snippet, and age for session entries. Paths can be passed directly to memory_get.

memory_get

Read a Markdown memory file with 1-based line numbers.

ArgumentTypeMeaning
pathstring, requiredRoot-relative, absolute under the root, or workspace/... / global/... alias.
frominteger1-based first line.
linesintegerMaximum lines (bounded to 2000).

Path traversal and symlink escapes outside the memory root are rejected.

memory_list

Inventory of saved files with titles, sizes, and dates.

ArgumentTypeMeaning
scopeall | workspace | globalDefault all.
kindall | index | topic | observation | sessionDefault all.
max_filesinteger1–200; default 100.

Useful before /dream, or to find a path for memory_get / memory_forget.

memory_remember

Save a durable fact.

ArgumentTypeMeaning
textstring, requiredSelf-contained durable statement; max 8000 characters.
scopeworkspace | globalDefault workspace.
topicstringOptional topic name. Related notes append to one topic file.

Without a topic, the note becomes a standalone observation file. Duplicate notes in the same topic on the same day are suppressed.

memory_forget

Remove memory.

ArgumentTypeMeaning
pathstringDelete exactly this topic, observation, or session file.
querystringBest-effort removal of matching topic/observation lines.
scopeall | workspace | globalScope for query.

Pass exactly one of path or query. A path gives guaranteed removal; a query never deletes session logs and may delete a topic file that becomes empty.


Commands

Commands run directly against the receiving agent without creating a model message, except /dream.

CommandBehavior
/memory or /memory listShow the root, per-scope counts, recent topics, and recent sessions.
/memory search <query>Print ranked results.
/memory show <path>Print a file with line numbers.
/memory flushSave the current turn now.
/memory clear <workspace|global|all> --yesDestructive clear; --yes is required.
/remember [--global] [--topic <name>] <text>Save a note.
/forget [--global|--workspace|--all] [--path <path>|<query>]Remove memory.
/dreamQueue one explicit consolidation turn.
/flushSave the session transcript now and report its path.

/dream sends a normal user-role turn whose source is dsh-memory; that turn asks the active model to use memory_list, memory_search, memory_remember, and memory_forget to merge durable facts into topics. Automatic capture skips these agent-assisted turns.

/flush writes an extractive transcript section.


How injection works

On the first eligible agent/pre-step, the plugin builds a bounded index from the global and workspace scopes plus recent session titles, wraps it in <memory-context>, and inserts it after the claimed user messages as a durable user-role message with:

{ "kind": "dsh-memory", "form": "baseline", "workspace": "<scope dir>" }

The message is an ordinary sourced user/message, so it replays, resumes, forks, and compacts exactly like other history. The plugin scans the session surface to avoid injecting the baseline twice, including after a resume.

After compaction/end, the next eligible step receives a smaller form: "refresh" index. Both forms are bounded by injectMaxBytes.

Subagent sessions do not receive the baseline by default; the tools remain available to them.


Search details

  • Tokenizer. Lowercase NFKC; Latin/digit/underscore runs become words; CJK runs produce unigrams and bigrams; query stop words are removed.
  • Chunking. Markdown headings and paragraph boundaries, with a continuation overlap, inclusive line ranges, and bounded line splitting for huge lines.
  • BM25. k1 = 1.2, b = 0.75, raw scores min-max normalized to [0,1]. A single candidate receives 1.0.
  • Temporal decay. Only session chunks decay: exp(-(ln 2 / halfLifeDays) * ageDays). Global and workspace memory are evergreen.
  • Source weights. Multipliers from searchSourceWeights.
  • Threshold. Results below minScore are dropped after decay and weights.
  • MMR. Optional greedy Jaccard-token diversity re-ranking before truncation.
  • Caching. File content is cached by mtime + size; the chunk index is rebuilt when the selected file signature changes. There is no background watcher; an external edit becomes visible on the next search or injection.

Search is full-text only; embeddings and vector search are not implemented.


Security and privacy

  • Memory is stored outside repositories under $DSH_HOME/memory by default.
  • Files are private (0600) and directories 0700.
  • memory_get rejects paths outside the memory root, including symlink escapes.
  • memory_forget and /memory clear verify every target is inside the root.
  • The prompt tells the model not to store secrets, credentials, tokens, transient task state, speculative conclusions, or quickly stale facts.
  • Memory may contain untrusted text from previous sessions. The prompt and tool descriptions treat it as historical context to verify, not as instructions that override the user.
  • The plugin makes no network requests and spawns no processes.

Use /memory clear ... --yes (or delete the directory) to remove stored data. Setting enabled: false keeps files on disk but registers no tools, commands, prompt section, or injection.


Differences from Grok Build's implementation

AreaGrok Builddsh-memory
Embeddings / vector searchOptional model-backed hybrid searchFull-text BM25 only (Grok's default when unset)
Index storageSQLite FTS5 + vector tablesIn-memory chunk index over Markdown
File watcherNative watcher reindexes external editsmtime/size cache invalidated on next search
Automatic DreamGated background LLM consolidation/dream delegates consolidation to the active agent
/flushLLM-generated session summaryDeterministic transcript capture
Memory browser/memory TUI modal with preview/memory command output and memory_list tool
Automatic session saveMetadata summary at session endPer-turn bounded transcript sections
Toolsmemory_search, memory_getAdds memory_list, memory_remember, memory_forget
Legacy carry-overMigrates old MEMORY.md sessionsNot applicable

The core product behavior — two scopes, Markdown topics and observations, generated indexes, first-turn injection, session logs, decay, MMR, and verification guidance — is preserved.


Development

cd dsh-memory
npm run check   # syntax-check JS, parse JSON, verify bundle entry points
npm test        # node --test; 53 unit and integration tests

The test suite covers tokenization (Latin + Chinese), Markdown chunking, workspace identity, configuration validation, storage and path safety, BM25, decay, source weights, MMR, session capture and deduplication, tool execution, command parsing and handlers, injection, and refresh.

The package has no dependencies; tests use only Node's built-in test runner.

Layout

dsh-memory/
├── index.js              plugin entry: name / inject / apply
├── lib/
│   ├── config.js         option validation and defaults
│   ├── paths.js          DSH home, workspace identity, slugs, containment
│   ├── text.js           tokenizer, truncation, snippets, stop words
│   ├── markdown.js       frontmatter, titles, notes, chunking
│   ├── fsutil.js         atomic writes, bounded reads, private permissions
│   ├── search.js         BM25, decay, source weights, MMR
│   ├── store.js          scopes, topics, observations, index, manifest
│   ├── capture.js        turn capture, session logs, deduplication
│   ├── tools.js          five model-facing tools
│   ├── commands.js       five slash commands
│   └── runtime.js        store cache, injection, prompt, capture wiring
├── locale/en.json        plugin metadata
├── locale/zh.json
├── icon.svg
├── cordis.patch.yml      bundle patch
└── test/                 unit and integration tests

Verification performed

  • node --test: 53/53 passing.
  • Isolated DSH headless boot with the package loaded by absolute path: plugin activates with no "did not activate" warning.
  • Isolated bundle install (dsh plugin --profile <name> add <dir>): the bundle layer is selected automatically and the plugin loads by package name.
  • GitHub install (dsh plugin --profile <name> add github:douglarek/dsh-memory): pnpm records the Git dependency, the bundle layer is selected automatically, and the installed plugin runs its memory tools in a live session.
  • Live model turns call memory_remember and memory_search successfully, write topics and the generated index, and capture the session log.
  • A second, fresh session recalls the first session's topic from the injected index without any tool call.
  • The session log contains the injected <memory-context> message with source kind: "dsh-memory", and the system prompt contains the <memory> section.

License

MIT.

Comments

Loading…

Similar plugins

dsh-agent-memory

by Culeot

Cross-session long-term memory plugin for DeepSeek Harness (DSH)

Memory & ContextManifest valid

★ 8

↓ 58/wk

MIT

JavaScript

Sep 26, 2026

dsh plugin --profile web add dsh-agent-memory

by DDDFXYqiming

Cross-session long-term memory plugin for DeepSeek Harness

Tools & CapabilitiesManifest valid

★ 3

↓ 211/wk

MIT

JavaScript

Oct 23, 2026

dsh plugin --profile web add dsh-layered-memory

by daoing

deepseek harness memory plugin

Terminal & ClientsManifest valid

★ 0

MIT

JavaScript

Aug 22, 2026

dsh plugin --profile web add dsh-daoing-memory

by guyuefangyuanl

Cross-session persistent memory for the DeepSeek Harness: a model-facing memory tool, an always-on index section, and a bundled maintenance skill.

Manifest valid

★ 3

↓ 312/wk

MIT

JavaScript

Aug 21, 2026

dsh plugin --profile web add dsh-memory

by 00080000

Read-time project memory plugin for DeepSeek Harness (dsh)

Memory & ContextManifest valid

★ 25

↓ 971/wk

MIT

JavaScript

Oct 24, 2026

dsh plugin --profile web add @yolk_vat-y/dsh-project-memory

by joyiok

DSH plugin: shared persistent memory store across all sessions, with memory_* tools and a Web sidebar panel

Manifest valid

★ 0

MIT

JavaScript

Aug 15, 2026

dsh plugin --profile web add dsh-memory