dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Cross-session persistent memory plugin for DeepSeek Harness (DSH)
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.
This is a DSH Host plugin bundle; it is not installed with npm install.
Choose the first usable path:
plugin_manager tool available:plugin_manager { action: "install_bundle", target: "github:douglarek/dsh-memory" }
DSH_PROFILE is desktop: install from the Plugin Manager in the running
DSH app.
Another profile:
dsh plugin --profile "$DSH_PROFILE" add github:douglarek/dsh-memory
If DSH_PROFILE is unset, ask the user for the profile name.
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.
plugin_manager { action: "install_bundle", target: "github:douglarek/dsh-memory" }
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
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.
- insert:
- id: dsh-memory
name: 'dsh-memory'
config:
enabled: true
The package must be resolvable from the profile's node_modules.
| Capability | Behavior |
|---|---|
| Scoped notes | global/ and workspaces/<slug>-<hash8>/ under $DSH_HOME/memory/ |
| Curated memory | topics/<topic>.md and observations/_inbox/*.md |
| Generated index | MEMORY.md per scope, rebuilt after every write |
| Session capture | Each completed turn appended to a per-session Markdown log |
| First-turn injection | A compact index is injected once as a durable user-role message |
| Post-compaction refresh | A compact index is re-injected after compaction/end |
| Model tools | memory_search, memory_get, memory_list, memory_remember, memory_forget |
| Human commands | /memory, /remember, /forget, /dream, /flush |
| Search | BM25 full-text with temporal decay, source weights, and optional MMR |
| Chinese search | CJK unigrams + bigrams, so Chinese notes match without a segmenter |
| Prompt guidance | A <memory> section explains when and how to use the tools |
The implementation follows Grok Build's memory model:
MEMORY.md is a generated index of topics and observations.origin remote when available,
otherwise from the canonical project directory.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.
| Option | Default | Meaning |
|---|---|---|
enabled | true | Master switch; false registers nothing. |
memoryDir | '' | Memory root. Empty means $DSH_HOME/memory; ~ expands. |
scopeGlobal | true | Enable the global scope. |
scopeWorkspace | true | Enable the workspace scope. |
toolsEnabled | true | Register the five memory tools. |
promptEnabled | true | Add the <memory> system-prompt section. |
commandsEnabled | true | Register slash commands when the commands service is mounted. |
promptInstructions | '' | Replace the default <memory> prompt section verbatim. |
| Option | Default | Meaning |
|---|---|---|
captureEnabled | true | Append completed turns to session logs. |
captureSubagents | false | Capture subagent sessions too. |
captureMinTurnChars | 24 | Skip turns shorter than this unless a tool ran. |
captureMaxUserChars | 2000 | Per-turn user text cap. |
captureMaxAssistantChars | 2000 | Per-turn assistant text cap. |
captureMaxEntryChars | 6000 | Whole turn entry cap. |
captureMaxFileBytes | 2000000 | Rotate a session log to -partN.md past this size. |
| Option | Default | Meaning |
|---|---|---|
injectEnabled | true | Inject the memory index at all. |
injectSubagents | false | Inject into subagent sessions too. |
injectAlways | false | Inject a short "memory is empty" notice when no notes exist. |
injectAfterCompaction | true | Refresh the index after compaction/end. |
injectMaxBytes | 4096 | Byte budget for the injected index. |
injectMaxTopics | 40 | Topic entries per scope. |
injectMaxObservations | 8 | Pending observation entries per scope. |
injectMaxSessions | 8 | Recent session logs listed. |
| Option | Default | Meaning |
|---|---|---|
searchMaxResults | 6 | Default result count. |
searchMinScore | 0.7 | Default normalized score threshold. |
searchHalfLifeDays | 30 | Session-chunk half-life; 0 disables decay. |
searchMmrEnabled | true | Diversity re-ranking. |
searchMmrLambda | 0.7 | MMR relevance/diversity balance. |
searchMaxFiles | 2000 | File scan bound. |
searchMaxFileBytes | 2000000 | Per-file read bound. |
searchMaxChunks | 600 | Chunk index bound. |
searchStalenessDays | 7 | Add a staleness note to older session results. |
searchIncludeIndex | false | Also index the generated MEMORY.md (duplicates topics). |
searchSourceWeights | {global:1,workspace:1,session:1} | Per-source score multipliers. |
chunkMaxChars | 1600 | Chunk size. |
chunkOverlapChars | 320 | Continuation overlap; at most half of chunkMaxChars. |
indexMaxBytes | 8192 | Generated index size budget. |
indexMaxEntries | 64 | Generated index entry budget. |
skipTemporaryWorkspaces | false | Disable 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.
$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.
<slug>-<hash8> is derived from the repository identity:
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.sha256(identity)'s first 8 hex characters as the hash and the repo name
as the slug.origin remote, use the canonical project directory itself.Clones and worktrees of one repository therefore share a workspace scope.
The model sees five tools. All require an owning agent session because the workspace scope comes from that session's working directory.
memory_searchSearch global, workspace, and past-session chunks.
| Argument | Type | Meaning |
|---|---|---|
query | string, required | Specific technical terms work best. |
scope | all | workspace | global | Default all. |
source | all | workspace | global | session | Restrict by source kind. |
max_results | integer | 1–50; defaults to searchMaxResults. |
min_score | number | 0–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_getRead a Markdown memory file with 1-based line numbers.
| Argument | Type | Meaning |
|---|---|---|
path | string, required | Root-relative, absolute under the root, or workspace/... / global/... alias. |
from | integer | 1-based first line. |
lines | integer | Maximum lines (bounded to 2000). |
Path traversal and symlink escapes outside the memory root are rejected.
memory_listInventory of saved files with titles, sizes, and dates.
| Argument | Type | Meaning |
|---|---|---|
scope | all | workspace | global | Default all. |
kind | all | index | topic | observation | session | Default all. |
max_files | integer | 1–200; default 100. |
Useful before /dream, or to find a path for memory_get / memory_forget.
memory_rememberSave a durable fact.
| Argument | Type | Meaning |
|---|---|---|
text | string, required | Self-contained durable statement; max 8000 characters. |
scope | workspace | global | Default workspace. |
topic | string | Optional 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_forgetRemove memory.
| Argument | Type | Meaning |
|---|---|---|
path | string | Delete exactly this topic, observation, or session file. |
query | string | Best-effort removal of matching topic/observation lines. |
scope | all | workspace | global | Scope 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 run directly against the receiving agent without creating a model
message, except /dream.
| Command | Behavior |
|---|---|
/memory or /memory list | Show 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 flush | Save the current turn now. |
/memory clear <workspace|global|all> --yes | Destructive clear; --yes is required. |
/remember [--global] [--topic <name>] <text> | Save a note. |
/forget [--global|--workspace|--all] [--path <path>|<query>] | Remove memory. |
/dream | Queue one explicit consolidation turn. |
/flush | Save 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.
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.
k1 = 1.2, b = 0.75, raw scores min-max normalized to [0,1].
A single candidate receives 1.0.session chunks decay:
exp(-(ln 2 / halfLifeDays) * ageDays). Global and workspace memory are
evergreen.searchSourceWeights.minScore are dropped after decay and weights.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.
$DSH_HOME/memory by default.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.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.
| Area | Grok Build | dsh-memory |
|---|---|---|
| Embeddings / vector search | Optional model-backed hybrid search | Full-text BM25 only (Grok's default when unset) |
| Index storage | SQLite FTS5 + vector tables | In-memory chunk index over Markdown |
| File watcher | Native watcher reindexes external edits | mtime/size cache invalidated on next search |
| Automatic Dream | Gated background LLM consolidation | /dream delegates consolidation to the active agent |
/flush | LLM-generated session summary | Deterministic transcript capture |
| Memory browser | /memory TUI modal with preview | /memory command output and memory_list tool |
| Automatic session save | Metadata summary at session end | Per-turn bounded transcript sections |
| Tools | memory_search, memory_get | Adds memory_list, memory_remember, memory_forget |
| Legacy carry-over | Migrates old MEMORY.md sessions | Not 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.
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.
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
node --test: 53/53 passing.dsh plugin --profile <name> add <dir>): the bundle
layer is selected automatically and the plugin loads by package name.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.memory_remember and memory_search successfully, write
topics and the generated index, and capture the session log.<memory-context> message with source
kind: "dsh-memory", and the system prompt contains the <memory> section.MIT.