annkun/dsh-memory ↗★ 1

@fooxe/dsh-memory

Hierarchical Claude Code-style persistent memory for DeepSeek Harness: user + project (git-shared) scopes, session-start auto-injection, MEMORY.md index guards. Pure files, zero dependencies. 适合需要跨会话记忆项目上下文、避免重复解释偏好的用户。

Package
@fooxe/dsh-memory
Compatibility
Unverified
Harness peer range
>=0.0.1-rc.1
Cordis peer range
>=4.0.0
Version
0.11.3
License
MIT
Last updated
Oct 9, 2026

Install

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:annkun/dsh-memory

dsh-memory

npm license node

English | 中文版

Hierarchical persistent memory for DeepSeek Harness — inspired by the memory design Claude Code popularized. Your agents remember across sessions, wake up with context, and never mix projects.


English

What it does

Your DSH agent meets you for the "first time" — every single session. With dsh-memory, it remembers.

Tired of re-explaining "I prefer pnpm" in every project? Re-describing last week's architecture decision? dsh-memory gives your agent a durable memory: it saves what matters as it appears (preferences, project decisions, key numbers, lessons) and every future session starts with those memories already in context.

Here's what it looks like 30 seconds after install:

Session 1   You: "Remember — this project uses pnpm, not npm."
            Agent: saved via memory_save

Session 2   You: "Which package manager do we use?"
            Agent: "pnpm — you told me yesterday."   /.dsh/memory`; git/SVN/Hg roots auto-detected)
- **Lazy injection, CLAUDE.md-style** — project memories are tagged by sub-directory and only load when you work in that area; your token budget goes where you work
- **Write rules built in** — strong-evidence gate ("will this matter in a month?"), same-topic saves update in place, secrets refused on sight
- **Bounded by design** — 25KB guarded index, 200-line cap, 500 memories per scope: memory can never silently eat your context window
- **Zero dependencies, pure files** — nothing to provision, nothing to break

## Quick start

**Prerequisite**: the DSH CLI itself — `npm install -g @deepseek-ai/dsh`. From a source checkout, prefix every command with `pnpm` (e.g. `pnpm dsh ...`).

**1 · Install (one command)**

```sh
dsh plugin --profile web add @fooxe/dsh-memory        # DSH CLI installed
pnpm dsh plugin --profile web add @fooxe/dsh-memory   # from a source checkout

The --profile option is required and goes before add — pick the profile you actually boot (web for the Web UI; see ~/.dsh/profiles/ for what exists). Manual install via npm i -g @fooxe/dsh-memory (or pnpm add -g @fooxe/dsh-memory) + dsh web --patch ./overlay/dsh-memory.cordis.yml also works, but plugin add is the recommended path.

2 · Restart DSH — the step everyone misses

Tools register only at service startup. The plugin stays invisible inside an already-running session even after a successful install. Stop the service (Ctrl+C), start it again, then open a new chat.

3 · Verify (30 seconds)

Say "Remember that I prefer pnpm over npm." → a memory_save tool call appears. Open a new session and ask "Which package manager do I prefer?" → answered instantly from the injected index. ~/.dsh/memory/MEMORY.md now exists. Inside a project, decisions land in /.dsh/memory/ — commit it and the whole team shares it.

Troubleshooting (every row battle-tested on a real install)

SymptomFix
dsh: command not foundInstall the DSH CLI first — see Prerequisite
required option '--profile 'It goes before the subcommand: dsh plugin --profile web add ...
pnpm ERR_P..._STORE: Unexpected store locationYour terminal pnpm differs from DSH's bundled one (11.7.0). Delete the whole profile dir (~/.dsh/profiles/web) and re-run plugin add — it rebuilds cleanly from scratch
Installed + restarted, still no memory toolsWatch startup logs for warning: ... did not activate, and run dsh --profile web --dump-config | grep fooxe to confirm the entry is in the tree; file an issue with the log if the warning persists
ERR_PNPM_IGNORED_BUILDS after installHarmless for this plugin (zero native deps); run pnpm approve-builds in the profile dir to clear it
plugin add installs an old version (e.g. 0.7.2)Your default registry (a mirror) lags behind npmjs. Pin explicitly: npx pnpm@11.7.0 add @fooxe/dsh-memory@latest --registry=https://registry.npmjs.org in the profile dir, or make it permanent by adding @fooxe:registry=https://registry.npmjs.org to ~/.npmrc

Innovations

