# dsh-task-memory English | [中文](README.zh.md) Task-isolated long-term memory for [DeepSeek Harness](https://github.com/deepseek-ai/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: 1. Default task = derived from session `cwd` 2. `memory_bind_task` rebinds the current session to a named vault 3. 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 ```bash # 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](https://dsh.pub/en/plugins/), you can also install via the registry badge / `dshpub` flow. ## Local develop (without installing) ```bash npm install npm run build npm test # node:test unit tests npm run smoke # build + smoke ``` If you run DSH from a source checkout: ```bash 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: ```yaml 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 ```text ~/.dsh/storages/task-memory/ .json ``` Each file: ```json { "taskId": "", "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_task` title updates, `save`, and `update`) are **serialized** in-process (per-task lock); concurrent agents cannot lose updates. Prefer `update` over `load` → mutate → `save` for 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 `*.tmp` files 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