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/ARCHITECTURE.md +177 -177
- package/CHANGELOG.md +104 -92
- package/README.es.md +163 -138
- package/README.hi.md +161 -136
- package/README.md +140 -137
- package/README.pt.md +164 -139
- package/README.zh.md +159 -156
- package/client/client.js +241 -241
- package/index.mjs +1739 -1730
- package/lib/constants.mjs +68 -68
- package/lib/store.mjs +717 -717
- package/package.json +153 -147
- package/types.d.ts +237 -237
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
|
-
|
|
6
|
-
|
|
7
|
-
[](LICENSE)
|
|
10
|
+
[](https://github.com/topics/dsh-plugin)
|
|
11
|
+
[](#)
|
|
12
|
+
[](https://github.com/PerryLink/dsh-memento/actions)
|
|
13
|
+
[](https://github.com/PerryLink/dsh-memento/releases)
|
|
10
14
|
[](https://www.npmjs.com/package/dsh-memento)
|
|
11
15
|
[](https://www.npmjs.com/package/dsh-memento)
|
|
12
|
-
[](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
|
-
|
|
17
|
+
[English](README.md) · [简体中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
</div>
|
|
19
20
|
|
|
20
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
##
|
|
32
|
+
## What you get
|
|
46
33
|
|
|
47
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
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
|
-
|
|
74
|
-
dsh plugin --profile
|
|
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
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
##
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
##
|
|
139
|
+
## Permissions & data
|
|
157
140
|
|
|
158
|
-
- **
|
|
159
|
-
- **
|
|
160
|
-
- **
|
|
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
|
-
##
|
|
145
|
+
## Security boundaries
|
|
164
146
|
|
|
165
|
-
- **
|
|
166
|
-
-
|
|
167
|
-
- **
|
|
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
|
-
##
|
|
152
|
+
## Known limitations
|
|
170
153
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
`
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
185
|
+
## Topics
|
|
187
186
|
|
|
188
|
-
|
|
187
|
+
`dsh`, `dsh-plugin`, `deepseek-harness`, `memory`, `agent-memory`, `approval`, `audit`, `sqlite`, `cordis`, `llm`
|
|
189
188
|
|
|
190
|
-
##
|
|
189
|
+
## Contributors
|
|
191
190
|
|
|
192
|
-
|
|
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
|