1. Two-level scopes — cross-project, zero confusion

  • User scope (~/.dsh/memory): personal preferences and habits, stored once, available in every project. Stop re-explaining "I prefer pnpm" in each repo.
  • Project scope ( /.dsh/memory): decisions and conventions stored inside their own project — any VCS (git / SVN / Mercurial) or a plain folder works; commit the directory with your version control and the whole team shares it automatically.
  • The two never mix: project A's architectural decisions stay out of project B, while your personal style follows you everywhere.
  • Scope auto-detection (v0.4): DSH_MEMORY_PROJECT_DIR env override > an existing .dsh/memory marker above (supports nested sub-project scopes) > any VCS root — .git, .svn or .hg (SVN/Mercurial projects anchor correctly on first use) > the current directory itself (VCS-less projects get their own scope instead of flooding the user bucket). $HOME, / and /tmp never become a scope: a dotfiles ~/.git cannot turn home into one giant shared bucket.

2. Session-start auto-injection

Both scope indexes are seeded into the system prompt when a session starts (ctx.systemPrompt). The agent doesn't need to remember to look things up — it begins every conversation already knowing your context.

3. Context-window guards

Memory should grow in value, not in token cost: the MEMORY.md index is hard-capped at 200 lines / 25 KB, each scope holds at most 500 memories with oldest-first pruning, and oversized memories return a truncated preview plus an on-disk path (local_file) instead of flooding the window.

4. Claude Code-compatible read contract

memory_read returns the same field contract as Claude Code's shipped project_memory_read — content?, local_file?, size_bytes, updated_at, truncated — so tooling and habits transfer.

5. Zero footprint

Pure files. No server process, no embedding provider, no account, no database. Delete a scope's directory and that scope forgets everything.

6. A real visual memory manager (v0.10.0)

Most memory plugins dump markdown at you. This one ships a panel: Settings → Memory lists both scopes with live guard gauges, groups memories by workspace and sub-folder in an expandable tree, and lets you add, edit, and delete entries in place — one form, identical layout, for both adding and editing. The panel writes through the same guarded pipeline as the agent's tool calls, so the UI and the model can never drift apart. Since v0.11 injection and saving are session-scoped together — each session reads ITS workspace and writes back to the same one. The result: three-level partitioning (personal / workspace / session) with zero cross-contamination, and a flat token bill — inject only what the working area needs, search the rest on demand.

Tools

ToolPurpose
memory_saveSave a durable memory; scope defaults to project inside a detected project root, user elsewhere
memory_searchCase-insensitive keyword search across both scopes (ids, titles, tags, content)
memory_readRead one full memory (Claude Code contract fields)
memory_listRecent memories per scope, newest first

Tool descriptions embed proactive-save guidance — preferences, decisions and key facts get saved without being asked; secrets never do.

Write rules (v0.5, ported from Claude Code / Gemini CLI practice):

  • Strong-evidence default — before saving, the model asks "will this still matter a month from now?"; unsure → skip (memory noise costs more than gaps)
  • Dedupe-and-update — saving an existing topic updates that memory in place (content replaced, timestamp refreshed) instead of appending a duplicate
  • Dated index lines — every MEMORY.md entry carries YYYY-MM-DD, so the model can reason fresh-vs-stale at injection time
  • Secret redaction — credentials/tokens/passwords are never saved; the model refuses and says so

Memory logic — when · what · which scope

When to save (the model judges as information appears): a preference or correction is stated → save now (corrections are the highest-value memories); a decision is made → save; a key number/ID appears → save; an error + fix closes → save. Strong-evidence gate (v0.5): ask "will this still matter in a month?" — if unsure, skip; memory noise costs more than memory gaps.

Never saved: secrets / tokens / passwords (refused, out loud), transient state, anything directly readable from the repo, unconfirmed guesses.

Which scope — the one-line test: is this fact about the person or about this project?

| User scope ~/.dsh/memory | Project scope /.dsh/memory | |---|---| | Personal preferences (pnpm, Chinese comments) | Technical decisions (A over B, because C) | | Working habits (test before commit) | Conventions (layout, naming, build commands) | | Cross-project lessons | Key numbers / IDs (ports, servers, app IDs) | | Communication style | Anything the team should share through the repo |

Portability test: still true in a different project? → user scope; only true here → project scope.

Path-tagged memories (v0.6, CLAUDE.md-style lazy injection): project-scope memories are automatically tagged with the sub-directory they were saved in. Root-level (untagged) memories always inject into the system prompt; path-tagged memories only inject when the session's working directory falls inside that path — "you see memories for where you work", exactly like nested CLAUDE.md files. The path parameter on memory_save also accepts an explicit override.

