dsh-memento 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,132 +1,107 @@
1
+ <div align="center">
2
+
1
3
  # dsh-memento
2
4
 
3
5
  **Bounded, layered, approval-gated, auditable cross-session memory for DeepSeek Harness.**
4
6
 
5
- [![license](https://img.shields.io/badge/license-Apache--2.0-3a7d44)](LICENSE)
6
- [![dsh](https://img.shields.io/badge/dsh-0.1.0--rc.6-4e51e8)](https://www.npmjs.com/package/@deepseek-ai/dsh)
7
- [![node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-339933)](https://nodejs.org/)
8
- [![platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey)]()
9
- [![no build step](https://img.shields.io/badge/build-none%20%28pure%20ESM%29-8a6d3b)]()
7
+ *A typed `ctx.memory` seam, a write-approval gate no model path can bypass, and audit trails rebuilt from the session log.*
8
+
9
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
10
+ [![DSH plugin](https://img.shields.io/badge/dsh-plugin-✅-green)](https://github.com/topics/dsh-plugin)
11
+ [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen.svg)](#)
12
+ [![CI](https://img.shields.io/github/actions/workflow/status/PerryLink/dsh-memento/ci.yml?branch=main&label=CI)](https://github.com/PerryLink/dsh-memento/actions)
13
+ [![Version](https://img.shields.io/github/v/tag/PerryLink/dsh-memento?label=version)](https://github.com/PerryLink/dsh-memento/releases)
10
14
  [![npm version](https://img.shields.io/npm/v/dsh-memento)](https://www.npmjs.com/package/dsh-memento)
11
15
  [![npm downloads](https://img.shields.io/npm/dm/dsh-memento)](https://www.npmjs.com/package/dsh-memento)
12
- [![CI](https://github.com/PerryLink/dsh-memento/actions/workflows/ci.yml/badge.svg)](https://github.com/PerryLink/dsh-memento/actions/workflows/ci.yml)
13
-
14
- [English](README.md) · [中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
15
16
 
16
- > Other memory plugins sell a **warehouse**. dsh-memento sells the **seam**: a typed `ctx.memory` service, a write approval gate no model path can bypass, and audit trails you can rebuild from the session log. Native-first memory for DeepSeek Harness — protocol + trust gate + audit, with zero network and zero credentials.
17
+ [English](README.md) · [简体中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
17
18
 
18
- ## ✨ Why dsh-memento?
19
+ </div>
19
20
 
20
- - **It's a capability seam, not another store.** Service Definition (`ctx.memory`), local SQLite Provider (`node:sqlite`, WAL, `0600`), and Consumers (`memory` tool + frozen snapshot injection). Any future plugin — a `dsh-claude-move` seed integration, a bridge, a panel — feeds and reads the **same store through the same gate**.
21
- - **The gate cannot be bypassed.** Every write path (`add`/`replace`/`remove`/`seed`) is forced through the approval waterfall **inside the service**, not in the tool layer. `writePolicy: ask | auto | off` is configuration the model can neither see nor change; a session-level `never` stance still pre-empts everything. `replace`/`remove`/`consolidate` carry the full text of the entries they will change in the approval payload — what you approve is what you see, and a denied write still lands a `*-denied` audit row.
22
- - **Model-visible ⟺ logged.** The injected snapshot lands verbatim in `request/header.system`; every write is reconstructable from `approval/asked` (full payload) + `approval/decided` (outcome) + the plugin's own audit table.
23
- - **Bounded and honest.** Hard per-track/per-layer character budgets (default user 2000 / agent 4000). A full store **fails with a structured error** (usage + limit) — the model consolidates and retries. Never truncated, never auto-compacted.
21
+ ---
24
22
 
25
- ## ⚡ Quick start
26
-
27
- ```sh
28
- # requires Node ^22.19 || >=24 and DSH 0.1.0-rc.6
29
- dsh plugin --profile web add dsh-memento # or ./dsh-memento / a tarball / a GitHub URL
30
- dsh --profile web --dump-config # expect a "# == dsh-memento" layer, no FAILED at startup
31
- ```
23
+ ## Compatibility
32
24
 
33
- Then, in the Web UI: ask the model to remember something → approve the write → start a **new session** and ask what it remembers. That's the whole demo.
34
-
35
- ```yaml
36
- # optional override in the profile's cordis.patch.yml
37
- - id: memento
38
- config:
39
- writePolicy: ask # ask (default) | auto | off — model-invisible
40
- budgets:
41
- user: { userGlobal: 4000, workspace: 2000 } # Chinese-heavy memory: raise + note why
42
- agent: { userGlobal: 4000, workspace: 4000 }
43
- ```
25
+ | Surface | Status |
26
+ |---|---|
27
+ | Harness | DeepSeek Harness `0.1.0-rc.6` |
28
+ | Node | `^22.19.0 || >=24.0.0` |
29
+ | Platforms | Windows / macOS / Linux (pure host; no native code, no network) |
30
+ | Model | Any |
44
31
 
45
- ## 🧠 What it does
32
+ ## What you get
46
33
 
47
- | | Component | What you get |
48
- | --- | --- | --- |
49
- | 🧩 Service Definition | `ctx.memory` — `add` / `replace` / `remove` / `query` / `seed` / `budgets()` | Typed, merge-declared service; write methods enforce the gate internally |
50
- | 🧬 Adapter registry | `ctx.memoryAdapters` — `register` / `list` / `adapt` / `export` | Third-party memory plugins adapt their own stores into the protocol; reference adapters for mem0, Hermes `memory.md`, and `CLAUDE.md` ship built-in |
51
- | 💾 Provider | `lib/store.mjs` — `node:sqlite` single file (`$DSH_HOME/dsh-memento/memory.db`, WAL) | Zero dependencies, zero network; entry + audit tables; unique-substring match |
52
- | 🛠 Consumers | `memory` tool · frozen snapshot injection (system-prompt section, order `-50`) · `memory_recall` tool · `/memory` command · read-only Web panel | Model-facing writes/reads, budget-headed frozen snapshot, two-part recall, user-side command, browser drawer |
34
+ `dsh-memento` is a capability seam, not another memory warehouse: a typed `ctx.memory` service, a local SQLite provider (`node:sqlite`, WAL, `0600`, at `$DSH_HOME/dsh-memento/memory.db`), and its consumers — the `memory` tool and a frozen snapshot injected into the system prompt.
53
35
 
54
- **Two tracks × two layers × per-agent key.** `user` track = facts about the user (preferences, communication style, landmines); `agent` track = environment facts, project conventions, lessons learned. Each track has `user-global` (cross-workspace) and `workspace` (per-session cwd) layers — Codex-style merged layering, not Hermes-style global-only. A third dimension isolates entries by the session's `agentPreset` (per-agent scope); entries without a preset stay in the shared layer visible to everyone. Session-scoped reads and write targeting follow the same visibility: a session sees — and `replace`/`remove` can only touch — shared entries plus its own agent's entries, and `workspace` entries only for its own cwd. The management surfaces (`/memory`, the panel) keep the full cross-agent view.
36
+ - **The approval gate cannot be bypassed.** Every write path (`add` / `replace` / `remove` / `seed`) is forced through the approval waterfall inside the service, not in the tool layer. `writePolicy: ask | auto | off` is model-invisible configuration; `replace` / `remove` / `consolidate` carry the full text of the entries they change in the approval payload, and a denied write still lands a `*-denied` audit row.
37
+ - **Model-visible ⟺ logged.** The injected snapshot lands verbatim in `request/header.system`; every write is reconstructable from `approval/asked` + `approval/decided` + the plugin's own audit table.
38
+ - **Bounded and honest.** Hard per-track/per-layer character budgets (default user 2000 / agent 4000). A full store fails with a structured error (usage + limit) — never truncated, never auto-compacted.
55
39
 
56
- **Frozen snapshots.** The snapshot is rendered once per session at first prompt assembly (synchronous SQLite read + per-session cache) and never changes mid-session — prefix-cache stable by construction. Session-internal changes persist to disk + audit only.
40
+ Two tracks × two layers × per-agent key: a `user` track (facts about the user) and an `agent` track (environment facts and conventions), each split into `user-global` and `workspace` layers, isolated per `agentPreset`. The snapshot is frozen once per session at first prompt assembly and never changes mid-session.
57
41
 
58
- ```
59
- Consumer: memory tool Consumer: frozen snapshot (systemPrompt section, order -50)
60
- add/replace/remove/query per-session freeze, budget-headed
61
- │ writes (agent+callId) │ reads (sync, session cwd)
62
- ▼ ▼
63
- Service Definition: ctx.memory — budgets/add/replace/remove/query/seed
64
- every write: budget precheck → ctx.approval.request (approval waterfall) → budget recheck → persist → audit
65
- │
66
- ▼
67
- Provider: lib/store.mjs — node:sqlite (WAL, 0600), entries + audit tables, unique-substring match
68
- ```
69
-
70
- ## 🧰 Install & uninstall
42
+ ## Quick start
71
43
 
72
44
  ```sh
73
- dsh plugin --profile <name> add ./dsh-memento # local checkout (no build step)
74
- dsh plugin --profile <name> add dsh-memento # npm package (0.2.0+, published)
75
- dsh plugin --profile <name> add git+https://github.com/PerryLink/dsh-memento.git # GitHub install
76
- dsh plugin --profile <name> remove dsh-memento # uninstall: DB + session logs are kept
77
- ```
78
-
79
- After uninstall the memory database and the session logs that recorded memory activity remain; old sessions stay loadable.
80
-
81
- ## ⚙️ Configuration
82
-
83
- Every field is a validated Schemastery `Config`; invalid values fail loudly at load. Override in cordis.yml under the `memento` row.
45
+ # 1. install the bundle into your profile
46
+ dsh plugin --profile web add "github:PerryLink/dsh-memento#main"
84
47
 
85
- | Field | Default | Meaning |
86
- | --- | --- | --- |
87
- | `enabled` | `true` | `false` removes the service, tools, snapshot, command, panel, and answerer entirely (no half-state) |
88
- | `dbPath` | `''` → `$DSH_HOME/dsh-memento/memory.db` | absolute, or relative to `$DSH_HOME`; when `$DSH_HOME` is not exported (the Windows default — `dsh web` does not write the resolved home back to the env), both fall back to `~/.dsh` |
89
- | `budgets.user.userGlobal` / `budgets.user.workspace` | `2000` / `2000` | hard char budget per layer of the user track |
90
- | `budgets.agent.userGlobal` / `budgets.agent.workspace` | `4000` / `4000` | hard char budget per layer of the agent track |
91
- | `writePolicy` | `'ask'` | `'ask'` = user approval; `'auto'` = allow through (approval source recorded); `'off'` = reject. Model-invisible |
92
- | `writePolicies` | `{}` | per-track/scope or per-source overrides: keys `user/workspace`, `agent/user-global`, `source:claude`, … → `ask`/`auto`/`off`; unmatched falls back to `writePolicy` |
93
- | `language` | `'en'` | model-visible text and command output language: `'en'` (default) or `'zh'` — tool descriptions, frozen snapshot, `/memory` command, and web panel all follow it |
94
- | `snapshotOrder` | `-50` | snapshot section order: after harness identity (`-100`), before persona (`0`) |
95
- | `maxEntriesPerQuery` | `20` | default per-query result cap (explicit `limit` allowed, hard-capped at 1000) |
96
- | `commandListLimit` | `50` | entries rendered per `/memory list` / `query` command |
97
- | `commandAuditLimit` | `10` | audit rows rendered per `/memory audit` command |
98
- | `recall.historyLimitDefault` / `recall.snippetCap` / `recall.snippetChars` / `recall.windowDays` | `8` / `5` / `300` / `30` | `memory_recall` history defaults: sessions scanned, snippets per session, snippet chars, recency window in days |
99
- | `panelEntriesLimit` | `200` | web panel entries page size (and clamp) |
100
- | `panelAuditLimit` | `20` | web panel audit rows by default (ceiling 200) |
101
- | `auditRetentionDays` | `0` | audit retention: 0 = keep forever, >0 = prune rows older than N days at store open |
102
- | `proposals.enabled` / `proposals.maxChars` / `proposals.maxPending` | `true` / `2000` / `8` | auto-capture: pending memory proposal after each successful compaction (truncated, one per session); disable or tune caps |
48
+ # or from npm (published releases)
49
+ dsh plugin --profile web add dsh-memento
103
50
 
104
- ## 🛠 Tools & surfaces
105
-
106
- - **`memory`** — add/replace/remove/consolidate/query with Save/Skip guidance embedded in the description (save user preferences, corrections, environment facts, conventions, lessons; skip trivia, re-derivable facts, dumps, one-off paths). Writes ride the approval gate; reads are free; replace/remove target a **unique substring** (ambiguous matches fail with the candidate list); consolidate merges 1..20 entries into one with a single approval and one atomic write. Entries carry protocol v1 fields: short `tags` (≤16 × ≤32 chars) and a per-entry `version` that increments on every replace.
107
- - **`memory_recall`** — two-part recall: bounded memory matches **plus** recent session-history matches via `ctx.sessionQuery` (degrades gracefully to memory-only where the service is absent).
108
- - **`/memory`** — user-triggered command (not a model turn): `list` · `query <word>` · `add [--track=user|agent] [--scope=user-global|workspace] <text>` · `remove [flags] <substring>` · `consolidate [flags] <substring...> => <text>` · `proposals [approve|dismiss <id>]` · `budgets` · `audit` · `export [--adapter=<id>]` · `import <path> [--adapter=<id>]` · `adapters`. Command writes ride the same waterfall + policy; audit lands in the plugin audit table + `command/done`. `export` is read-only and dumps all entries + budgets as one JSON document; `import` restores it (file path or inline JSON, single approval, budget pre-checked) — a complete backup/migration round-trip. Adapter verbs convert external memory formats: `import --adapter=mem0 <facts.json>` feeds facts through the approval-gated `seed`; `export --adapter=<id>` prints a read-only conversion to stdout. Imported entries get fresh ids and timestamps; proposals, audit rows and recall counts are not migrated.
109
- - **Auto-capture proposals** — after a successful session compaction, the summary lands as a pending memory proposal (`agent/workspace`); approving writes it through the approval gate, dismissing drops it. Pending proposals appear in the frozen snapshot and the panel.
110
- - **Web panel** — zero-build `dsh.client` drawer: browse entries by track/layer, search, budget bars, audit tail. Read-only by design: writes and approval happen through the `memory` tool and the built-in approval UI.
111
-
112
- ## 🎓 What we learned from the terminal memories
113
-
114
- dsh-memento is not a port of Claude Code, Codex, or Hermes — but its design deliberately absorbed the parts each of them got right, and refused the parts that hurt:
115
-
116
- | Terminal memory | What it got right | What dsh-memento adopted |
117
- | --- | --- | --- |
118
- | **Claude Code** — `CLAUDE.md` | hierarchical **plain-text memory files** (user-level → project-level) that are human-readable, human-editable, and merged automatically into every session — memory you can read and fix yourself | plain-text entries; `user-global` / `workspace` layers merged per session; a store you can browse, `export`, and audit — transparency as a feature |
119
- | **Codex** — `AGENTS.md` | **per-directory scoped instructions** auto-discovered and injected with zero model friction — locality beats volume, no tool call needed to "load" memory | `workspace` layer keyed by the session's cwd (Windows case-insensitive); the frozen snapshot is injected automatically at session start |
120
- | **Hermes** — `memory.md` | **proactive memory saves** (save/update/delete) and, in [issue #48181](https://github.com/NousResearch/hermes-agent/issues/48181), the security lesson that a gate enforced only in the tool layer is bypassable by late tool injection — enforce it where every write path meets | the `memory` tool with explicit Save/Skip guidance + approval-gated auto-capture proposals; the approval gate lives **inside** `ctx.memory`'s write methods, not in the tool layer |
121
-
122
- Sources: [Claude Code memory](https://code.claude.com/docs/en/memory) · [Codex AGENTS.md](https://developers.openai.com/codex/cli/agents-md) · [Hermes memory](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/memory.md) · [Hermes #48181](https://github.com/NousResearch/hermes-agent/issues/48181).
123
-
124
- And the parts we deliberately refused: hidden auto-summarization into model-private state (compaction summaries here become **pending proposals** that wait for a human approve/dismiss), warehouse/vector-store ambitions, and any write that lacks a human-visible approval or audit trail. Also adopted: Hermes's documented caveat that two processes sharing one home directory write the same memory file — see Security boundaries.
51
+ # 2. restart and verify the row
52
+ dsh --profile web --dump-config | grep -A3 'id: memento'
53
+ ```
125
54
 
126
- ## 🆚 How it's different
55
+ ## Install & uninstall
56
+
57
+ - **git channel** (latest `main`): `dsh plugin --profile web add git+https://github.com/PerryLink/dsh-memento.git`.
58
+ - **npm channel** (published releases): `dsh plugin --profile web add dsh-memento`.
59
+ - **tarball channel**: `npm pack` in this repo, then `dsh plugin --profile web add ./dsh-memento-<version>.tgz`.
60
+ - **uninstall**: `dsh plugin --profile web remove dsh-memento` (the memory database and session logs are kept).
61
+
62
+ ## Configuration
63
+
64
+ All tunables are Schemastery `Config` fields (changeable from cordis.yml). Invalid values fail loudly at load. Override under the `memento` row.
65
+
66
+ | Key | Default | Meaning |
67
+ |---|---|---|
68
+ | `enabled` | `true` | Master switch; `false` removes the service, tools, snapshot, command, panel, and answerer |
69
+ | `dbPath` | `''` → `$DSH_HOME/dsh-memento/memory.db` | Absolute, or relative to `$DSH_HOME` (falls back to `~/.dsh` on Windows) |
70
+ | `budgets.user.userGlobal` | `2000` | Hard character budget for the user track's user-global layer |
71
+ | `budgets.user.workspace` | `2000` | Hard character budget for the user track's workspace layer |
72
+ | `budgets.agent.userGlobal` | `4000` | Hard character budget for the agent track's user-global layer |
73
+ | `budgets.agent.workspace` | `4000` | Hard character budget for the agent track's workspace layer |
74
+ | `writePolicy` | `'ask'` | Default write policy: `ask` / `auto` / `off` (model-invisible) |
75
+ | `writePolicies` | `{}` | Per-track/scope or per-source overrides (e.g. `user/workspace`, `source:claude`) |
76
+ | `language` | `'en'` | Model-visible and command output language: `en` / `zh` |
77
+ | `snapshotOrder` | `-50` | Snapshot section order (after harness identity, before persona) |
78
+ | `maxEntriesPerQuery` | `20` | Default per-query result cap (hard-capped at 1000) |
79
+ | `commandListLimit` | `50` | Entries rendered per `/memory list` / `query` |
80
+ | `commandAuditLimit` | `10` | Audit rows rendered per `/memory audit` |
81
+ | `recall.historyLimitDefault` | `8` | `memory_recall` sessions scanned by default |
82
+ | `recall.snippetCap` | `5` | `memory_recall` snippets per session |
83
+ | `recall.snippetChars` | `300` | `memory_recall` snippet characters |
84
+ | `recall.windowDays` | `30` | `memory_recall` recency window in days |
85
+ | `panelEntriesLimit` | `200` | Web panel entries page size |
86
+ | `panelAuditLimit` | `20` | Web panel audit rows by default |
87
+ | `auditRetentionDays` | `0` | Audit retention (0 = keep forever) |
88
+ | `proposals.enabled` | `true` | Auto-capture a memory proposal after each successful compaction |
89
+ | `proposals.maxChars` | `2000` | Proposal character cap |
90
+ | `proposals.maxPending` | `8` | Pending proposal cap |
91
+
92
+ ## Tools & surfaces
93
+
94
+ | Surface | Kind | Notes |
95
+ |---|---|---|
96
+ | `memory` | tool | add/replace/remove/consolidate/query with Save/Skip guidance; writes ride the approval gate |
97
+ | `memory_recall` | tool | Bounded memory matches plus recent session-history matches |
98
+ | `/memory` | command | `list` · `query` · `add` · `remove` · `consolidate` · `proposals` · `budgets` · `audit` · `export` · `import <path>` · `adapters` |
99
+ | web panel | client drawer | Read-only: browse entries, search, budget bars, audit tail |
100
+
101
+ ## How it's different
127
102
 
128
103
  | Plugin | What it is | dsh-memento's difference |
129
- | --- | --- | --- |
104
+ |---|---|---|
130
105
  | dsh-memory-evolve | memory warehouse / evolution loops | a typed service seam, approval gate, and session-log audit; no warehouse ambition |
131
106
  | dsh-mnemon | memory store helper | protocol + gate + audit, not another store |
132
107
  | dsh-kb-sieve | knowledge-base sieving | no retrieval engineering: small-corpus substring search, cross-session recall via `session_search`/`sessionQuery` |
@@ -137,59 +112,83 @@ And the parts we deliberately refused: hidden auto-summarization into model-priv
137
112
 
138
113
  The name is **`dsh-memento`** (published on npm and GitHub). Not `dsh-recall` (confusable with dsh-external/Recall), not the deleted legacy name `dsh-memory`.
139
114
 
140
- ## 🧬 dsh-memory-protocol v1
115
+ ## dsh-memory-protocol v1
116
+
117
+ `dsh-memento` is the community rehearsal of the DSH memory protocol — a candidate shape for an official `ctx.memory` seam. The protocol normalizes this plugin's seam into a cross-plugin contract:
141
118
 
142
- dsh-memento is the community rehearsal of the **DSH memory protocol** — a candidate shape for an official `ctx.memory` seam. The protocol normalizes this plugin's seam into a cross-plugin contract: entry spec (two tracks × two layers × per-agent key + `tags` + per-entry `version`), write-operation semantics (idempotency by unique-substring conditional writes, approve-what-you-see payloads), the audit contract (every write reconstructable from `approval/asked` + `approval/decided` + the provider ledger), the budget model (`BUDGET_EXCEEDED` / `AMBIGUOUS_MATCH` semantics), and schema versioning/migration rules.
119
+ - **Entry spec** — two tracks × two layers × per-agent key, plus short `tags` (≤16 × ≤32 chars) and a per-entry `version` that increments on every `replace`.
120
+ - **Write semantics** — idempotent unique-substring conditional writes; approve-what-you-see payloads (`replace` / `remove` / `consolidate` carry the full text they change).
121
+ - **Audit contract** — every write reconstructable from `approval/asked` + `approval/decided` + the provider ledger.
122
+ - **Budget model** — `BUDGET_EXCEEDED` / `AMBIGUOUS_MATCH` semantics.
123
+ - **Schema versioning** — migration rules with loud version checks.
143
124
 
144
125
  - **Spec** — [docs/protocol-v1.md](docs/protocol-v1.md) (中文: [protocol-v1.zh.md](docs/protocol-v1.zh.md)); normative JSON Schema at [docs/schemas/dsh-memory-protocol-v1.schema.json](docs/schemas/dsh-memory-protocol-v1.schema.json).
145
- - **Adapter registry** — `ctx.memoryAdapters` lets third-party memory plugins speak the protocol by registering a pure data converter (reversible `register()`; import rides the approval-gated `seed`, export is read-only). Onboarding: [docs/adapters-guide.md](docs/adapters-guide.md) (中文: [adapters-guide.zh.md](docs/adapters-guide.zh.md)).
126
+
127
+ **Adapter registry** — `ctx.memoryAdapters` (`register` / `list` / `adapt` / `export`) lets third-party memory plugins speak the protocol by registering a pure data converter (reversible `register()`; import rides the approval-gated `seed`, export is read-only). Onboarding: [docs/adapters-guide.md](docs/adapters-guide.md) (中文: [adapters-guide.zh.md](docs/adapters-guide.zh.md)).
146
128
 
147
129
  | Built-in adapter | External format | Notes |
148
- | --- | --- | --- |
149
- | `mem0` | mem0 fact collections (`{facts: [{memory, metadata?}]}`) | `metadata.category`/`metadata.tags` become tags; raw `messages` arrays are rejected — adapters convert, never extract |
130
+ |---|---|---|
131
+ | `mem0` | mem0 fact collections (`{facts: [{memory, metadata?}]}`) | `metadata.category` / `metadata.tags` become tags; raw `messages` arrays are rejected — adapters convert, never extract |
150
132
  | `hermes-memory-md` | Hermes `memory.md` (`## section` + bullets) | section names become tags; non-bullet prose fails loudly |
151
133
  | `claude-code-memory-md` | `CLAUDE.md`-style markdown (headings, bullets, paragraphs) | bullets and paragraphs become entries; section names become tags |
152
134
 
153
- - **Conformance suite** — [test/protocol-conformance/](test/protocol-conformance/README.md): a distributable case set any provider claiming compatibility runs (`node test/protocol-conformance/run.mjs --provider ./your-factory.mjs`); this repo's CI runs it against its own provider as the golden reference (`npm run test:conformance`).
135
+ **Conformance suite** — [test/protocol-conformance/](test/protocol-conformance/README.md): a distributable case set any provider claiming compatibility runs (`node test/protocol-conformance/run.mjs --provider ./your-factory.mjs`); this repo's CI runs it against its own provider as the golden reference (`npm run test:conformance`).
136
+
154
137
  - **Upstream proposal** — [docs/upstream-proposal.md](docs/upstream-proposal.md) (中文: [upstream-proposal.zh.md](docs/upstream-proposal.zh.md)): why the official `ctx.memory` seam should adopt the protocol, the differences, and the migration path.
155
138
 
156
- ## 🔒 Security boundaries
139
+ ## Permissions & data
157
140
 
158
- - **Public services only** (`tools`, `systemPrompt`, the approval seam). No engine / agent-loop / apiproxy / official-UI changes.
159
- - **Zero network, zero credentials.** Local database; POSIX file mode `0600`.
160
- - **Fail loud.** Corrupt DB or newer schema fails at load; full budgets and ambiguous substring matches fail with structured errors. Nothing silently swallowed or truncated.
161
- - **One process, one store.** Multiple sessions in one process share the SQLite store (serialized writes, per-session audit). Two **processes** sharing one `$DSH_HOME` write the same file: last-writer-wins under SQLite locking — don't run two harness instances on one `$DSH_HOME` if you need cross-process consistency (same caveat the Hermes project documents).
141
+ - **Permissions**: declares `harness:tool`, `filesystem:read`, `filesystem:write`, and `network:none` / `subprocess:none` / `shell:none` / `python:none` / `credentials:none` in its workshop manifest. Write approval rides the official approval seam.
142
+ - **Data**: local SQLite database (`0600`), zero network, zero credentials.
143
+ - **Session log**: audit completeness comes from the approval pair (`approval/asked` + `approval/decided`) plus the plugin's own audit table.
162
144
 
163
- ## ⚠️ Known limitations
145
+ ## Security boundaries
164
146
 
165
- - **Session events vocabulary is declared, not yet emitted (rc.6).** `memory/added|updated|removed|recalled|snapshot` are merge-declared in `types.d.ts`, but rc.6 has no registration surface for out-of-repo event types (unregistered appends would make persisted sessions unloadable). Audit completeness comes from the approval pair + the audit table; emission turns on automatically once a harness build registers the types. See [ARCHITECTURE.md](ARCHITECTURE.md) decision 4.
166
- - **`ask` policy needs an answerer.** With no UI/ACP answerer composed, writes fail closed (`unavailable`) — by design, the approval seam's fail-closed stance.
167
- - **No FTS5 indexing.** Substring search runs on case-insensitive `instr` (correct for CJK); recall ranking uses per-entry hit counts. FTS5's trigram tokenizer cannot index single-character CJK tokens, so it is not used — see [ARCHITECTURE.md](ARCHITECTURE.md) decision 10.
147
+ - **Public services only.** Consumes `tools`, `systemPrompt`, and the approval seam; no engine / agent-loop / apiproxy / official-UI changes.
148
+ - **Zero network, zero credentials.** Local database with POSIX file mode `0600`.
149
+ - **Fail loud.** Corrupt DB, newer schema, or invalid config fails at load; full budgets and ambiguous substring matches fail with structured errors.
150
+ - **One process, one store.** Multiple sessions share the SQLite store; two processes sharing one `$DSH_HOME` write the same file (last-writer-wins under SQLite locking).
168
151
 
169
- ## 🧪 Development
152
+ ## Known limitations
170
153
 
171
- ```sh
172
- npm install
173
- npm test # node --test: 133 tests — budget, unique-substring, gate policy, store, snapshot, mock-ctx integration (S2/S3 invariants), V2 command/recall/panel/import, protocol adapters + conformance
174
- npm run test:conformance # dsh-memory-protocol v1 conformance suite (golden reference; third-party providers use --provider)
175
- npm run typecheck # tsc --checkJs gate over index.mjs / lib / scripts
176
- npm run check:coverage # line-coverage gate: lib ≥90%, index.mjs ≥85%, all files ≥90%
177
- npm run check:readmes # five-language README consistency gate
178
- ```
154
+ - **Session events are declared, not yet emitted (rc.6).** `memory/added|updated|removed|recalled|snapshot` are merge-declared, but rc.6 has no registration surface for out-of-repo event types; emission turns on once a harness build registers them.
155
+ - **`ask` policy needs an answerer.** With no UI/ACP answerer composed, writes fail closed.
156
+ - **No FTS5 indexing.** Substring search runs on case-insensitive `instr` (correct for CJK).
157
+
158
+ ## What we learned from the terminal memories
179
159
 
180
- `lib/` is zero-DSH-dependency (node: builtins only); DSH imports exist only in `index.mjs`. Full discipline in [AGENTS.md](AGENTS.md); design decisions in [ARCHITECTURE.md](ARCHITECTURE.md).
160
+ `dsh-memento` is not a port of Claude Code, Codex, or Hermes — but its design deliberately absorbed the parts each got right, and refused the parts that hurt:
181
161
 
182
- ## 🏷 Topics
162
+ | Terminal memory | What it got right | What dsh-memento adopted |
163
+ |---|---|---|
164
+ | **Claude Code** — `CLAUDE.md` | hierarchical plain-text memory files (user-level → project-level), human-readable and human-editable, merged automatically into every session | plain-text entries; `user-global` / `workspace` layers merged per session; a store you can browse, `export`, and audit — transparency as a feature |
165
+ | **Codex** — `AGENTS.md` | per-directory scoped instructions auto-discovered and injected with zero model friction | the `workspace` layer keyed by the session cwd (Windows case-insensitive); the frozen snapshot injected automatically at session start |
166
+ | **Hermes** — `memory.md` | proactive memory saves and the security lesson that a gate enforced only in the tool layer is bypassable by late tool injection | the `memory` tool with Save/Skip guidance + approval-gated auto-capture proposals; the gate lives inside `ctx.memory`'s write methods, not in the tool layer |
167
+
168
+ Sources: [Claude Code memory](https://code.claude.com/docs/en/memory) · [Codex AGENTS.md](https://developers.openai.com/codex/cli/agents-md) · [Hermes memory](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/memory.md) · [Hermes #48181](https://github.com/NousResearch/hermes-agent/issues/48181).
169
+
170
+ And the parts deliberately refused: hidden auto-summarization into model-private state (compaction summaries here become **pending proposals** that wait for a human approve/dismiss), warehouse/vector-store ambitions, and any write that lacks a human-visible approval or audit trail. Also adopted: Hermes's documented caveat that two processes sharing one home directory write the same memory file — see Security boundaries.
171
+
172
+ ## Development
183
173
 
184
- Suggested GitHub topics: `dsh` · `dsh-plugin` · `deepseek-harness` · `memory` · `agent-memory` · `approval` · `audit` · `sqlite` · `cordis` · `llm`
174
+ ```sh
175
+ npm install # node ^22.19 || >=24
176
+ npm test # node --test: 133 tests
177
+ npm run test:conformance # dsh-memory-protocol v1 conformance suite
178
+ npm run typecheck # tsc --checkJs gate
179
+ npm run check:coverage # line-coverage gate
180
+ npm run check:readmes # five-language README consistency gate
181
+ ```
182
+
183
+ `lib/` is zero-DSH-dependency (node: builtins only); DSH imports exist only in `index.mjs`.
185
184
 
186
- ## 👥 Contributors
185
+ ## Topics
187
186
 
188
- Special thanks to [@Niuniu-Sir](https://github.com/Niuniu-Sir) for issue [#1](https://github.com/PerryLink/dsh-memento/issues/1) — the thorough boot-crash report that led to the `~/.dsh` fallback shipped in 0.3.1.
187
+ `dsh`, `dsh-plugin`, `deepseek-harness`, `memory`, `agent-memory`, `approval`, `audit`, `sqlite`, `cordis`, `llm`
189
188
 
190
- ## 📄 License
189
+ ## Contributors
191
190
 
192
- Apache License 2.0 — see [LICENSE](LICENSE). No third-party code is redistributed; see [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
191
+ - [@Niuniu-Sir](https://github.com/Niuniu-Sir) — the boot-crash report in [issue #1](https://github.com/PerryLink/dsh-memento/issues/1) that led to the `~/.dsh` fallback shipped in 0.3.1.
193
192
 
194
193
  ## PerryLink DSH Plugin Family
195
194
 
@@ -212,3 +211,7 @@ This project is one of the [15 DeepSeek Harness plugins](https://github.com/Perr
212
211
  | [dsh-github](https://github.com/PerryLink/dsh-github) | GitHub PR/issues integration for DSH, every write gated by approval |
213
212
  | [dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide) | Plugin-development knowledge base as an on-demand agent skill |
214
213
  | [dsh-claude-move](https://github.com/PerryLink/dsh-claude-move) | Migrate Claude Code sessions, memory, skills and CLAUDE.md into DSH |
214
+
215
+ ## License
216
+
217
+ [Apache License 2.0](LICENSE) © 2026 dsh-memento contributors