Overview
dsh-task-memory
README / EN
Package documentation
dsh-task-memory
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.
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
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 |
memory_recall |
Exact-key read |
memory_search |
Keyword search (EN + 中文 bigrams) |
memory_forget |
Delete one key |
memory_list_tasks |
List vaults |
memory_clear_task |
Wipe one vault (confirm: true) |
Install
# From the public GitHub repo (recommended pin: full commit SHA)
dsh plugin --profile web add "github:wangyihao0001-oss/dsh-task-memory"
# Or link a local checkout while developing
dsh plugin --profile web add "$(pwd)"
After install, restart the web UI (or reboot the profile), bind a task, then remember / recall / search.
Catalog: once listed on dsh.pub, you can also install via the registry badge / dshpub flow.
Local develop (without installing)
npm install
npm run build
npm test # node:test unit tests
npm run smoke # build + smoke
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 affected)
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)
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
LIMITATIONS
Known limitations
Submitted through a public pull request. Automated checks verified the public bundle contract and committed files, but did not inspect runtime capabilities. This is not a human review, security audit, publisher identity check, or official endorsement.