Two-stage visibility (v0.7): nothing is silently hidden — the injected index always states how many path-tagged memories exist outside the current working area (e.g. +3 more tagged to other areas of this project — memory_search surfaces them.), so the model knows to search on demand and pays context cost only when needed.

Layered scoping — how the project root is decided

Two physically isolated stores that can never mix: user ~/.dsh/memory and project /.dsh/memory. The root is auto-detected by a five-level chain, priority = explicitness (the clearest signal wins):

  1. DSH_MEMORY_PROJECT_DIR env override (explicit user intent)
  2. An existing .dsh/memory marker above (our own past anchor — supports nested sub-project scopes)
  3. Any VCS root above: .git / .svn / .hg (SVN and Mercurial projects anchor correctly on first use)
  4. The host workspaceRegistry (DSH official project registry, async refinement)
  5. The current directory itself (VCS-less projects get their own scope)

Guard: $HOME, / and /tmp never become a scope — a dotfiles ~/.git cannot turn home into one giant shared bucket. Better no isolation than wrong isolation.

Storage layout

~/.dsh/memory/                       search -> read -> list end-to-end

dsh-memory happily coexists with DSH's official MCP memory options — pick whichever fits your workflow, or use both.

## License

MIT. Not affiliated with DeepSeek or Anthropic.

---

# 中文版

**给 DeepSeek Harness 装上跨会话持久记忆——灵感来自 Claude Code 的记忆设计。你的 agent 记得住、醒得来、项目之间不串味。**

## 这个插件做什么

> 你的 DSH agent 每次开会话都是"初次见面"。
> 装上 dsh-memory,它记得你。

受够了每个项目都要重新解释一遍"我用 pnpm"?上周定的架构决策这周又要从头讲?`dsh-memory` 给 agent 装上持久记忆:信息出现时**自动存下重要的东西**(偏好、项目决策、关键数字、经验教训),**之后每次会话开场自带这些记忆**。

装完 30 秒后是这个样子:

```text
会话 1   你:"记住——这个项目用 pnpm,不用 npm。"
         Agent:memory_save 已保存

会话 2   你:"我们用什么包管理器?"
         Agent:"pnpm——你昨天告诉我的。"   /.dsh/memory`;git/SVN/Hg 根自动检测)
- **按需注入(CLAUDE.md 式)**——项目记忆带子目录标签,只在对应区域工作时加载,token 花在刀刃上
- **写入规则内建**——强证据门槛("一个月后还有用吗?")、同主题原地更新、密钥一律拒存
- **天生防膨胀**——25KB 索引护栏 + 200 行上限 + 每域 500 条:记忆永远不会悄悄吃掉上下文窗口
- **零依赖纯文件**——没有要部署的、没有会坏的

## 快速开始

**前置**:先装 DSH 本体——`npm install -g @deepseek-ai/dsh`。从源码检出运行的话,每条命令加 `pnpm` 前缀(如 `pnpm dsh ...`)。

**第 1 步 · 安装(一条命令)**

```sh
dsh plugin --profile web add @fooxe/dsh-memory        # 已装 DSH CLI
pnpm dsh plugin --profile web add @fooxe/dsh-memory   # 源码检出方式

--profile 必填且放在 add 前面——填你实际启动的 profile(Web 界面就是 web;已有哪些看 ~/.dsh/profiles/ 目录)。手动方式 npm i -g @fooxe/dsh-memory(或 pnpm add -g @fooxe/dsh-memory)+ dsh web --patch ./overlay/dsh-memory.cordis.yml 也可以,但推荐 plugin add。

第 2 步 · 重启 DSH(最容易漏的一步)

工具只在服务启动那一刻注册——装完后运行中的会话里看不到插件。把服务 Ctrl+C 停掉、重新启动、再开新会话。

第 3 步 · 验证(30 秒)

说一句*"记住我喜欢 pnpm,不用 npm"* → 出现 memory_save 工具调用。新开会话问*"我喜欢什么包管理器?"* → 直接答出 = 全链路通了。~/.dsh/memory/MEMORY.md 文件同时出现。在项目里保存的决策落在 /.dsh/memory/——提交版本库全组共享。

安装排障(每一行都来自真实安装实测)

症状解法
dsh: command not foundDSH 本体没装,看前置步骤
required option '--profile '参数放在子命令前面:dsh plugin --profile web add ...
pnpm ERR_P..._STORE: Unexpected store location你终端的 pnpm 和 DSH 自带的(11.7.0)版本不一致——把整个 profile 目录(~/.dsh/profiles/web)删掉重跑 plugin add,全新重建即可
装了也重启了还是没有记忆工具看启动日志有没有 warning: ... did not activate,并跑 `dsh --profile web --dump-conf