skepsun / dsh-loom

已收录

极简·省 token 的 DSH 长期记忆插件:零 LLM 自动捕获、符号索引渐进披露、ESR 证据闭环。Minimalist token-saving memory for DeepSeek Harness: zero-LLM auto-capture, symbolic index, ESR-lite evidence closure.

master模型会话 查看源代码

安装

npx -y @deepseek-ai/dsh plugin --profile web add github:skepsun/dsh-loom

此安装命令根据 GitHub 仓库地址生成,是未经验证的安装起点。

README

维护者编写的文档快照。

在 GitHub 查看 ↗
提交版本 997c972同步于 2026年8月18日

dsh-loom

English · 中文

Minimalist long-term memory for DeepSeek Harness, distilled from the pi-loom and pi-esr ideas — with one goal: save tokens.

  • Zero-LLM intake — auto-captures meaningful events from tool results by pure pattern matching (git milestones with a written -m commit message, edits to key files, repeated errors), plus an explicit loom_store. Nothing on the hot path calls a model, and pure plumbing — git push / git stash / silent commits — is deliberately never recorded (see Auto-capture policy below).
  • Symbolic index + progressive disclosure — a compact [LOOM] block (default budget 700 chars ≈ 175 tokens; one line per memory) is injected at prompt assembly and frozen per session, keeping the request prefix byte-stable for KV-cache reuse. The agent drills down with loom_recall / loom_detail instead of dumping raw hits into context.
  • ESR-lite closure protocolesr_task / esr_close / esr_link give tasks a draft → active → stable lifecycle where stable requires real evidence (artifact / evaluation / memory_ref), surfacing closure gaps instead of letting the agent declare victory without proof.
  • Memory GC (pi-esr constraints) — a scheduled, mechanical, archive-only sweep: TTL-expired memories are archived, over-cap workspaces evict the lowest-value entries, stable tasks past their retention window leave the [ESR] surface, and dangling link edges are dropped. The working set (active task refs, task memories, indexed hits) is never touched, and nothing is hard-deleted — every archived entry keeps its id and stays re-fetchable.
  • Web viewer — a memory browser with benchmark-ish stats and a config card, built entirely on DSH's native settings slots (no third-party UI package).
MIT   ·   node >= 22.19   ·   host-half + browser-half in one package

Why another memory plugin?

Surveys of the existing DSH plugin ecosystem show the recall-bridge, approval-gate, LLM-distillation and vector/graph niches are already crowded. dsh-loom fills the three gaps that matter for token discipline:

  1. No model in the write path — capture is deterministic pattern matching.
  2. No raw text in the prompt — a bounded symbolic index is injected, retrieval stays on demand ("retrieved ≠ injected").
  3. Honest task closure — STABLE cannot be declared without evidence.

DSH already provides cross-session FTS (ctx.sessionQuery), storage (ctx.storageDomain), prompt-injection hooks and settings slots; dsh-loom is a thin composition layer over them, not a re-implementation.

Install

# from GitHub (this repo)
dsh plugin --profile web add github:skepsun/dsh-loom

# once published to npm
dsh plugin --profile web add dsh-loom

# local development (symlink — edits apply immediately)
dsh plugin --profile web add link:/path/to/dsh-loom

Then restart dsh web. Data persists in ~/.dsh/storages/dsh_loom.json.

A fresh session is required to see the injected [LOOM]/[ESR] blocks and the tools; both prompts and the tools registry are assembled per session.

A symlinked plugin resolves its imports from its own node_modules, so the host-side dependencies must be present next to the checkout — they are not tracked by git:

cd /path/to/dsh-loom
node scripts/setup-links.mjs     # one command: links the @deepseek-ai
                                 # workspace packages into node_modules AND
                                 # installs zod (reused from the harness
                                 # pnpm store, or via `npm install`)

