@hilbras/remembra 3.7.0 → 3.8.0

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/dist/types.js CHANGED
@@ -38,6 +38,12 @@ export const storeInputShape = {
38
38
  .default(3)
39
39
  .describe("1=minor, 5=critical (default 3)"),
40
40
  source: z.string().optional().describe("Originating session or client"),
41
+ confidence: z
42
+ .number()
43
+ .min(0)
44
+ .max(1)
45
+ .optional()
46
+ .describe("Trust in this claim 0..1 (default 1.0 for explicit stores, 0.7 for digests)"),
41
47
  };
42
48
  export const StoreInput = z
43
49
  .object(storeInputShape)
@@ -74,6 +80,28 @@ export const forgetInputShape = {
74
80
  id: z.string().describe("Memory id (from memory_store or memory_list)"),
75
81
  };
76
82
  export const ForgetInput = z.object(forgetInputShape);
83
+ export const getInputShape = {
84
+ id: z.string().describe("Memory id — returns the memory with related links and backlinks"),
85
+ };
86
+ export const GetInput = z.object(getInputShape);
87
+ export const relateInputShape = {
88
+ id: z.string().describe("Source memory id"),
89
+ related: z
90
+ .array(z.string().min(1))
91
+ .min(1)
92
+ .max(50)
93
+ .describe("Target memory ids to link to / unlink from"),
94
+ action: z
95
+ .enum(["add", "remove"])
96
+ .default("add")
97
+ .describe("add (default) creates links, remove deletes them"),
98
+ };
99
+ export const RelateInput = z.object(relateInputShape);
100
+ export const historyInputShape = {
101
+ id: z.string().describe("Memory id to show version history for"),
102
+ limit: z.number().int().min(1).max(100).optional().describe("Max past versions to return (newest first)"),
103
+ };
104
+ export const HistoryInput = z.object(historyInputShape);
77
105
  /** Backup file envelope (remembra export / import). */
78
106
  export const SNAPSHOT_FORMAT = "remembra-export";
