Back to home

GongYuanCaiJi

dsh-pi-memory

跨会话持久记忆(移植自 pi-memory)

Stars
0
Language
JavaScript
Created
Aug 14, 2026
Updated
Aug 15, 2026

Introduction

中文 | English

dsh-pi-memory

让 DeepSeek Harness(dsh)跨会话记住事情:持久事实、每日日志、待办清单,以及可选的 qmd 语义搜索。

license


中文

dsh-pi-memorypi-memory(Pi 生态最流行的记忆插件)的 DeepSeek Harness(dsh)移植版。你的 coding agent 每次开新会话都会忘光一切 —— 这个插件给它一份记忆:长期事实与决策、按天追加的工作日志、待办清单,全部是你可以直接读、改、提交的纯 Markdown 文件。装上可选的 qmd 之后,还能跨所有记忆做关键词、语义与混合搜索

移植说明:代码与逻辑 100% 来自上游 pi-memoryjayzeng/pi-memory,MIT)。本移植只改动了 dsh 插件入口与生命周期接线,每一处改动都有原因,逐条记录在移植票 #18 的交付回报里。请也给上游 pi-memory 一个 star。

已知限制:插件注入给 agent 的提示词与记忆上下文模板是上游英文原文,逐字保留未做翻译;记忆文件内容用什么语言写由你决定。

功能

工具说明
memory_write写入 MEMORY.md(长期)或今日日志
memory_forget删除匹配条目,并生成可恢复的删除记录
memory_restorememory_forget 返回的 recovery ID 恢复删除
memory_read读取任意记忆文件或列出每日日志
scratchpad添加 / 完成 / 撤销 / 清理待办清单项
memory_search跨所有记忆文件搜索(需要 qmd)
memory_status健康检查:文件位置、qmd / collection / embeddings 状态、当前配置

核心六件套(memory_writememory_forgetmemory_restorememory_readscratchpadmemory_status)装上即可用,不需要任何额外配置。搜索是可选能力。

memory_search 模式

模式速度方法最适合
keyword~30msBM25具体术语、日期、名字、#标签、[[链接]]
semantic~2s向量搜索相关概念、不同措辞
deep~10s混合 + 重排其他模式找不到时

效果

# 会话 1
你 ▸ 这个仓库我永远用 pnpm,不用 npm。记住。
dsh ▸ 已记入长期记忆。   (写入 MEMORY.md)

# ……几天后,全新会话……
你 ▸ 把 prettier 加为 devDependency
dsh ▸ pnpm add -D prettier
      (从记忆里想起你的包管理器偏好——不用再提醒)

所有内容都存在 $DSH_HOME/agent/memory/(默认 ~/.dsh/agent/memory/)下的 Markdown 文件里,你随时可以 cat

$ cat ~/.dsh/agent/memory/MEMORY.md
<!-- 2026-06-07 10:12:03 [a1b2c3d4] -->
#preference [[package-manager]] 这个仓库永远用 pnpm,不用 npm。

安装

⚠️ dsh-pi-memory 尚未发布到 npm,以下用本地路径安装。发布后即可用裸名安装(届时 README 会更新)。

# 1. 克隆本仓库并安装依赖
git clone https://github.com/GongYuanCaiJi/dsh-pi-memory.git
cd dsh-pi-memory && npm install

# 2. 装进一个 dsh profile(headless 一次性任务还需要 @deepseek-ai/dsh-headless@next)
P=verify-$(basename $PWD)-$$
dsh plugin --profile "$P" add @deepseek-ai/dsh-headless@next
dsh plugin --profile "$P" add .

# 3. 用起来
dsh --profile "$P" "记住:我偏好深色模式"
dsh --profile "$P" "我上次说过偏好什么?"   # 新会话,它还记得

可选:启用 qmd 搜索

memory_search(以及 per-turn 模式的自动检索注入)需要 qmd,两种安装方式任选:

npm install -g @tobilu/qmd                      # 不需要 Bun
bun install -g https://github.com/tobi/qmd      # 确保 ~/.bun/bin 在 PATH 上

qmd 就绪后,插件会在下一次会话启动时自动创建 pi-memory collection 与路径 context —— 无需手动步骤。随时运行 memory_status 确认 qmd、collection、embeddings 的状态。

语义 / deep 模式需要向量 embeddings;插件会自动保持最新(写入后在后台跑 qmd embed)。第一次 embed 会下载 embedding 模型,所以全新安装后语义搜索可能要等一分钟左右才上线。想手动设置:

qmd collection add ~/.dsh/agent/memory --name pi-memory
qmd context add /daily "Daily append-only work logs organized by date" -c pi-memory
qmd context add / "Curated long-term memory: decisions, preferences, facts, lessons" -c pi-memory
qmd embed

没有 qmd 时,核心工具完全可用,只有 memory_search 与选择性注入需要它。

文件布局

~/.dsh/agent/memory/
  MEMORY.md              # 策展的长期记忆
  SCRATCHPAD.md           # 待办清单
  daily/
    2026-02-15.md         # 每日追加日志
    2026-02-14.md
    ...
  recovery/
    <recovery-id>.json    # memory_forget 删除的完整负载与恢复状态

工作原理

上下文注入

每个 agent turn 之前,按优先级注入以下内容到 system prompt:

  1. 未完成的待办项(最多 2K 字符)
  2. 今日日志(最多 3K 字符,尾部)
  3. MEMORY.md(最多 4K 字符,中间截断)
  4. 昨日日志(最多 3K 字符,尾部——优先级最低,先被裁掉)

总量上限 16K 字符。

KV 缓存稳定快照(默认)

本地前缀缓存运行时(llama.cpp、vLLM、MLX)从第一个分叉 token 起就会失效。如果注入的记忆块每 turn 都变,整个会话历史每一 turn 都会被重算。

为了让前缀字节稳定,插件在刻意选择的检查点对记忆上下文做快照,期间每个 turn 输出相同字节。快照在以下时机刷新:

  • 会话启动 —— 每会话一份新快照
  • 压缩(compaction) —— 写入 handoff 后刷新(一次刻意的缓存边界)
  • memory_writetarget: long_term —— 标记快照脏,下一 turn 刷新
  • 跨日 —— 快照记录的日期不再是今天

target: daily 的写入与 scratchpad 写入标记脏 —— 它们高频发生,内容已经通过工具调用参数回显。模型随时可以用 memory_read / memory_search 拿到权威最新状态。

设置 PI_MEMORY_SNAPSHOT=per-turn 可恢复旧的逐 turn 重建行为(含逐 prompt 的 qmd 搜索注入)。

选择性注入(per-turn 模式,可选)

PI_MEMORY_SNAPSHOT=per-turn 且 qmd 可用时,插件会在每个 turn 前用你的 prompt 自动搜索记忆,把命中前 3 条与标准上下文一起注入。搜索有 3 秒超时、失败静默。默认 stable 模式下,模型随时可以自己调 memory_search

标签与链接

在记忆内容里用 #tags[[wiki-links]] 提高可搜性:

#decision [[database-choice]] 后端全部选 PostgreSQL。
#preference [[editor]] 用户偏好 Neovim + LazyVim 配置。
#lesson [[api-versioning]] URL 前缀版本化(/v1/)避开 CDN 缓存问题。

这是内容约定,不是强制元数据。qmd 的全文索引会免费让它们可搜。

会话交接(handoff)

上下文窗口压缩时,插件自动把交接条目写进今日日志:

<!-- HANDOFF 2026-02-15 14:30:00 [a1b2c3d4] -->
## Session Handoff
**未完成的待办项:**
- [ ] 修 auth bug
- [ ] 看 PR #42
**最近日志上下文:**
...今日日志最后 15 行...

