Provides task-isolated long-term memory for DeepSeek Harness: each task's memory is stored separately, with memory read, write, retrieval, and prompt injection only effective within the current task.
- Language
- JavaScript
- License
- MIT
- Branch
- main
Install
$ dsh plugin --profile web add github:wangyihao0001-oss/dsh-task-memoryRun the command above in your terminal to install this plugin via the dsh CLI. You can switch Profile in the top-right corner. New to dsh? Read the beginner tutorial
Install via your agent
Install the DeepSeek Harness plugin wangyihao0001-oss/dsh-task-memory for me: review the repository at https://github.com/wangyihao0001-oss/dsh-task-memory first, then run the install command and verify the plugin loads successfully.
Paste this instruction to the DSH Web GUI assistant — it will install and verify for you.
One-Line Positioning
Provides task-isolated long-term memory for DeepSeek Harness: each task gets an independent vault, with memory write, read, retrieval, and prompt injection all scoped within the current task boundary, preventing memory leakage across different projects.
Core Capabilities
- Per-task storage: Each task maintains an independent vault under
~/.dsh/storages/task-memory/<task-id>.json, with memory never automatically leaking across tasks - 8 memory tools: Models can fully manage memory via
memory_bind_task/memory_remember/memory_recall/memory_search/memory_forget/memory_current_task/memory_list_tasks/memory_clear_task - Automatic default task derivation: When unbound, generates a stable task ID from the session's working directory (cwd) hash, enabling "directory isolation" without manual configuration
- Session-scoped prompt injection: Each agent's system prompt only injects memory from that session's task, prioritizing pinned entries then recent entries, constrained by character budget
- Capacity and concurrency safety: Vault capacity is configurable; pinned entries are never evicted; explicit error on new key overflow instead of silent dropping; same-task writes serialized via in-process async lock
- Atomic writes and crash recovery: Each save uses "temp file + atomic rename"; cleans up crash residual tmp files older than 1 hour on startup
Technical Implementation
- Language: TypeScript (
src/index.ts/src/store.ts/src/search.ts, compiled tolib/index.js,type: moduleESM) - Key dependencies: Host peer dependencies
@deepseek-ai/cordis ^4.0.1,@deepseek-ai/dsh-agent ^0.1.0-rc.8,@deepseek-ai/dsh-tools ^0.1.0-rc.6,@deepseek-ai/dsh-system-prompt ^0.1.0-rc.6,@deepseek-ai/dsh-home-paths ^0.1.0-rc.6,@deepseek-ai/schemastery ^3.18.1; runtime only uses Node built-insnode:fs/promises/node:path/node:crypto - Architecture pattern: Cordis single-side plugin —
export const name = 'task-memory',export const inject = ['tools', 'systemPrompt']; viadsh.bundle.patchpointing tocordis.patch.ymlto inject into host layer, registering 8 tools + 1 fixed systemPrompt section + 1 agent-scoped systemPrompt.context - Entry file:
src/index.ts(exportsapply(ctx, config), completing tool registration, prompt injection, session-task binding cleanup, tmp cleanup, and default task cache warmup)
Use Cases
Users maintaining multiple projects in the same DSH (frontend + backend + experiment scripts), using DSH as a long-term R&D assistant, and不希望模型把 A 项目的技术栈约定误用到 B 项目. Pain point is most DSH memory plugins are either globally shared or workspace-based, unfriendly to people running multiple parallel tasks in the same working tree; this plugin uses task as the boundary, with a side benefit solving "session-level prompt pollution" — each agent session's system prompt only sees its own task's memory.
Prerequisites & Compatibility
| Dependency | Min Version | Description |
|---|---|---|
| DeepSeek Harness (DSH) | >= 0.1.0-rc.8 | Determined by @deepseek-ai/dsh-agent ^0.1.0-rc.8 in package.json#peerDependencies; other dsh-* peers are ^0.1.0-rc.6 |
| Node.js | >= 20 | Declared in package.json#engines.node |
@deepseek-ai/cordis | ^4.0.1 | Peer dependency, provided by host DSH |
@deepseek-ai/dsh-tools | ^0.1.0-rc.6 | Peer dependency, wraps defineTool to help register 8 tools |
@deepseek-ai/dsh-system-prompt | ^0.1.0-rc.6 | Peer dependency, provides systemPrompt.section / systemPrompt.context injection points |
@deepseek-ai/dsh-home-paths | ^0.1.0-rc.6 | Peer dependency, used to resolve resolveDshHome() to get ~/.dsh |
@deepseek-ai/schemastery | ^3.18.1 | Peer dependency, validates Config with schema |
| Platform | Cross-platform | Only depends on Node.js built-ins fs / path / crypto, no native modules |
| Native modules | None | All uses Node built-in APIs, no node-gyp compilation artifacts |
| Installation profile | web (or any profile that loads Host tools) | cordis.patch.yml injected into host's tools and system prompt layer |
Installation
dsh plugin --profile web add github:wangyihao0001-oss/dsh-task-memory
Configuration Options
Configuration is in the config field of cordis.patch.yml, Schema validated by Config in src/index.ts, all fields have defaults and can run with zero config:
| Config | Type | Description | Default |
|---|---|---|---|
injectLimit | number | Max number of memory entries injected into current task's system prompt | 8 |
injectMaxChars | number | Soft character budget for entire injection block (stops adding new entries when exceeded) | 2400 |
injectMaxEntryChars | number | Character limit per single memory entry in injection block (truncates if exceeded) | 400 |
injectPrompt | boolean | Whether to inject pinned/recent facts for current task (per agent scope) | true |
maxEntries | number (>= 1) | Entry limit per vault; evicts oldest non-pinned entries when exceeded | 500 |
storageRoot | string | Optional, overrides default storage root ~/.dsh/storages/task-memory | "" (empty string uses default) |
Restart dsh web (or restart profile) after modification for Cordis to reload.
FAQ
Q: Will memory files remain after uninstalling the plugin?
A: Yes. Memory is stored as plain JSON in ~/.dsh/storages/task-memory/<task-id>.json; removing the bundle from profile does not delete these files; manual backup or deletion of the directory is needed for complete cleanup.
Q: Will injected prompts cross-task contaminate?
A: No. Injection is registered per agent scope (agent.ctx.systemPrompt.context), each session's system prompt only contains memory from its own task; memory from other tasks, sessions, or agents is never visible.
Q: Does keyword search support Chinese?
A: Yes. Search does English tokenization + Chinese bigram (adjacent two-character combination) matching (see src/search.ts#tokenize), but it's still lexical matching, no vector search or semantic similarity.
Q: What happens when vault is full and a new key is written?
A: Write fails with a clear error (prompting to forget or unpin some entries), never silently drops the just-written fact; however, in-place updates (upsert) to existing keys won't be rejected due to capacity, and will try to shrink non-pinned entries.
Q: Do I need to manually specify taskId?
A: Not by default: when unbound, a stable task ID is generated from the session's working directory (cwd) hash. When running multiple projects simultaneously, call memory_bind_task to explicitly switch.
Q: How to pin a version in production?
A: Append 40-digit commit SHA to the package name during installation, e.g., dsh plugin --profile web add "github:wangyihao0001-oss/dsh-task-memory#<sha>", to avoid upstream updates being auto-pulled.
Q: Do I need to restart DSH after upgrade/uninstall?
A: Yes. The plugin injects into host's Cordis layer via cordis.patch.yml; after installation or removal, must restart dsh web (or restart profile) for Cordis to reload.
Q: Can I write sensitive information into memory?
A: Not recommended. Both README and the 8 tool descriptions explicitly warn against writing keys, tokens, or personal privacy; vault is plain JSON, backups or manual edits will also be persisted to disk.
Getting Started Difficulty
Beginner — after installation, no configuration needed to get "automatic per-cwd task separation + 8 memory tools + prompt injection" capability; all preferences can be adjusted via the config field in cordis.patch.yml as needed.
Known Issues & Limitations
- Search is lexical matching: English tokens + Chinese bigrams, no vector search or semantic similarity (
src/search.ts:8-50) - No Web UI for browsing vault: Currently a Host-only combo package, vault can only be managed via tools or direct JSON file editing
- Isolation boundary only applies to this plugin's task id: Does not sandbox other DSH plugins or workspaces themselves
- Conservative tmp cleanup: On startup only cleans crash residual tmp files > 1 hour old, to avoid accidentally deleting in-progress writes from other processes (
src/store.ts:189-208) — the trade-off is tmp files within 1 hour persist until next startup - Uninstall does not delete data: Removing from profile does not clear
~/.dsh/storages/task-memory/, manual backup or cleanup required - Capacity limit is transparent for existing keys but strict for new keys: When vault is full and only pinned entries can be evicted, new key writes fail (to avoid "just written but immediately evicted" silent loss), need to first forget or unpin
- Same-task writes use in-process lock: Not cross-process/machine mutually exclusive, vault files can be manually copied but concurrent writes need manual coordination
- Tool descriptions consume context: Descriptions of 8 tools like
memory_bind_task/memory_searchare loaded into model context with tool list, frequent task switching or parallel multi-tasking can consume significant token budget
English | 中文
Task-isolated long-term memory for DeepSeek Harness.
Memories live in per-task vaults under ~/.dsh/storages/task-memory/. Facts stored for one task are invisible to another unless you deliberately switch.
Catalog: dsh.pub/en/plugins/dsh-task-memory
Why this exists
Most DSH memory plugins are global or workspace-wide. This one treats task as the isolation boundary:
- Default task = derived from session
cwd memory_bind_taskrebinds the current session to a named vault- Search / recall / prompt injection never cross that boundary — prompt injection is registered at agent scope, so each session's system prompt only ever shows its own task's memories
Quick start
# Install into the web profile (pin a full commit SHA for production)
dsh plugin --profile web add "github:wangyihao0001-oss/dsh-task-memory"
# Or via the catalog CLI
npx dshpub add wangyihao0001-oss/dsh-task-memory --profile web
Restart the web UI (or reboot the profile), then in a session:
memory_bind_task— e.g.taskId: "my-app"(optionaltitle)memory_remember—key: "stack",content: "Node 22 + Postgres", optionallypinned: truememory_recall/memory_search— read back within the same taskmemory_current_task— confirm which vault this session is on
Tools
| Tool | Purpose |
|---|---|
memory_bind_task | Bind this session to a task vault |
memory_current_task | Show the session's current vault (binding or default) |
memory_remember | Upsert a fact by key (optional tags / pin / task override) |
memory_recall | Exact-key read |
memory_search | Keyword search (EN + 中文 bigrams); empty query lists recent/pinned |
memory_forget | Delete one key |
memory_list_tasks | List vaults |
memory_clear_task | Wipe one vault (confirm: true required) |
Never store secrets in memory entries.
Install / verify / disable
# Install
dsh plugin --profile web add "github:wangyihao0001-oss/dsh-task-memory#<40-char-sha>"
# Confirm the bundle layer is present
dsh --profile web --dump-config
# Remove from the profile when done
dsh plugin --profile web remove dsh-task-memory
After install or remove, restart dsh web (or reboot the profile) so the Cordis layer reloads.
Vault files under ~/.dsh/storages/task-memory/ are not deleted on uninstall — back up or delete them yourself if needed.
Local develop (without installing)
npm install
npm run build
npm test # node:test unit tests
npm run smoke # build + smoke
Link a checkout while developing:
dsh plugin --profile web add "$(pwd)"
If you run DSH from a source checkout:
pnpm dsh web --patch /absolute/path/to/dsh-task-memory/cordis.dev.yml
Update the absolute path in cordis.dev.yml so it points at this checkout’s built lib/index.js.
Config
cordis.patch.yml defaults:
injectLimit: 8 # max memories in prompt context
injectMaxChars: 2400 # soft char budget for the injected block
injectMaxEntryChars: 400 # per-entry char cap in the injected block (truncated)
injectPrompt: true # inject pinned/recent facts for the active task
maxEntries: 500 # vault cap (>= 1); oldest non-pinned entries are evicted first
# (pinned are never evicted; new keys over the cap are rejected;
# upserts of existing keys are not blocked by capacity)
Optional storageRoot overrides ~/.dsh/storages/task-memory.
Storage & reliability
~/.dsh/storages/task-memory/
<task-id>.json
Each file:
{
"taskId": "<task-id>",
"title": "<title>",
"updatedAt": 0,
"entries": [
{
"id": "m_…",
"key": "<key>",
"content": "…",
"tags": [],
"pinned": true,
"createdAt": 0,
"updatedAt": 0
}
]
}
- Files are plain JSON — safe to hand-edit or back up
- Writes go through tmp file + atomic rename, so readers always see a consistent snapshot
- Mutations for the same task (including
memory_bind_tasktitle updates,save, andupdate) are serialized in-process (per-task lock); concurrent agents cannot lose updates. Preferupdateoverload→ mutate →savefor read-modify-write - Pinned entries are never evicted; when a full vault has nothing removable but pinned entries, new keys are rejected with a clear error instead of silently dropping the just-written fact, while upserts of existing keys are never blocked by capacity (they still shrink best-effort)
- On startup, stale
*.tmpfiles from crashed writes are cleaned up (only those older than 1h, so another process's live write is never touched)
Model experience
When injectPrompt is true, the plugin injects a short memory block into the current agent session's system prompt:
- Only the vault bound to that session (or the cwd-derived default)
- Prefer pinned entries, then recent ones, up to
injectLimit/ char budgets - Other sessions and other tasks never appear in this block
Tools remain available for explicit recall/search beyond what fits in the prompt.
Known limitations
- Host-only bundle: no Web UI for browsing vaults yet (see roadmap)
- Keyword search is lexical (EN tokens + 中文 bigrams), not embeddings / vector search
- Isolation is per task id within this plugin — it does not sandbox the rest of DSH
- Catalog listing on dsh.pub is an automated contract check, not a security audit
- Do not store credentials, tokens, or personal secrets in memories
Compatibility
- Node.js
>= 20 - DeepSeek Harness peers as declared in
package.json(@deepseek-ai/dsh-*/cordis/schemastery) - Installs as a Git bundle via
dsh.bundle.patch→cordis.patch.yml - Intended profile:
web(or any profile that loads Host tools)
Roadmap
- ✅ Per-session prompt injection via agent-scoped context (replaces process-level binding guess)
- Optional vector search behind the same tools
- Tiny Web UI page to browse / pin / delete vaults
License
MIT — see LICENSE.
Read the usage guide →
Install steps, key points, FAQ and compatibility for this plugin — auto-derived from indexed fields.
Listing badge
[](https://deepseek-plugin.org/plugins/wangyihao0001-oss/dsh-task-memory)Paste this markdown into your GitHub README to link back to this listing. The badge only states the listing — not a security endorsement.