The script auto-locates the harness checkout at ../deepseek-harness (also works when it sits next to the repo's parent, e.g. E:\deepseek-harness + E:\kototoro_demo\dsh-loom); override with DSH_HARNESS_DIR. Without this step, dsh web boot fails with ERR_MODULE_NOT_FOUND: Cannot find package 'zod' (and would fail on the @deepseek-ai/* peers next). node scripts/setup-links.mjs --check prints the state without writing anything.

What you get in the GUI

After restart, inside the native DSH settings surface:

  • Settings → Loom Memory — overview stat cards (counts by workspace/kind, auto-capture totals, per-workspace [LOOM] index token estimate, cumulative GC totals), a searchable / filterable memory table with archive + delete actions, the ESR task board with evidence gaps, the relation list, and a memory-GC panel (dry-run toggle + run button + pointer report).
  • Settings → Plugins → dsh-loom — a config card bound to the dsh-loom settings namespace. Changes apply to new sessions (frozen blocks stay stable).

The browser half is served by DSH's client-module loader directly from this package (dsh.client + exports["./client"], no web-application rebuild); the data comes from the loopback-fenced /api/dsh-loom/* route family. If you change client/src, rebuild the bundle with:

npm run build:client

Tools

ToolPurposeKind
loom_storeExplicitly store one memory (kind, tags, optional entity anchor)write
loom_recallDeterministic keyword recall over workspace memories; optional search_sessions FTS over past sessionsread
loom_detailFull record of one memory id (provenance, tags, hits)read
esr_taskCreate a task entity (draft → active)write
esr_closeClose a task via the evidence protocol (artifact + evaluation + memory_ref)write
esr_linkAdd a typed relation between two entities (mini graph)write
esr_gcRun the memory GC for the workspace (dry_run:true previews)write

Memory GC

A scheduled sweep (gcIntervalHours, default 24h) plus a manual esr_gc / GUI button keeps the store bounded the pi-esr way — mechanical, working-set protected, archive-only:

  • TTL-expired memories are archived (soft; the id stays, retrievable via the GUI's archived filter);
  • over-cap workspaces evict the lowest-value non-protected memories;
  • stable tasks past gcStableRetentionDays become archived and leave [ESR];
  • links whose both endpoints are gone are dropped (dangling edges).

GC never touches the working set: memories referenced by an active task (memory_refs), task-kind memories, and already-indexed hits (hits >= promoteHits). Run esr_gc with dry_run: true to preview. Nothing is hard-deleted — the report ends with re-fetch pointers for everything it archived, so archives are recoverable, not lost.

Auto-capture policy

Capture is deterministic and offline — it only sees tool results, never the conversation. Exactly what earns a memory record:

Tool resultActionSignal
git commit … -m "subject"record — the written subject is the memory0.55
git merge / rebase / cherry-pick / tag / checkout -brecord (milestone)0.5
git push / git stash / commit without -mskip — plumbing echo, not a decision
write/edit of a significant config & doc pathrecord0.3
read of a config pathrecord0.3
repeated tool errorrecord (deduped by message)0.25

Explicit loom_store writes are always recorded regardless of these rules (rate-limited per session).

Who earns a [LOOM] index line (this is what actually touches the prompt): signal >= minIndexSignal or hits >= promoteHits or kind === "task", then capped by indexMaxLines / indexMaxChars. One extra guard keeps the pipe clean: auto-captured git command echoes — text that embeds a shell chain (git push: cd … && …) — stay out of the index even when above the signal threshold, until recall hits have promoted them. Everything else sits quietly in storage, reachable on demand via loom_recall / loom_detail — "retrieved ≠ injected".

Injected blocks

What the model actually sees (rendered once per session, then frozen):

[LOOM] workspace: pi-loom · 2 memories · 1 task(s) active · 0 links
[D] 06-18 Decided: use sqlite-vec for retrieval #a2331d87
[T] 06-18 Retrieval upgrade — ACTIVE · gap: artifact, evaluation, memory_ref #tsk_8b26
drill: loom_recall <query> | loom_detail <id> | esr_task / esr_close / esr_link

[ESR] tasks: 1 active / 1 stable
- tsk_0d: Retrieval upgrade — ACTIVE · gap: artifact, evaluation, memory_ref
- closed: tsk_9a (RAG eval)  ·  +1

Prefixes: [D] decision · [E] error · [P] procedure · [F] fact · [I] insight · [H] handoff · [T] task. Membership follows the Auto-capture policy (signal threshold / recall promotion / git-echo guard), bounded by the configured line and character budgets. # ids address the full records via loom_detail.

Config

Defaults are token-conscious; override any key via the profile patch (~/.dsh/profiles/web/cordis.patch.yml) or the web config card:

- id: loom
  config:
    autoCapture: true        # zero-LLM tool-result capture
    sessionSearch: true      # loom_recall may also FTS past sessions
    autoCapturePerSession: 40
    indexMaxLines: 12        # [LOOM] line cap
    indexMaxChars: 700       # [LOOM] char cap (token budget)
    minIndexSignal: 0.4      # auto-captures below this stay out of the index
                             # (git command echoes are excluded regardless,
                             # until promoted by recall hits)
    promoteHits: 3           # ...until recalled this many times
    expireDays: 180          # memory TTL (0 = never)
    maxMemoriesPerWorkspace: 2000
    gcEnabled: true          # scheduled memory GC
    gcIntervalHours: 24      # sweep cadence
    gcStableRetentionDays: 120  # stable tasks leave [ESR] after this
    loomIndexOrder: 40       # systemPrompt section order (before tools band)
    esrOrder: 41

Development

npm test            # 21 tests: core + web API + GC (node:test)
npm run build:client

Repo layout: lib/ (host half: store / capture / index-block / tools / api / settings), client/ (browser half, TSX + build.mjs), test/ (node:test).

  • pi-loom — the original cross-session memory plugin (5-signal RRF fusion, sqlite-vec, Dream Engine).
  • pi-esr — project-lifetime evidence-driven task states; the closure protocol here is its lite form.

License

MIT

项目文件与信号

以下项目是目录快照中检测到的公开仓库信号。

测试已检测

仓库信息

开发语言
JavaScript
许可证
MIT
最后更新
2026年8月18日 16:09

谨慎安装

请检查源代码、权限、生命周期脚本、依赖与网络访问;不受信任的插件应先在隔离环境中测试。