其他行为

  • 持久化:记忆文件就是磁盘上的 Markdown —— 可读、可编辑、git 友好。
  • 可恢复删除memory_forget 先把完整删除内容存进 recovery/ 再改记忆,返回的 recovery ID 可交给 memory_restore。恢复 JSON 在 qmd 的 **/*.md 索引之外。
  • 工具响应预览:写入 / scratchpad 工具返回大小受限的预览而非全文。
  • qmd 自动建 collection:qmd 可用时,首次会话启动自动创建 collection 与路径 context。
  • qmd 自动重索引:每次写入后,后台防抖 qmd update(fire-and-forget,不阻塞),可用 PI_MEMORY_QMD_UPDATE 关闭。
  • qmd embeddings:语义 / deep 搜索所需向量自动保持最新 —— 重索引后与启动时后台跑增量 qmd embed。随 PI_MEMORY_QMD_UPDATE 一并关闭。
  • 优雅降级:没有 qmd 时核心工具照常工作,memory_search 返回安装指引。

配置

变量取值默认说明
PI_MEMORY_DIR路径$DSH_HOME/agent/memory覆盖记忆存储目录(默认在 dsh home 下,而非 Pi 的 ~/.pi
PI_MEMORY_SNAPSHOTstable, per-turnstablestable 在检查点快照记忆以保 KV 缓存稳定;per-turn 每 turn 重建(旧行为)
PI_MEMORY_QMD_UPDATEbackground, manual, offbackground控制写入后的自动 qmd update + qmd embed
PI_MEMORY_QMD_SEARCH_TIMEOUT_MS正整数(毫秒)60000显式 memory_search 的 qmd 查询超时
PI_MEMORY_NO_SEARCH1未设置关闭 per-turn 模式的选择性注入(stable 模式无效)
PI_MEMORY_SUMMARIZE_TRANSITIONS1, true, yes, on未设置生命周期过渡(reload/new/resume/fork)也写退出总结;默认过渡跳过总结以提速
PI_MEMORY_EXIT_SUMMARY0, off, false, no 关闭未设置(启用)关闭会话结束时的退出总结(不做 LLM 调用、不跑 qmd update,退出即时)
PI_MEMORY_EXIT_SUMMARY_MODELprovider/model-id未设置(会话模型)写退出总结用的模型,比如更便宜的。无法解析则回退会话模型
PI_MEMORY_EXIT_SUMMARY_TIMEOUT_MS正整数(毫秒)10000退出总结自限超时;超时则不落盘

移植注:session_shutdown 在 dsh 上映射为 agent/disposed —— 该事件只在 dsh 主动销毁 agent 且服务仍存活时触发;headless 一次性任务结束时服务先于插件析构,退出总结会安静跳过(不崩溃、不落盘)。这是 dsh 生命周期与 Pi 的差异,详见移植票 #18。

故障排查

先跑 memory_status —— 大多数问题一眼可见。

症状原因修复
memory_search 说需要 qmdqmd 未安装或不在 PATH安装 qmd(npm install -g @tobilu/qmd);Bun 安装的确保 ~/.bun/bin 在 PATH
搜不到你确定存在的词索引过期写入后有后台 qmd update;若关闭了(PI_MEMORY_QMD_UPDATE=off),手动 qmd update
semantic / deep 报 "need embeddings"向量还没建后台会自动开始 embed——稍后重试;PI_MEMORY_QMD_UPDATEmanual/off 时自己跑 qmd embed
collection pi-memory 缺失自动建库没跑(qmd 是会话中途装的)跑任意 memory_search(会自动建)或手动 qmd collection add ~/.dsh/agent/memory --name pi-memory
Windows 上 qmd 在 shell 里能用、dsh 里不能.cmd/.ps1 shim 损坏插件会绕过 shim,直接用 node 调 qmd 的 JS 入口;确保 npm 全局 node_modules 目录在 PATH
写入后记忆没注入缓存稳定快照只在检查点刷新长期写入下一 turn 刷新;daily/scratchpad 用 memory_read,或设 PI_MEMORY_SNAPSHOT=per-turn

运行测试

# 单元测试(无 LLM、无 qmd——快、确定性。仅需 Node)
npm test

# 端到端测试(需要 dsh + API key,可选 qmd)
npm run test:e2e

# 没有 API key?用仓库根目录的 mock-llm.mjs(一个脚本化 mock LLM,规则见文件头注释):
node mock-llm.mjs                        # 起在 127.0.0.1:8099
DEEPSEEK_BASE_URL=http://127.0.0.1:8099 DEEPSEEK_API_KEY=mock-key npm run test:e2e

# 召回效果评估(需要 dsh + API key + qmd)
npm run test:eval

# 固定 provider/model 跑更便宜的 eval
PI_E2E_PROVIDER=deepseek-official PI_E2E_MODEL=deepseek-v4-flash npm run test:eval

所有测试都会备份并恢复现有记忆文件。

测试层级

层级命令需求测什么
单元npm testNode上下文构建、截断、handoff、scratchpad 解析、qmd 管道
E2Enpm run test:e2edsh + API key工具注册、写入 / 召回、scratchpad 生命周期、搜索
Evalnpm run test:evaldsh + API key + qmd有无选择性注入的召回准确率对比

开发

单文件插件(index.js),无需构建步骤。

# 直接用 dsh 测
P=verify-$(basename $PWD)-$$
dsh plugin --profile "$P" add @deepseek-ai/dsh-headless@next
dsh plugin --profile "$P" add .
dsh --profile "$P" "记住:我偏好深色模式"

# 验证记忆已写入
cat ~/.dsh/agent/memory/MEMORY.md

发布(维护者)

tag 驱动。推送 v* tag 会触发发布 workflow:lint、build、单元测试、校验 tag 与 package.json 版本一致,然后发布到 npm。

npm version patch   # 或 minor / major
git push --follow-tags

更新日志

上游 CHANGELOG.md 逐字保留(SHA-256 钉在 THIRD_PARTY_NOTICES.md 中,可自验)。dsh 移植本身的改动清单见移植票 #18 的交付回报。

第三方声明

上游 pi-memory 为 MIT 许可。完整声明与逐字文件校验见 THIRD_PARTY_NOTICES.md,许可文本见 LICENSE


English

dsh-pi-memory is a DeepSeek Harness (dsh) port of pi-memory, the most popular memory extension in the Pi ecosystem. Your coding agent forgets everything between sessions — this plugin gives it a memory: durable facts and decisions, a running daily log, and a scratchpad of things to come back to — all as plain Markdown files you can read, edit, and commit. With optional qmd it also gets keyword, semantic, and hybrid search across everything it has ever remembered.

Porting notes: the code and logic are 100% from upstream pi-memory (jayzeng/pi-memory, MIT). This port only changes the dsh plugin entry and lifecycle wiring; every change is listed with a reason in the delivery report of porting ticket #18. Please also star upstream pi-memory.

Known limitation: the prompts and memory-context templates injected into the agent are upstream English, preserved verbatim (not translated); the language of your memory content is up to you.

Features

ToolDescription
memory_writeWrite to MEMORY.md (long-term) or daily log
memory_forgetDelete matching entries and create a durable recovery record
memory_restoreRestore a deletion using the recovery ID returned by memory_forget
memory_readRead any memory file or list daily logs
scratchpadAdd/done/undo/clear/list checklist items
memory_searchSearch across all memory files (requires qmd)
memory_statusHealth check: where files live, qmd/collection/embeddings state, active config

The six core tools (memory_write, memory_forget, memory_restore, memory_read, scratchpad, memory_status) work immediately with no other setup. Search is opt-in below.

memory_search modes

ModeSpeedMethodBest for
keyword~30msBM25Specific terms, dates, names, #tags, [[links]]
semantic~2sVector searchRelated concepts, different wording
deep~10sHybrid + rerankingWhen other modes miss

What it feels like

# Session 1
you ▸ I always use pnpm in this repo, never npm. Remember that.
dsh ▸ Got it — saved to long-term memory.   (writes MEMORY.md)

# …days later, brand new session…
you ▸ add prettier as a dev dependency
dsh ▸ pnpm add -D prettier
      (recalled your package-manager preference from memory — no reminder needed)

Everything lives in $DSH_HOME/agent/memory/ (default ~/.dsh/agent/memory/) as Markdown, so you can also just cat it:

$ cat ~/.dsh/agent/memory/MEMORY.md
<!-- 2026-06-07 10:12:03 [a1b2c3d4] -->
#preference [[package-manager]] Always use pnpm in this repo, never npm.

Installation

⚠️ dsh-pi-memory is not published to npm yet — install from a local checkout below. Once published, a bare-name install works (this README will be updated).

# 1. Clone this repo and install dependencies
git clone https://github.com/GongYuanCaiJi/dsh-pi-memory.git
cd dsh-pi-memory && npm install

# 2. Add it to a dsh profile (headless one-shot runs also need @deepseek-ai/dsh-headless@next)
P=verify-$(basename $PWD)-$$
dsh plugin --profile "$P" add @deepseek-ai/dsh-headless@next
dsh plugin --profile "$P" add .

# 3. Use it
dsh --profile "$P" "Remember: I prefer dark mode"
dsh --profile "$P" "What did I say I prefer?"   # brand new session — it remembers

Optional: enable search with qmd

memory_search (and selective injection in per-turn mode) need qmd. Either install method works:

npm install -g @tobilu/qmd                      # no Bun required
bun install -g https://github.com/tobi/qmd      # ensure ~/.bun/bin is on PATH

When qmd is present, the plugin automatically creates the pi-memory collection and path contexts on the next session start — no manual step. Run memory_status any time to confirm qmd, the collection, and embeddings are ready.

Semantic/deep modes need vector embeddings; the plugin keeps them current automatically (qmd embed runs in the background at session start and after writes). The very first embed downloads the embedding model, so semantic search may take a minute to come online on a fresh install. To set the collection up by hand:

qmd collection add ~/.dsh/agent/memory --name pi-memory
qmd context add /daily "Daily append-only work logs organized by date" -c pi-memory
qmd context add / "Curated long-term memory: decisions, preferences, facts, lessons" -c pi-memory
qmd embed

Without qmd, the core tools still work fully — only memory_search and selective injection require it.

File layout

~/.dsh/agent/memory/
  MEMORY.md              # Curated long-term memory
  SCRATCHPAD.md           # Checklist of things to fix/remember
  daily/
    2026-02-15.md         # Daily append-only log
    2026-02-14.md
    ...
  recovery/
    <recovery-id>.json    # Complete payload and restore state for a memory_forget deletion

How it works

Context injection

Before every agent turn, the following are injected into the system prompt (in priority order):

  1. Open scratchpad items (up to 2K chars)
  2. Today's daily log (up to 3K chars, tail)
  3. MEMORY.md (up to 4K chars, middle-truncated)
  4. Yesterday's daily log (up to 3K chars, tail — lowest priority, trimmed first)

Total injection is capped at 16K chars.

KV cache-stable snapshot (default)

Local prefix-caching runtimes (llama.cpp, vLLM, MLX) invalidate from the first divergent token onward. If the injected memory block changes turn-to-turn, every subsequent user / assistant / tool token gets reprocessed — effectively the entire conversation history each turn.

To keep the prefix byte-stable, the plugin snapshots the memory context at deliberate checkpoints and emits the same bytes for every turn in between. Snapshots refresh on:

  • session start — fresh snapshot per session
  • compaction — handoff is written then snapshot refreshes (one intentional cache boundary)
  • memory_write with target: long_term — marks the snapshot dirty so the next turn refreshes
  • Day rollover — snapshot's captured date no longer matches today

memory_write with target: daily and scratchpad writes do not mark dirty — they're high-frequency and the write content is already echoed via tool-call args. The model can always call memory_read / memory_search for the authoritative latest state.

Set PI_MEMORY_SNAPSHOT=per-turn to opt out and restore the old per-turn rebuild behavior, including automatic per-prompt qmd search injection.

Selective injection (opt-in via per-turn mode)

When PI_MEMORY_SNAPSHOT=per-turn is set and qmd is available, the plugin automatically searches memory using the user's prompt before each turn. The top 3 keyword results are injected alongside the standard context. The search has a 3-second timeout and fails silently. In the default stable mode, the model gets the same capability by calling memory_search on demand.

Tags and links

Use #tags and [[wiki-links]] in memory content to improve searchability:

#decision [[database-choice]] Chose PostgreSQL for all backend services.
#preference [[editor]] User prefers Neovim with LazyVim config.
#lesson [[api-versioning]] URL prefix versioning (/v1/) avoids CDN cache issues.

These are content conventions, not enforced metadata. qmd's full-text indexing makes them searchable for free.

Session handoff

When the context window compacts, the plugin automatically captures a handoff entry in today's daily log:

<!-- HANDOFF 2026-02-15 14:30:00 [a1b2c3d4] -->
## Session Handoff
**Open scratchpad items:**
- [ ] Fix auth bug
- [ ] Review PR #42
**Recent daily log context:**
...last 15 lines of today's log...

Other behavior

  • Persistence: Memory files are plain Markdown on disk — readable, editable, and git-friendly.
  • Recoverable deletion: memory_forget stores complete deleted entries under recovery/ before changing memory and returns a recovery ID that memory_restore can use. Recovery JSON is outside qmd's **/*.md index.
  • Tool response previews: Write/scratchpad tools return size-capped previews instead of full file contents.
  • qmd auto-setup: On first session start with qmd available, the plugin creates the collection and path contexts automatically.
  • qmd re-indexing: After every write, a debounced qmd update runs in the background (fire-and-forget, non-blocking) unless disabled via PI_MEMORY_QMD_UPDATE.
  • qmd embeddings: Vector embeddings for semantic/deep search are kept current automatically — qmd embed (incremental) runs in the background after each re-index and as a catch-up at session start. Disabled along with re-indexing via PI_MEMORY_QMD_UPDATE.
  • Graceful degradation: If qmd is not installed, core tools work fine. memory_search returns install instructions.