79
107
  export const SnapshotInput = z.object({
@@ -94,6 +122,8 @@ export const SnapshotInput = z.object({
94
122
  lastSeen: z.string().optional(),
95
123
  archivedAt: z.string().optional(),
96
124
  provenance: z.enum(["explicit", "auto"]).optional(),
125
+ confidence: z.number().min(0).max(1).optional(),
126
+ related: z.array(z.string()).optional(),
97
127
  embedding: z.array(z.number()).optional(),
98
128
  }))
99
129
  .max(100_000),
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -3,4 +3,4 @@
3
3
  * the `/health` readiness payload, and the `remembra_info` metric.
4
4
  * package.json is kept in sync by a test (phase7).
5
5
  */
6
- export declare const VERSION = "3.7.0";
6
+ export declare const VERSION = "3.8.0";
package/dist/version.js CHANGED
@@ -3,5 +3,5 @@
3
3
  * the `/health` readiness payload, and the `remembra_info` metric.
4
4
  * package.json is kept in sync by a test (phase7).
5
5
  */
6
- export const VERSION = "3.7.0";
6
+ export const VERSION = "3.8.0";
7
7
  //# sourceMappingURL=version.js.map
@@ -21,6 +21,7 @@ How Remembra is put together, and where the extension seams are.
21
21
  ┌──────────────────────────────────┐
22
22
  │ MemoryStore (store.ts) │ Plain markdown files + frontmatter
23
23
  │ .remembra lock · crash recovery │ (no database, by decision — Q5-A)
24
+ │ history snapshots · AES-GCM at │ (encryption + history opt-in, Phase 8)
24
25
  └──────────────────────────────────┘
25
26
  ```
26
27
 
@@ -84,14 +85,20 @@ Anything it fixes is logged:
84
85
 
85
86
  All actionable failures are `RemembraError` with a stable `code`
86
87
  (`src/errors.ts`): `INVALID_INPUT`, `SNAPSHOT_INVALID`, `SCOPE_ESCAPES_ROOT`,
87
- `NOT_FOUND`, `CONFLICT`, `LOCK_TIMEOUT`, `IO_ERROR`, `LLM_ERROR`.
88
+ `NOT_FOUND`, `CONFLICT`, `LOCK_TIMEOUT`, `IO_ERROR`, `LLM_ERROR`,
89
+ `ENCRYPTED_NO_KEY`.
88
90
 
89
- - **HTTP** maps codes → statuses (400/404/409/423/500/502) and returns
91
+ - **HTTP** maps codes → statuses (400/404/409/423/500/502/503) and returns
90
92
  `{ error, code }` bodies;
91
93
  - **MCP tools** return `[CODE] message` text with `isError: true`;
92
94
  - raw filesystem failures are wrapped as `IO_ERROR`; Zod failures crossing a
93
95
  service boundary become `INVALID_INPUT`/`SNAPSHOT_INVALID` with a field
94
- summary.
96
+ summary;
97
+ - `ENCRYPTED_NO_KEY` (Phase 8) deliberately breaks the "skip unparseable
98
+ files" rule: an encrypted file without `REMEMBRA_ENCRYPT_KEY` (or with a
99
+ wrong one) is **data you must be able to read**, so it propagates —
100
+ searches fail with 503 and `/health` reports
101
+ `storage: "ENCRYPTED_NO_KEY"` instead of silently serving partial results.
95
102
 
96
103
  ## Schema versioning
97
104
 
@@ -100,6 +107,48 @@ Every memory file carries `version: <n>` in frontmatter (`SCHEMA_VERSION` in
100
107
  format: bump the constant, add a migration branch in `parse()`, and cover it
101
108
  with a fixture test.
102
109
 
110
+ ## Encryption at rest (audit Phase 8, opt-in — `src/crypto.ts`)
111
+
112
+ `REMEMBRA_ENCRYPT_KEY` (64 hex chars, a 32-byte symmetric key used directly —
113
+ no KDF for high-entropy material) flips two chokepoints in `MemoryStore`:
114
+
115
+ - **write** (`writeCached`): serialized bytes → `encryptBuffer` → atomic
116
+ rename. One random 12-byte nonce per write, AES-256-GCM.
117
+ - **read** (`parse`): bytes → `decryptBuffer` → frontmatter parse. Detection
118
+ is by the `RMBENC1` magic prefix, so **plain and encrypted files coexist**
119
+ — mixed trees read fine, cache validation stays stat-based, and history
120
+ snapshots (raw byte copies) keep whatever form they were written in.
121
+
122
+ Migration is an explicit locked operation, not a lazy rewrite:
123
+ `remembra encrypt` / `remembra decrypt` walk `global/`, `scopes/`,
124
+ `archived/` and `.history/`, convert in place under the advisory lock, and
125
+ skip files already in the target state (idempotent). Writes after enabling
126
+ the key are encrypted immediately — migration only covers what's already on
127
+ disk.
128
+
129
+ Failure semantics: `decryptBuffer` passes plain bytes through untouched;
130
+ ciphertext without/with a wrong key throws `ENCRYPTED_NO_KEY` (503). The
131
+ warn-once "skip malformed file" path explicitly re-throws `RemembraError`s —
132
+ unreadable storage must never degrade into *smaller* search results.
133
+
134
+ ## Version history (audit Phase 8 — `snapshotHistory` / `history`)
135
+
136
+ `MemoryStore.update()` is the single content-mutation chokepoint (merge
137
+ today; anything future). Before rewriting a file whose **content differs**
138
+ from what's on disk, it copies the raw pre-image to
139
+ `.history/<id>/<epochMs>-<seq>.md`:
140
+
141
+ - `epochMs-seq` names sort lexicographically = chronologically (seq breaks
142
+ same-millisecond ties; the advisory lock serializes writers);
143
+ - raw copy ⇒ encrypted files stay encrypted, plain stay plain, byte-for-byte;
144
+ - content-equality gate ⇒ embedding backfills and `memory_relate` never
145
+ create snapshots;
146
+ - pruning keeps the newest `REMEMBRA_HISTORY_LIMIT` (default 20, `0`
147
+ disables) per id;
148
+ - `.history/` is *data-adjacent but never walked by `all()`* — reads go
149
+ through the explicit `history(id)` path only (`.tmp` cleanup in crash
150
+ recovery does cover it).
151
+
103
152
  ## Parse cache (audit Phase 5: LRU + lazy loading)
104
153
 
105
154
  Every read goes through an LRU keyed by file path and **validated by
package/docs/chatgpt.md CHANGED
@@ -83,6 +83,31 @@ curl -X POST http://localhost:8787/memories/digest \
83
83
 
84
84
  Requires `REMEMBRA_LLM` + key — see [providers.md](providers.md).
85
85
 
86
+ ### Get one memory (with links)
87
+
88
+ ```bash
89
+ curl http://localhost:8787/memories/<id> \
90
+ -H "x-api-key: $REMEMBRA_API_KEY"
91
+ # → { "memory": {...}, "related": [...], "backlinks": [...] }
92
+ ```
93
+
94
+ ### Link two memories (relationship graph)
95
+
96
+ ```bash
97
+ curl -X POST http://localhost:8787/memories/<id>/relate \
98
+ -H "content-type: application/json" \
99
+ -H "x-api-key: $REMEMBRA_API_KEY" \
100
+ -d '{"related": ["<other-id>"], "action": "add"}'
101
+ ```
102
+
103
+ ### Version history with diffs
104
+
105
+ ```bash
106
+ curl "http://localhost:8787/memories/<id>/history?limit=5" \
107
+ -H "x-api-key: $REMEMBRA_API_KEY"
108
+ # → { "id": "...", "versions": [{ "content": "...", "diff": "--- ..." }, ...] }
109
+ ```
110
+
86
111
  ## 3. Create the Custom GPT
87
112
 
88
113
  1. Go to **chatgpt.com → Explore GPTs → Create a GPT**.
package/docs/clients.md CHANGED
@@ -95,6 +95,9 @@ REMEMBRA_API_KEY="your-secret" remembra --http
95
95
  | `REMEMBRA_LOCK_TIMEOUT_MS` | `5000` | Max wait for the cross-process storage lock |
96
96
  | `REMEMBRA_LOCK_STALE_MS` | `10000` | Age after which a lock with a dead/unknown pid is stolen |
97
97
  | `REMEMBRA_CACHE_SIZE` | `10000` | Parse-cache LRU capacity (entries); `0` disables caching |
98
+ | `REMEMBRA_HISTORY_LIMIT` | `20` | Max version snapshots kept per memory; `0` disables history |
99
+ | `REMEMBRA_REDACT` | *(unset)* | `1` enables PII redaction at ingest (irreversible) — see [security.md](security.md#pii-redaction-opt-in-380) |
100
+ | `REMEMBRA_ENCRYPT_KEY` | *(unset)* | 64-hex 32-byte key → AES-256-GCM at rest; run `remembra encrypt` — see [security.md](security.md#encryption-at-rest-opt-in-380) |
98
101
  | `REMEMBRA_DEBUG` | *(unset)* | `1` logs the storage root path at startup (off by default: log hygiene) |
99
102
  | `REMEMBRA_LOG` | *(auto)* | Force log format: `json` or `text`. Unset → auto: JSON when stderr is piped, text on a TTY. See [observability.md](observability.md) |
100
103
 
package/docs/lifecycle.md CHANGED
@@ -75,6 +75,12 @@ same type + scope) — the LLM is only called when two memories are plausibly
75
75
  about the same thing. If the merge LLM fails, the item is **stored fresh**
76
76
  (fail-open: extraction never loses data).
77
77
 
78
+ Since 3.8.0 a merge also snapshots the **pre-merge file** into
79
+ `.history/<id>/` first — every past version stays recoverable with
80
+ `memory_history` / `GET /memories/:id/history`, which renders a unified line
81
+ diff of old → new for each version (pruned to `REMEMBRA_HISTORY_LIMIT`,
82
+ default 20).
83
+
78
84
  ## Configuration
79
85
 
80
86
  | Variable | Default | Purpose |
@@ -88,7 +94,8 @@ about the same thing. If the merge LLM fails, the item is **stored fresh**
88
94
  ~/.remembra/
89
95
  ├── global/<id>.md # active, global
90
96
  ├── scopes/<scope>/<id>.md # active, project-scoped
91
- └── archived/
92
- ├── global/<id>.md # archived (excluded from search)
93
- └── scopes/<scope>/<id>.md
97
+ ├── archived/
98
+ ├── global/<id>.md # archived (excluded from search)
99
+ └── scopes/<scope>/<id>.md
100
+ └── .history/<id>/<epoch>-<seq>.md # superseded pre-images (3.8.0)
94
101
  ```
@@ -69,9 +69,39 @@ in `/repo/b`. Global memories are always visible.
69
69
  | `importance` | 1–5 | defaults to 3; higher ranks higher (same weight in both modes) |
70
70
  | `source` | string | originating session/client (optional) |
71
71
  | `provenance` | `explicit \| auto` | set automatically: `explicit` = stored deliberately, `auto` = digest-extracted; pre-3.4.0 files are neutral |
72
+ | `confidence` | 0–1 | trust in this claim (3.8.0): explicit stores default `1.0`, digests `0.7` (the extraction LLM may supply its own). **Displayed, not ranked** — importance answers "relevant?", confidence answers "true?"; preserved through merge/import/export |
73
+ | `related` | string[] | ids of linked memories (3.8.0) — see [Relationships](#relationships-380) |
72
74
  | `id` | 12-char id | assigned automatically (collision-safe) |
73
75
  | `createdAt` / `updatedAt` | ISO timestamps | assigned automatically |
74
76
 
77
+ ## Relationships (3.8.0)
78
+
79
+ Memories can link to each other — a directed `related: [ids]` list in
80
+ frontmatter, managed with `memory_relate`:
81
+
82
+ ```markdown
83
+ related: [7133edba, 9f2e01aa]
84
+ ```
85
+
86
+ - Edges are **stored on the source only**; backlinks are derived at read time
87
+ (`memory_get` / `GET /memories/:id` return both directions), so a link is a
88
+ single write with no consistency dance.
89
+ - Targets are validated on `add` (they must exist); self-links are rejected.
90
+ - Links do not affect ranking — retrieval is unchanged; they are structure for
91
+ the consumer to follow (decision → facts it rests on, history → decision it
92
+ records).
93
+
94
+ ## Version history (3.8.0)
95
+
96
+ Any content-changing update (today: contradiction merges) first snapshots the
97
+ on-disk pre-image into `~/.remembra/.history/<id>/<epoch>-<seq>.md` — a
98
+ byte-for-byte copy of the file as it was. `memory_history` /
99
+ `GET /memories/:id/history` return the versions newest-first, each with a
100
+ unified line diff against its predecessor. Snapshots prune to
101
+ `REMEMBRA_HISTORY_LIMIT` (default 20, `0` disables); embedding backfills and
102
+ linking never snapshot (content unchanged). History files are invisible to
103
+ `all()`/search — `.history` is never walked as data.
104
+
75
105
  ## Retrieval ranking
76
106
 
77
107
  When `memory_search` runs, memories are scored in layers:
@@ -131,7 +161,16 @@ Layout:
131
161
  $REMEMBRA_HOME/ # defaults to ~/.remembra
132
162
  ├── global/
133
163
  │ └── <id>.md
134
- └── scopes/
135
- └── <scope>/
136
- └── <id>.md
164
+ ├── scopes/
165
+ └── <scope>/
166
+ └── <id>.md
167
+ ├── archived/ # same shape, out of search (lifecycle.md)
168
+ └── .history/<id>/ # superseded pre-images (version history, 3.8.0)
137
169
  ```
170
+
171
+ > Opt-in: with `REMEMBRA_ENCRYPT_KEY` set, every file above is written as
172
+ > AES-256-GCM ciphertext instead (same names, detected by magic bytes) —
173
+ > see [security.md](security.md#encryption-at-rest-opt-in-380). With
174
+ > `REMEMBRA_REDACT=1`, PII patterns are replaced with typed placeholders
175
+ > (`<EMAIL>`, `<CARD>`, …) *before* this file is ever written — see
176
+ > [security.md](security.md#pii-redaction-opt-in-380).
@@ -25,7 +25,8 @@ Example JSON events:
25
25
 
26
26
  Event names in the wild: `http_listening`, `mcp_listening`, `search`,
27
27
  `shutdown`, `crash_recovery`, `memory_parse_skipped`, `embedding_failed`,
28
- `touch_failed`, `merge_llm_failed`, `decay_failed`.
28
+ `touch_failed`, `merge_llm_failed`, `decay_failed`, `redacted` (3.8.0 — PII
29
+ found at ingest; fields are per-kind counts, never the matched text).
29
30
 
30
31
  ## Metrics — `GET /metrics`
31
32
 
@@ -38,7 +39,7 @@ stays exempt so unauthenticated readiness probes keep working.
38
39
 
39
40
  | Series | Type | Labels | Meaning |
40
41
  |---|---|---|---|
41
- | `remembra_http_requests_total` | counter | `route`, `method`, `status` | Requests. `route` is a fixed low-cardinality label (`health`/`metrics`/`memories`/`search`/`digest`/`maintain`/`memory_item`/`other`) — never the raw path. |
42
+ | `remembra_http_requests_total` | counter | `route`, `method`, `status` | Requests. `route` is a fixed low-cardinality label (`health`/`metrics`/`memories`/`search`/`digest`/`maintain`/`memory_item`/`memory_sub`/`other`) — never the raw path. `memory_sub` = the `relate`/`history` sub-routes (3.8.0). |
42
43
  | `remembra_http_request_duration_seconds` | histogram | `route` | Request latency. |
43
44
  | `remembra_errors_total` | counter | `code`, `transport` | Classified errors (`http`/`mcp`). Codes: the [error codes](architecture.md#error-classification-audit-phase-2) plus `INVALID_INPUT`, `PAYLOAD_TOO_LARGE`, `INTERNAL`. |
44
45
  | `remembra_searches_total` | counter | — | `memory_search` invocations. |
@@ -49,6 +50,10 @@ stays exempt so unauthenticated readiness probes keep working.
49
50
  | `remembra_digest_duration_seconds` | histogram | — | Digest run latency (includes lock queueing). |
50
51
  | `remembra_cache_events_total` | counter | `result` | Parse-cache probes: `hit` / `miss`. |
51
52
  | `remembra_cache_entries` | gauge | — | Parse-cache entries currently held. |
53
+ | `remembra_redactions_total` | counter | `kind` | PII placeholders written at ingest (3.8.0): `email`/`ssn`/`card`/`phone`/`secret`. Zero (absent) unless `REMEMBRA_REDACT=1`. |
54
+ | `remembra_relate_total` | counter | `action` | `memory_relate` link writes (3.8.0): `add` / `remove` (no-op idempotent calls don't count). |
55
+ | `remembra_history_snapshots_total` | counter | — | History pre-images written (3.8.0). Growth rate ≈ content-changing updates. |
56
+ | `remembra_encryption_migrations_total` | counter | `mode` | `remembra encrypt`/`decrypt` files converted (3.8.0). |
52
57
  | `remembra_info` | gauge | `version` | Build info, always `1`. |
53
58
 
54
59
  ### Scrape config
package/docs/security.md CHANGED
@@ -61,6 +61,60 @@ Retrieved memories should be treated as **data with provenance**, not commands
61
61
  | **ID collisions** | 12-hex IDs (2⁴⁸) + existence check on store |
62
62
  | **Content-Length** | Set on every response |
63
63
  | **Metrics auth (3.7.0)** | `GET /metrics` sits *after* the API-key check — counters and latencies never leak without the key (`/health` stays exempt for readiness probes) |
64
+ | **PII redaction (3.8.0, opt-in)** | `REMEMBRA_REDACT=1` strips emails, Luhn-valid card numbers, SSNs, phone numbers and high-entropy secrets at the *ingest layer* (`memory_store`, digest items, merge output) — raw patterns never reach disk, embeddings, or export snapshots |
65
+ | **Encryption at rest (3.8.0, opt-in)** | `REMEMBRA_ENCRYPT_KEY` → AES-256-GCM per file; reading an encrypted file without the key fails **loudly** (`ENCRYPTED_NO_KEY`, HTTP 503, `/health` 503) — never warn-skipped as if the data didn't exist |
66
+
67
+ ## Encryption at rest (opt-in, 3.8.0)
68
+
69
+ Plain markdown stays the default (you can read and edit your memories —
70
+ that's the point). Setting a key flips storage to ciphertext:
71
+
72
+ ```bash
73
+ export REMEMBRA_ENCRYPT_KEY="$(node -p 'require("node:crypto").randomBytes(32).toString("hex")')"
74
+ remembra encrypt # migrate the existing tree (memories + history) in place
75
+ remembra --http # from here on, writes are AES-256-GCM
76
+ ```
77
+
78
+ | | |
79
+ |---|---|
80
+ | **Format** | `RMBENC1 │ nonce(12) │ tag(16) │ ciphertext` per file — AES-256-GCM via `node:crypto`, zero dependencies, random nonce per write, same `.md` names (detected by magic bytes) |
81
+ | **Key** | 64 hex chars (32 bytes) used directly — no KDF needed for a high-entropy symmetric key. *Not* a human passphrase |
82
+ | **Mixed trees** | Plain files stay readable while the key is set, and `remembra decrypt` reverses the migration — both directions are idempotent |
83
+ | **Fail-loud** | Encrypted file + missing/wrong key → `ENCRYPTED_NO_KEY` (HTTP 503, MCP `[ENCRYPTED_NO_KEY]`, `/health` 503). GCM auth failure makes a wrong key indistinguishable from tampering |
84
+ | **What it protects** | At-rest exfiltration: stolen backups, copied `~/.remembra`, a leaked git history of the directory |
85
+ | **What it does not** | A runtime attacker on your machine can read the env of the process holding the key — this is not a substitute for OS disk encryption & process isolation; and files stop being human-readable (decrypt first: unset the key after `remembra decrypt`) |
86
+
87
+ Export snapshots (`remembra export`) contain **decrypted** JSON — they are
88
+ protected by file permissions like any other backup.
89
+
90
+ ## PII redaction (opt-in, 3.8.0)
91
+
92
+ ```bash
93
+ export REMEMBRA_REDACT=1
94
+ ```
95
+
96
+ Everything that enters storage — `memory_store` calls, every digest-extracted
97
+ item, and merge output — runs through a pattern filter first:
98
+
99
+ | Matches | Placeholder | Guard against false positives |
100
+ |---------|-------------|------------------------------|
101
+ | Emails | `<EMAIL>` | — |
102
+ | Card numbers (13–19 digits) | `<CARD>` | must pass the **Luhn** check |
103
+ | SSNs (`123-45-6789`) | `<SSN>` | dashed format only |
104
+ | Phone numbers | `<PHONE>` | separators required, 10–15 digits — dates (`2026-09-23`, 8 digits) and versions (`3.6.0`) never match |
105
+ | Provider tokens (`sk-…`, `ghp_…`, `AKIA…`) + ≥40-char high-entropy blobs | `<SECRET>` | generic blobs must contain a digit (long English words survive) |
106
+
107
+ Properties:
108
+
109
+ - **Irreversible by design** — the original bytes are not kept anywhere;
110
+ before enabling, assume anything redacted is gone from future exports too.
111
+ - **Not a compliance control** — regex covers the common shapes; names,
112
+ addresses in free prose, and anything the patterns miss are untouched.
113
+ Treat it as belt-and-braces on top of not feeding PII to your LLM providers.
114
+ - The **extraction LLM still sees the raw transcript** (it must, to
115
+ understand it) — redaction guards what Remembra *stores*, not what your
116
+ `REMEMBRA_LLM` provider receives. Use `memory_store` (not digest) for
117
+ content you must not send to a third-party model.
64
118
 
65
119
  ## Deployment checklist
66
120
 
@@ -82,17 +136,22 @@ remembra --http
82
136
  directory)
83
137
  - [ ] Periodic `memory_list {type: "role"}` audit
84
138
  - [ ] LLM/embedding keys scoped to least privilege
139
+ - [ ] Consider `REMEMBRA_REDACT=1` before storing content derived from other
140
+ people's data (redaction is irreversible — decide once, up front)
141
+ - [ ] Consider `REMEMBRA_ENCRYPT_KEY` when the store leaves your machine
142
+ (backups, shared filesystems) — generate 32 random bytes, store the key
143
+ in your secret manager, run `remembra encrypt`
85
144
 
86
145
  ## Known non-goals (current version)
87
146
 
88
147
  - **No multi-tenancy** — one store per installation; scope isolates *projects*,
89
148
  not *users*. Never share one instance between mutually untrusting users.
90
- - **No encryption at rest** — files are plaintext markdown (by design: you can
91
- read and edit them). Use filesystem-level encryption if needed.
92
- - **No PII redaction** — what you store is what's written to disk.
93
149
  - **Single-writer assumption per store, now cross-process safe** — mutations
94
150
  take an advisory lockfile (`O_EXCL`, stale-steal, typed `LOCK_TIMEOUT`), so
95
151
  an MCP server, the `remembra maintain` CLI, and a session digest can run
96
152
  against one store concurrently on one machine. Network filesystems with
97
153
  unreliable `O_EXCL` semantics are untested; `remembra export` for backups
98
154
  across machines.
155
+ - Encryption-at-rest and PII redaction are **off by default** (both since
156
+ 3.8.0, both opt-in above) — defaults keep files human-readable and
157
+ byte-faithful to what you stored.
package/docs/tools.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Tool Reference
2
2
 
3
- Remembra exposes four MCP tools. All of them work the same way across every
3
+ Remembra exposes nine MCP tools. All of them work the same way across every
4
4
  MCP-compatible client.
5
5
 
6
6
  ## `memory_store`
@@ -15,6 +15,7 @@ Persist a memory so it survives context-window resets.
15
15
  | `tags` | string[] | no | `[]` | Keywords that boost retrieval |
16
16
  | `importance` | 1–5 | no | `3` | Ranking weight |
17
17
  | `source` | string | no | — | Originating session/client |
18
+ | `confidence` | 0–1 | no | auto | Trust in this claim — defaults to `1.0` for explicit stores, `0.7` for digest extractions (the LLM may supply its own) |
18
19
 
19
20
  **When to use which type:**
20
21
  - Something the model should *know* → `fact`
@@ -64,6 +65,50 @@ Permanently delete a memory.
64
65
 
65
66
  Returns an error result if no memory matches the id.
66
67
 
68
+ ## `memory_get`
69
+
70
+ Fetch one memory by id with its full content, its `related` links resolved,
71
+ and its **backlinks** (memories that point at it). Use after `memory_search`
72
+ when you need the whole statement, not the snippet.
73
+
74
+ | Argument | Type | Required | Description |
75
+ |----------|------|----------|-------------|
76
+ | `id` | string | ✅ | Memory id |
77
+
78
+ Returns `[NOT_FOUND] …` with `isError: true` if no memory matches.
79
+
80
+ ## `memory_relate`
81
+
82
+ Create or remove directed links between memories — the relationship graph.
83
+ Tie a decision to the facts it depends on, or a history entry to the decision
84
+ it records. Targets must exist; backlinks are derived at read time, so one
85
+ write keeps the edge consistent. See [memory-model.md](memory-model.md#relationships-380).
86
+
87
+ | Argument | Type | Required | Default | Description |
88
+ |----------|------|----------|---------|-------------|
89
+ | `id` | string | ✅ | — | Source memory id |
90
+ | `related` | string[] | ✅ | — | Target memory ids (1–50; must exist on `add`) |
91
+ | `action` | `add \| remove` | no | `add` | Create or delete the links |
92
+
93
+ Idempotent: re-linking what's already linked is a no-op (no `updatedAt` churn).
94
+ A memory cannot be related to itself (`INVALID_INPUT`).
95
+
96
+ ## `memory_history`
97
+
98
+ Version history of one memory with unified line diffs — every
99
+ content-changing update (e.g. a contradiction merge) snapshots the previous
100
+ version first. Newest version first; each entry diffs against its
101
+ predecessor. See [lifecycle.md](lifecycle.md#contradiction-merging).
102
+
103
+ | Argument | Type | Required | Description |
104
+ |----------|------|----------|-------------|
105
+ | `id` | string | ✅ | Memory id |
106
+ | `limit` | 1–100 | no | Max *past* versions to return |
107
+
108
+ Snapshots live in `~/.remembra/.history/<id>/`, pruned to
109
+ `REMEMBRA_HISTORY_LIMIT` (default 20) per memory; `0` disables history.
110
+ Non-content updates (embedding backfills, linking) never snapshot.
111
+
67
112
  ## `memory_digest`
68
113
 
69
114
  Extract memories from a conversation transcript using the configured LLM and
@@ -94,6 +139,8 @@ Returns counts + affected ids. Also available as `POST /maintain` and the
94
139
  remembra maintain # decay sweep + vector backfill (one-shot, prints JSON)
95
140
  remembra export <file>.json # full backup snapshot incl. archived memories
96
141
  remembra import <file>.json # restore; validates whole file first (atomic), idempotent
142
+ remembra encrypt # migrate the whole tree to ciphertext at rest (needs REMEMBRA_ENCRYPT_KEY)
143
+ remembra decrypt # migrate back to plain markdown (also needs the key)
97
144
  ```
98
145
 
99
146
  Import skips existing ids and exact-duplicate contents, so running it twice —
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hilbras/remembra",
3
- "version": "3.7.0",
3
+ "version": "3.8.0",
4
4
  "description": "External memory for AI assistants — remember facts, decisions, roles and history across sessions. MCP server for OpenCode, Claude Code, Cline, Kimi Code and more.",
5
5
  "type": "module",
6
6
  "bin": {