Configuration

VariableValuesDefaultDescription
PI_MEMORY_DIRpath$DSH_HOME/agent/memoryOverride the memory storage directory (defaults under the dsh home, not Pi's ~/.pi)
PI_MEMORY_SNAPSHOTstable, per-turnstablestable snapshots memory at checkpoints for KV cache stability; per-turn rebuilds every turn (legacy behavior)
PI_MEMORY_QMD_UPDATEbackground, manual, offbackgroundControls automatic qmd update + qmd embed after writes
PI_MEMORY_QMD_SEARCH_TIMEOUT_MSpositive integer (milliseconds)60000Sets the timeout for explicit memory_search qmd queries
PI_MEMORY_NO_SEARCH1unsetDisable selective injection in per-turn mode (no effect in stable mode)
PI_MEMORY_SUMMARIZE_TRANSITIONS1, true, yes, onunsetAlso write exit summaries during lifecycle transitions (reload/new/resume/fork). By default these transitions skip summaries for speed.
PI_MEMORY_EXIT_SUMMARY0, off, false, no to disableunset (enabled)Disable the exit summary on session end. Ending then does no LLM call and no qmd update, so it is instant; explicit memory_write during sessions is unaffected.
PI_MEMORY_EXIT_SUMMARY_MODELprovider/model-idunset (session model)Model used to write the exit summary, e.g. a cheaper/faster one. Unresolvable specs fall back to the session model.
PI_MEMORY_EXIT_SUMMARY_TIMEOUT_MSpositive integer (milliseconds)10000Self-imposed timeout for exit-summary generation on session end. On expiry nothing is persisted.

Porting note: session_shutdown maps to dsh's agent/disposed — that event fires only when dsh disposes an agent while services are still live; in headless one-shot runs the services are torn down before plugin disposers run, so the exit summary is silently skipped (no crash, nothing persisted). This is a dsh-vs-Pi lifecycle difference, detailed in porting ticket #18.

Troubleshooting

Run the memory_status tool first — it reports most of these at a glance.

SymptomCauseFix
memory_search says qmd is requiredqmd not installed or not on PATHInstall qmd (npm install -g @tobilu/qmd); if installed via Bun, ensure ~/.bun/bin is on PATH
Search returns nothing for terms you know existIndex is staleA background qmd update runs after writes; if disabled (PI_MEMORY_QMD_UPDATE=off), run qmd update manually
"need embeddings" on semantic/deep searchVectors not built yetEmbedding starts automatically in the background — retry shortly. If PI_MEMORY_QMD_UPDATE is manual/off, run qmd embed yourself
Collection pi-memory missingAuto-setup didn't run (qmd installed mid-session)Run any memory_search (auto-creates it) or qmd collection add ~/.dsh/agent/memory --name pi-memory
qmd works in the shell but not from dsh on WindowsBroken .cmd/.ps1 shimsThe plugin bypasses them by invoking qmd's JS entry with node; make sure the npm global node_modules dir is on PATH
Memory isn't being injected after a writeCache-stable snapshot only refreshes at checkpointsLong-term writes refresh next turn; for daily/scratchpad use memory_read, or set PI_MEMORY_SNAPSHOT=per-turn

Running tests

# Unit tests (no LLM, no qmd — fast, deterministic. Node only.)
npm test

# End-to-end tests (requires dsh + API key, optionally qmd)
npm run test:e2e

# No API key? Use mock-llm.mjs at the repo root (a scripted mock LLM; its
# response rules are documented in the file header):
node mock-llm.mjs                        # serves on 127.0.0.1:8099
DEEPSEEK_BASE_URL=http://127.0.0.1:8099 DEEPSEEK_API_KEY=mock-key npm run test:e2e

# Recall effectiveness eval (requires dsh + API key + qmd)
npm run test:eval

# Pin provider/model for cheaper eval runs
PI_E2E_PROVIDER=deepseek-official PI_E2E_MODEL=deepseek-v4-flash npm run test:eval

All tests back up and restore existing memory files.

Test levels

LevelCommandRequirementsWhat it tests
Unitnpm testNodeContext builder, truncation, handoff, scratchpad parsing, qmd plumbing
E2Enpm run test:e2edsh + API keyTool registration, write/recall, scratchpad lifecycle, search
Evalnpm run test:evaldsh + API key + qmdRecall accuracy with vs without selective injection

Development

This is a single-file plugin (index.js). No build step required.

# Test with dsh directly
P=verify-$(basename $PWD)-$$
dsh plugin --profile "$P" add @deepseek-ai/dsh-headless@next
dsh plugin --profile "$P" add .
dsh --profile "$P" "remember: I prefer dark mode"

# Verify memory was written
cat ~/.dsh/agent/memory/MEMORY.md

Publishing (maintainers)

Releases are tag-driven. Pushing a v* tag runs the publish workflow, which lints, builds, runs the unit tests, verifies the tag matches package.json, and then publishes to npm.

npm version patch   # or minor / major
git push --follow-tags

Changelog

Upstream CHANGELOG.md is preserved verbatim (its SHA-256 is pinned in THIRD_PARTY_NOTICES.md so the claim is self-verifiable). The dsh port's own change list lives in the delivery report of porting ticket #18.

Third-party notices

Upstream pi-memory is MIT-licensed. Full notices and verbatim-file verification live in THIRD_PARTY_NOTICES.md; the license text is in LICENSE.