pi-memoria 0.2.0 → 0.3.1
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/AGENTS.md +110 -0
- package/README.md +126 -166
- package/index.ts +301 -204
- package/package.json +29 -69
- package/src/aliases.ts +104 -0
- package/src/config.ts +22 -184
- package/src/database.ts +301 -0
- package/src/errors.ts +55 -0
- package/src/files.ts +29 -0
- package/src/hot-memory.ts +231 -0
- package/src/results.ts +264 -0
- package/src/sessions.ts +246 -843
- package/src/text.ts +48 -0
- package/skills/memoria/SKILL.md +0 -77
- package/skills/memoria-sessions/SKILL.md +0 -69
- package/src/commands.ts +0 -398
- package/src/frontmatter.ts +0 -318
- package/src/index-engine.ts +0 -1071
- package/src/recall.ts +0 -211
- package/src/rerank.ts +0 -85
- package/src/runtime.ts +0 -1469
- package/src/search.ts +0 -499
- package/src/similarity.ts +0 -374
- package/src/store.ts +0 -1724
- package/src/synonyms.ts +0 -105
- package/src/timeexpr.ts +0 -145
- package/src/tokenize.ts +0 -295
- package/src/tools.ts +0 -813
- package/src/types.ts +0 -541
- package/src/usage.ts +0 -188
- package/src/util.ts +0 -141
package/AGENTS.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Working on pi-memoria
|
|
2
|
+
|
|
3
|
+
This is a TypeScript Pi extension with five tools and **one global memory store**.
|
|
4
|
+
README.md documents the product; this file documents how to change and release the repository.
|
|
5
|
+
|
|
6
|
+
## North star
|
|
7
|
+
|
|
8
|
+
1. **Recall.** If it is in memory, we retrieve it. If it was said in any prior conversation, session
|
|
9
|
+
search finds it. Failing to retrieve something that exists is the only unacceptable outcome.
|
|
10
|
+
2. **Speed.** Millisecond retrieval on the common path; no query that changes how the agent works.
|
|
11
|
+
3. **No context bloat.** Only hot memory (≤ 5000 characters) is always loaded. Everything else is
|
|
12
|
+
retrieved on demand.
|
|
13
|
+
|
|
14
|
+
## Commands
|
|
15
|
+
|
|
16
|
+
- `npm ci --ignore-scripts`: install the locked development dependencies.
|
|
17
|
+
- `npm run check`: strict TypeScript checking.
|
|
18
|
+
- `npm test`: storage, concurrency, retrieval, and Pi integration tests; uses temporary directories.
|
|
19
|
+
- `npm run verify`: typecheck and tests.
|
|
20
|
+
- `npm run bench`: reproducible local retrieval measurements on synthetic data.
|
|
21
|
+
- `pi -e ./index.ts`: manually try the extension; this uses real global memory unless overridden.
|
|
22
|
+
- `npm pack --dry-run`: inspect the distributable.
|
|
23
|
+
|
|
24
|
+
## Architecture
|
|
25
|
+
|
|
26
|
+
- `index.ts`: Pi lifecycle hooks, tool schemas, guidance, and bounded tool results.
|
|
27
|
+
- `src/config.ts`: global paths and session-root configuration.
|
|
28
|
+
- `src/database.ts`: SQLite WAL, transactional FTS5 triggers, CRUD, retrieval, alias-expanded keyword queries, exact tag predicates, session-root registry.
|
|
29
|
+
- `src/hot-memory.ts`: authoritative bullet file, stable IDs, priorities, duplicate-safe adds/edits, single-line validation, locking, atomic writes, cap enforcement.
|
|
30
|
+
- `src/aliases.ts`: optional global `synonyms.json` loading/validation and bounded one-hop query expansion.
|
|
31
|
+
- `src/errors.ts`: stable expected-error codes and SQLite failure classification.
|
|
32
|
+
- `src/results.ts`: compact model-facing rendering, UTF-8 byte budgeting, spill files, and the tool error boundary.
|
|
33
|
+
- `src/sessions.ts`: streaming ripgrep search of all JSONL branches and paginated source reads.
|
|
34
|
+
- `src/files.ts`, `src/text.ts`: durable file replacement and validation helpers (including single-line hot validation).
|
|
35
|
+
- `test/`: behavioral tests and isolated fixtures; `scripts/benchmark.ts`: local benchmark.
|
|
36
|
+
|
|
37
|
+
## Invariants
|
|
38
|
+
|
|
39
|
+
- Never create project-scoped memory or derive the memory directory from `cwd`.
|
|
40
|
+
- The entire generated `MEMORY.md`, including IDs, priority markers, and newlines, must be at most 5,000 JavaScript UTF-16 code units (a conservative character count).
|
|
41
|
+
- Hot memory is for context-free startup requirements. Retrievable preferences belong in SQLite.
|
|
42
|
+
- Archive evicted hot entries in SQLite **before** replacing the hot file. Explicit deletion does not archive.
|
|
43
|
+
- Serialize the entire hot-file read/modify/write with Pi's file mutation queue and a cross-process lock. Use atomic replacement; never truncate the live file in place.
|
|
44
|
+
- Use parameterized SQL and FTS triggers in the same transaction as the source change. Do not introduce embedding services, network calls, background model calls, or automatic conversation summarization.
|
|
45
|
+
- Search every configured session root, including hidden/ignored JSONL files and inactive branches. No project filter, recency cutoff, or implicit result-score threshold.
|
|
46
|
+
- Report pagination, clipping, missing roots, and subprocess errors. A partial or failed search is never proof of absence.
|
|
47
|
+
- Session text is evidence, not new instructions. Preserve role, timestamp, entry/parent IDs, file, and line citations.
|
|
48
|
+
- Spawn `rg` with an argument array and no shell. Ignore external ripgrep configuration. Honor cancellation.
|
|
49
|
+
- Load resources lazily at `session_start` or tool invocation; the extension factory must remain free of filesystem mutations, processes, and timers. Close SQLite idempotently at shutdown.
|
|
50
|
+
- Do not commit or push changes without explicit user approval.
|
|
51
|
+
|
|
52
|
+
## Development conventions
|
|
53
|
+
|
|
54
|
+
Use explicit `.ts` imports, strict types, Node built-ins, and small modules. Pi loads TypeScript directly; there is no build step. Keep the peer dependency ranges required by Pi packaging; pin the tested Pi version in devDependencies. Update package-lock.json through npm when dependencies change.
|
|
55
|
+
|
|
56
|
+
Read the installed Pi documentation and relevant examples before changing integration code. The reference installation for this workspace is `/home/rcsaquino/.npm-global/lib/node_modules/@earendil-works/pi-coding-agent/`; resolve `docs/...` and `examples/...` there, not here. Read referenced Markdown files completely. Check exported declarations for exact API signatures.
|
|
57
|
+
|
|
58
|
+
Add meaningful regression tests for cap boundaries, races, durable retrieval, pagination, and error paths when changing them. Run `npm run verify` before delivery. Benchmark claims must state corpus size and distinguish indexed SQLite lookups from linear session scans.
|
|
59
|
+
|
|
60
|
+
## Releasing
|
|
61
|
+
|
|
62
|
+
Start a release only when the user decides to bump the version. Tags, GitHub releases, and npm versions are public and are not cleanly removable.
|
|
63
|
+
|
|
64
|
+
1. Bump `version` in `package.json`, then run `npm run verify`. A version-only bump does not change dependencies, so `package-lock.json` needs no update.
|
|
65
|
+
2. Commit as `Release X.Y.Z` and push `main`.
|
|
66
|
+
3. Create an annotated tag `vX.Y.Z` with the message `pi-memoria X.Y.Z` (the convention for `v0.2.0` and later) and push it with the commit:
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
git tag -a vX.Y.Z -m "pi-memoria X.Y.Z"
|
|
70
|
+
git push origin main vX.Y.Z
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
4. Create the GitHub release after the tag exists. Publishing the release triggers
|
|
74
|
+
`.github/workflows/npm-publish.yml`, which checks the tag against `package.json`, runs
|
|
75
|
+
`npm run verify`, and publishes to npm. `gh` is installed and authenticated as
|
|
76
|
+
`rcsaquino`:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
gh release create vX.Y.Z --title "pi-memoria X.Y.Z" --notes-file - <<'EOF'
|
|
80
|
+
...
|
|
81
|
+
EOF
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Keep notes factual: what changed, requirements, and limits. Do not restate the README.
|
|
85
|
+
|
|
86
|
+
5. Watch the workflow and confirm the registry:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
gh run list --workflow npm-publish.yml --limit 4
|
|
90
|
+
npm view pi-memoria version dist-tags
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- The workflow authenticates with npm trusted publishing (OIDC). The trusted publisher
|
|
94
|
+
on npmjs.com must name the repository `rcsaquino/pi-memoria` and the workflow file
|
|
95
|
+
`npm-publish.yml`. The package's publishing access disallows traditional tokens,
|
|
96
|
+
so OIDC is the only automated publish path.
|
|
97
|
+
- The `files` field in `package.json` controls the tarball; inspect it with
|
|
98
|
+
`npm pack --dry-run` first.
|
|
99
|
+
- The registry can accept the tarball (`HTTP 202`, "being processed") and take a few
|
|
100
|
+
minutes to expose it. Confirm with `npm view` before reporting success.
|
|
101
|
+
- Fallback only if the workflow is unavailable: `npm publish` locally. Writes require
|
|
102
|
+
2FA, so it starts the npmjs web-auth flow and needs a real terminal or pseudo-TTY to
|
|
103
|
+
open the browser; without one it fails with `EOTP`. An automation token with 2FA
|
|
104
|
+
bypass also works.
|
|
105
|
+
|
|
106
|
+
Only push tags, create releases, or publish to npm for a user-requested version bump.
|
|
107
|
+
|
|
108
|
+
## Files and data to protect
|
|
109
|
+
|
|
110
|
+
Never use the user's real `~/.pi/agent/memoria/`, sessions, settings, or credentials in tests. Never commit memory databases, MEMORY.md contents, transcripts, lockfiles from running stores, or benchmark corpora. Do not edit `node_modules/` or generated package-lock.json manually. Do not install the extension into the user's Pi settings unless requested.
|
package/README.md
CHANGED
|
@@ -1,224 +1,184 @@
|
|
|
1
|
+
<!-- prettier-ignore -->
|
|
2
|
+
<div align="center">
|
|
3
|
+
|
|
1
4
|
# pi-memoria
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
**Global memory for [Pi](https://github.com/earendil-works/pi): startup rules in `MEMORY.md`, durable facts in SQLite FTS5, and cited search across every past conversation.**
|
|
7
|
+
|
|
8
|
+
[](https://github.com/rcsaquino/pi-memoria/releases)
|
|
9
|
+
[](https://nodejs.org)
|
|
10
|
+
[](https://www.typescriptlang.org)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
|
|
13
|
+
[How it works](#how-it-works) • [Installation](#installation) • [Hot memory](#hot-memory) • [Tools](#tools) • [Configuration](#configuration) • [Performance](#performance) • [Support](#support-and-contact)
|
|
5
14
|
|
|
6
|
-
|
|
7
|
-
locally, with no database, embedding service or additional runtime dependencies.
|
|
8
|
-
The agent can also search pi's saved conversations when a detail was never saved
|
|
9
|
-
as a note.
|
|
15
|
+
</div>
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
pi-memoria gives Pi one memory shared across every project: instructions that must apply from the first message go in a capped `MEMORY.md`, everything else in SQLite with FTS5, and past conversations stay searchable through ripgrep. Five tools, local storage only. No embeddings, no network calls, no background model work.
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- **Node.js 22.19+** (uses `node:sqlite`; tested on 22.19 and 24.20).
|
|
22
|
+
- **Pi** with the current extension API (tested with 0.87.1), Node-based. Standalone/Bun builds are not validated with `node:sqlite`.
|
|
23
|
+
- **ripgrep (`rg`) on PATH** for session search.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
14
26
|
|
|
15
27
|
```sh
|
|
16
28
|
pi install npm:pi-memoria
|
|
17
29
|
```
|
|
18
30
|
|
|
19
|
-
Restart
|
|
20
|
-
No configuration is required.
|
|
31
|
+
Restart Pi or run `/reload`. To uninstall, run `pi remove npm:pi-memoria`; stored memory remains until you delete its directory.
|
|
21
32
|
|
|
22
|
-
|
|
33
|
+
<details>
|
|
34
|
+
<summary><strong>Install from a local checkout</strong></summary>
|
|
23
35
|
|
|
24
36
|
```sh
|
|
25
|
-
|
|
37
|
+
npm ci --ignore-scripts
|
|
38
|
+
pi install /absolute/path/to/pi-memoria
|
|
26
39
|
```
|
|
27
40
|
|
|
28
|
-
|
|
41
|
+
Keep the checkout in place: a local install references it directly. To try it without installing:
|
|
29
42
|
|
|
30
|
-
|
|
43
|
+
```sh
|
|
44
|
+
pi -e /absolute/path/to/pi-memoria/index.ts
|
|
45
|
+
```
|
|
31
46
|
|
|
32
|
-
|
|
47
|
+
</details>
|
|
33
48
|
|
|
34
|
-
|
|
35
|
-
Remember that I use pnpm for personal projects and prefer tabs over spaces.
|
|
36
|
-
```
|
|
49
|
+
## How it works
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
|
|
51
|
+
| Store | What belongs there | How it is retrieved |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `MEMORY.md` | Instructions that must apply before any retrieval cue appears | Loaded at startup and refreshed before every user prompt |
|
|
54
|
+
| SQLite + FTS5 | Preferences, facts, decisions, names, conventions | `memoria_search` |
|
|
55
|
+
| Original Pi JSONL sessions | What was actually said, including old branches and pre-compaction messages | `memoria_sessions`, with file and line citations |
|
|
40
56
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
57
|
+
"Start every sentence with `beep_boop`" belongs in hot memory: even a session starting with "Hello" must obey it. "The user likes apples" belongs in SQLite with tags such as `fruit` and `preferences`: a fruit recommendation supplies the retrieval cue.
|
|
58
|
+
|
|
59
|
+
The model decides what to save and when to search; nothing is extracted automatically. Before saving, it searches for related memories, keeps unchanged facts, and edits existing ones when information changes. SQLite rejects repeated identical adds; differently worded paraphrases depend on the model's judgment.
|
|
60
|
+
|
|
61
|
+
## Hot memory
|
|
62
|
+
|
|
63
|
+
```md
|
|
64
|
+
- [h_0123456789abcdef] [p=90] Start every sentence with beep_boop.
|
|
44
65
|
```
|
|
45
66
|
|
|
46
|
-
|
|
67
|
+
Priority is **0–100** (default 50). The **entire file**, including IDs and newlines, must fit in **5,000 UTF-16 code units**, checked before every write. Content is single-line; CR, LF, U+2028, and U+2029 are rejected.
|
|
47
68
|
|
|
48
|
-
|
|
49
|
-
| --- | --- |
|
|
50
|
-
| `/memoria` | Show store status and the briefing's size |
|
|
51
|
-
| `/memoria search <query>` | Search saved notes |
|
|
52
|
-
| `/memoria sessions <query>` | Search earlier conversations |
|
|
53
|
-
| `/memoria topics` | Review notes and possible duplicates |
|
|
54
|
-
| `/memoria doctor` | Check for consistency problems |
|
|
55
|
-
| `/memoria paths` | Show storage locations |
|
|
69
|
+
Duplicate adds reuse the existing bullet and consume no capacity. When space is needed, strictly lower-priority bullets are archived to SQLite first (`hot-archive`), then the file is atomically replaced; if that cannot free enough room, the write fails with the live file unchanged.
|
|
56
70
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
saves a note when something is worth keeping.
|
|
71
|
+
> [!WARNING]
|
|
72
|
+
> Prefer the tools for edits. External edits can bypass the cap until the next load, and oversized content is never injected.
|
|
60
73
|
|
|
61
|
-
##
|
|
74
|
+
## Recall
|
|
62
75
|
|
|
63
|
-
|
|
76
|
+
Keyword search cannot infer every synonym, and session search has no recency or project filter. For "remember when" questions, search sessions and cite the original entries; follow `next_offset`/`next_text_offset`, and check `warnings` and `exhausted`. A partial or failed search is never proof of absence.
|
|
64
77
|
|
|
65
|
-
|
|
66
|
-
in the system prompt. Limited to 5,000 characters by default.
|
|
67
|
-
- **Topic notes** (`library/`): people, projects, decisions and other details
|
|
68
|
-
retrieved when relevant. Facts about the same subject accumulate in one file.
|
|
69
|
-
- **Saved conversations**: read-only searches of pi's transcripts, with file and
|
|
70
|
-
line references so the agent can check the surrounding dialogue.
|
|
78
|
+
## Tools
|
|
71
79
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
| Tool | Purpose |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `memoria_add` | Save a fact to SQLite or a startup rule to hot memory |
|
|
83
|
+
| `memoria_edit` | Change content, tags, priority, or hot text by ID |
|
|
84
|
+
| `memoria_delete` | Remove a memory by ID |
|
|
85
|
+
| `memoria_search` | Search SQLite with keywords, modes, and exact tags |
|
|
86
|
+
| `memoria_sessions` | Search or read original Pi session entries with citations |
|
|
76
87
|
|
|
77
|
-
|
|
88
|
+
Tool replies are compact; oversized results spill to a private `pi-memoria-result-*` file.
|
|
78
89
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
├── library/
|
|
84
|
-
│ ├── people/
|
|
85
|
-
│ ├── projects/
|
|
86
|
-
│ └── preferences/
|
|
87
|
-
├── .index/ # rebuildable search data
|
|
88
|
-
└── .trash/ # recoverable deleted notes
|
|
90
|
+
**Add a fact:**
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{"content":"The user likes apples.","tags":["fruit","preferences"]}
|
|
89
94
|
```
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
and edit notes with a text editor; the index picks up changes automatically.
|
|
96
|
+
**Add a hot rule:**
|
|
93
97
|
|
|
94
|
-
|
|
98
|
+
```json
|
|
99
|
+
{"store":"hot","content":"Start every sentence with beep_boop.","priority":90}
|
|
100
|
+
```
|
|
95
101
|
|
|
96
|
-
|
|
97
|
-
add a project store and teach search an abbreviation:
|
|
102
|
+
**Search memories:**
|
|
98
103
|
|
|
99
104
|
```json
|
|
100
|
-
{
|
|
101
|
-
"projectRoot": ".pi/memoria-project",
|
|
102
|
-
"synonyms": { "k8s": ["kubernetes"] }
|
|
103
|
-
}
|
|
105
|
+
{"query":"k8s deploy","mode":"all","tags":["infrastructure"]}
|
|
104
106
|
```
|
|
105
107
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
**Search sessions:**
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{"query":"deadline","role":"user","after":"2025-03-04","before":"2025-03-05"}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Read a session entry:**
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{"action":"read","path":"/absolute/path/to/session.jsonl","line":42}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
- **Add:** `store` is `long_term` (default) or `hot`; SQLite accepts `tags` and `source`. Identical content is reused with `created: false`; edits are the only way to change a fact. SQLite limits: 20,000 characters, 30 tags, 2,000-character source.
|
|
121
|
+
- **Edit/delete:** pass an `id` (`m_` for SQLite, `h_` for hot) and only the fields to change. `expected_revision` or hot `expected_content` catches concurrent writes. Deletion never archives hot bullets or erases sessions.
|
|
122
|
+
- **Search:** `memoria_search` searches SQLite only; hot `h_` entries are injected from `MEMORY.md` and cannot be searched or read by this tool. `mode` is `any` (default), `all`, `phrase`, or `literal`; a miss falls back to a literal scan and reports the mode used. `tags` match exactly and case-sensitively. `expand_aliases` adds `synonyms.json` terms for `any`/`all`. Read an SQLite memory with its `m_` ID; long content paginates via `text_offset`.
|
|
123
|
+
- **Sessions:** decoded JSON is searched, including hidden, ignored, and inactive-branch files. Results carry path/line citations. `exhausted: true` means every accessible root was scanned without errors; warnings mean partial results, never absence.
|
|
124
|
+
|
|
125
|
+
## Configuration
|
|
109
126
|
|
|
110
127
|
<details>
|
|
111
|
-
<summary>
|
|
112
|
-
|
|
113
|
-
| Key | Default | Meaning |
|
|
114
|
-
|---|---:|---|
|
|
115
|
-
| `rootDir` | `"$AGENT_DIR/memoria"` | Primary store. Supports `$AGENT_DIR`, `~/`, absolute and cwd-relative paths. |
|
|
116
|
-
| `projectRoot` | `""` | Optional writable per-project store; empty disables it. |
|
|
117
|
-
| `extraRoots` | `[]` | Additional **read-only** stores to search. |
|
|
118
|
-
| `hotLimit` | `5000` | Hard cap for `MEMORY.md`, in characters. |
|
|
119
|
-
| `snippetChars` | `280` | Body excerpt length per hit. |
|
|
120
|
-
| `autoRecall` | `true` | Search the library on every user prompt. |
|
|
121
|
-
| `autoRecallLimit` | `3` | Maximum notes injected per prompt. |
|
|
122
|
-
| `autoRecallMinRatio` | `0.3` | Automatic hits must score at least this fraction of the strongest eligible hit; set to `0` to disable the relative cutoff. |
|
|
123
|
-
| `autoRecallMinScore` | `1.4` | Score floor for auto-recall. |
|
|
124
|
-
| `autoRecallMaxChars` | `2400` | Strict total character budget, including wrappers and transcript fallback. |
|
|
125
|
-
| `autoRecallLastTurns` | `1` | Previous turns folded into the recall query. |
|
|
126
|
-
| `autoRecallPriorWeight` | `0.4` | Weight of those previous turns versus the current prompt. |
|
|
127
|
-
| `bodyCacheBytes` | `8388608` | In-memory body cache budget. |
|
|
128
|
-
| `scanIntervalMs` | `2000` | Minimum interval between filesystem freshness scans. |
|
|
129
|
-
| `watcherSettleMs` | `300` | Idle delay after a file event before refreshing (coalesces bursts). |
|
|
130
|
-
| `exclude` | `[]` | Path fragments never indexed. |
|
|
131
|
-
| `defaultCategory` | `"inbox"` | Folder for notes without a category. |
|
|
132
|
-
| `topicMaxWords` | `6` | Longest topic name before falling back to the category. |
|
|
133
|
-
| `topicMaxChars` | `8000` | Largest note before facts spill into a sibling file. |
|
|
134
|
-
| `usageTracking` | `true` | Track hits/writes/last-used in `.index/usage.json`. |
|
|
135
|
-
| `lastUsedWriteIntervalMs` | `21600000` | Refresh a note's `last_used` at most this often (6 h). |
|
|
136
|
-
| `staleAfterDays` | `365` | `doctor` reports notes unused for longer. |
|
|
137
|
-
| `promoteAfterWrites` | `3` | Suggest `memoria_hot` after this many writes with priority ≥ high. |
|
|
138
|
-
| `dedupeThreshold` | `0.62` | Overlap above which two notes are reported as merge candidates. |
|
|
139
|
-
| `relatedHits` | `3` | Related notes pulled into one result. |
|
|
140
|
-
| `relatedBoost` | `0.35` | Score factor for those related notes. |
|
|
141
|
-
| `synonyms` | `{}` | Inline synonym table (merged over `synonyms.json`). |
|
|
142
|
-
| `synonymWeight` | `0.6` | Weight of synonym-expanded query terms. |
|
|
143
|
-
| `timeHints` | `true` | Parse "last week"/"yesterday" in queries into a recency window. |
|
|
144
|
-
| `searchCacheSize` | `32` | LRU entries for repeated identical searches (0 disables). |
|
|
145
|
-
| `rerank` | `false` | Let the session model reorder recall candidates. |
|
|
146
|
-
| `rerankModel` | `""` | Model id (`provider/model`); empty uses the session model. |
|
|
147
|
-
| `rerankTopK` | `12` | Candidates shown to the reranker. |
|
|
148
|
-
| `rerankTimeoutMs` | `2500` | Reranker budget before falling back to lexical order. |
|
|
149
|
-
| `indexFormat` | `"auto"` | `auto` (binary above 20k notes), `json` or `binary`. |
|
|
150
|
-
| `sessionSearch` | `true` | Search saved session transcripts at all. |
|
|
151
|
-
| `sessionRoots` | `[]` | Extra transcript roots (searched before `<agent dir>/sessions`). |
|
|
152
|
-
| `sessionFallback` | `true` | Search transcripts automatically when the library returns nothing. |
|
|
153
|
-
| `sessionScanMs` | `1500` | Wall-clock budget for an explicit transcript search (the automatic fallback uses at most 400 ms). |
|
|
154
|
-
| `sessionExcerptChars` | `400` | Context characters per transcript hit. |
|
|
155
|
-
| `sessionCacheBytes` | `33554432` | In-memory budget for parsed transcripts. |
|
|
156
|
-
| `sessionIncludeTools` | `false` | Include tool calls/results and compaction summaries by default. |
|
|
157
|
-
| `sessionRipgrep` | `true` | Use a ripgrep prefilter to skip match-free transcripts when `rg` is available; without it the slower built-in scanner runs. |
|
|
128
|
+
<summary><strong>Environment variables, aliases, and storage layout</strong></summary>
|
|
158
129
|
|
|
159
|
-
|
|
130
|
+
| Variable | Effect |
|
|
131
|
+
|---|---|
|
|
132
|
+
| `PI_CODING_AGENT_DIR` | Pi's agent directory; memoria defaults to its `memoria/` child |
|
|
133
|
+
| `PI_MEMORIA_DIR` | Override the single global memory directory |
|
|
134
|
+
| `PI_MEMORIA_SESSION_DIRS` | JSON array of additional absolute session roots |
|
|
160
135
|
|
|
161
|
-
|
|
136
|
+
The optional `synonyms.json` next to `memoria.sqlite` maps terms for `any`/`all` searches. Built-ins are `k8s`→`kubernetes`, `db`→`database`, `repo`→`repository`, and `prefs`→`preferences`. Mappings are directional and one-hop; a malformed file is ignored whole with a warning.
|
|
162
137
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
138
|
+
```text
|
|
139
|
+
~/.pi/agent/memoria/
|
|
140
|
+
├── MEMORY.md
|
|
141
|
+
├── memoria.sqlite
|
|
142
|
+
├── synonyms.json
|
|
143
|
+
└── backups/
|
|
144
|
+
```
|
|
167
145
|
|
|
168
|
-
-
|
|
169
|
-
Do not store secrets.
|
|
170
|
-
- Search is lexical (BM25 with aliases, synonyms, prefix and fuzzy matching),
|
|
171
|
-
not embedding-based. It can miss a paraphrase with no matching terms.
|
|
172
|
-
- Recall is bounded. Relevant notes can be omitted by score or context limits;
|
|
173
|
-
transcript searches report `partial` when they run out of scan budget.
|
|
174
|
-
- Reranking can reorder retrieved notes, not find notes that search missed.
|
|
175
|
-
- Deletes move notes to `.trash/`. This is recovery, not secure erasure.
|
|
176
|
-
- Writes use atomic file replacement, but separate pi processes are not
|
|
177
|
-
coordinated as concurrent writers. Keep backups.
|
|
146
|
+
The default session root is `<agent-dir>/sessions`; roots Pi uses are remembered across projects. Changing `PI_MEMORIA_DIR` selects a different store without migrating the old one, project `cwd` is never used to choose it, and no data is sent over the network.
|
|
178
147
|
|
|
179
|
-
|
|
148
|
+
</details>
|
|
180
149
|
|
|
181
|
-
|
|
182
|
-
`$PI_CODING_AGENT_DIR/memoria/`). Notes are plain markdown, so a folder copy is
|
|
183
|
-
the complete backup; `.index/` is derived and can be omitted.
|
|
150
|
+
## Performance
|
|
184
151
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
`/memoria topics` and ask the agent to consolidate the appropriate notes.
|
|
152
|
+
<details>
|
|
153
|
+
<summary><strong>Benchmark: 10,000 memories and 50,000 session entries (11.9 MB)</strong></summary>
|
|
188
154
|
|
|
189
|
-
|
|
155
|
+
| Operation | Median | p95 |
|
|
156
|
+
|---|---:|---:|
|
|
157
|
+
| Selective SQLite FTS5 lookup | 0.093 ms | 0.119 ms |
|
|
158
|
+
| Alias-expanded FTS5 lookup (`k8s` → `kubernetes`) | 0.123 ms | 0.158 ms |
|
|
159
|
+
| Exact-tag filtered FTS5 lookup (10,000 matching rows) | 6.308 ms | 7.365 ms |
|
|
160
|
+
| Literal SQLite full scan | 4.709 ms | 5.094 ms |
|
|
161
|
+
| Hot-file refresh with locking | 0.148 ms | 0.249 ms |
|
|
162
|
+
| Session match near the end of the corpus | 26.776 ms | 34.777 ms |
|
|
163
|
+
| Absent session term, complete scan | 4.325 ms | 5.172 ms |
|
|
190
164
|
|
|
191
|
-
|
|
192
|
-
covers all tools and commands, note format, scopes, session search, backup
|
|
193
|
-
semantics, briefing validation and benchmark commands. It follows the current
|
|
194
|
-
checkout, which may be ahead of the npm release.
|
|
165
|
+
`npm run bench` recreates this synthetic corpus in a temporary directory. Warm-cache medians on Linux, Node 24.20, Ryzen 5 7500F, including `rg` startup. Indexed lookups stay fast; scans grow with corpus size. Not a performance guarantee.
|
|
195
166
|
|
|
196
|
-
|
|
167
|
+
</details>
|
|
168
|
+
|
|
169
|
+
## Development
|
|
197
170
|
|
|
198
171
|
```sh
|
|
199
|
-
npm
|
|
200
|
-
npm run
|
|
201
|
-
npm test
|
|
202
|
-
npm run eval
|
|
172
|
+
npm ci --ignore-scripts
|
|
173
|
+
npm run verify
|
|
203
174
|
npm run bench
|
|
204
|
-
pi -e ./index.ts
|
|
205
175
|
```
|
|
206
176
|
|
|
207
|
-
|
|
208
|
-
[AGENTS.md](https://github.com/rcsaquino/pi-memoria/blob/main/AGENTS.md)
|
|
209
|
-
for architecture, invariants and contribution checks.
|
|
210
|
-
|
|
211
|
-
Report bugs through [GitHub Issues](https://github.com/rcsaquino/pi-memoria/issues).
|
|
212
|
-
Include your pi and Node versions, steps to reproduce, and relevant errors.
|
|
213
|
-
Remove personal memory content and credentials before sharing logs.
|
|
214
|
-
|
|
215
|
-
## Support My Work
|
|
216
|
-
|
|
217
|
-
If pi-memoria is useful to you, please consider supporting my work by
|
|
218
|
-
[buying me a coffee](https://ko-fi.com/rcsaquino). 😊
|
|
177
|
+
There is no build step: Pi loads `index.ts` directly. `src/database.ts`, `src/hot-memory.ts`, and `src/sessions.ts` own the storage layers; `index.ts` wires them to lifecycle events and the tool schemas. Tests use temporary directories, real SQLite FTS5, real `rg`, concurrent writers, and Pi's extension loader. See [AGENTS.md](AGENTS.md) for architecture and contribution rules.
|
|
219
178
|
|
|
220
|
-
|
|
179
|
+
## Support and contact
|
|
221
180
|
|
|
222
|
-
|
|
181
|
+
If pi-memoria is useful to you, you can support its development on
|
|
182
|
+
[Ko-fi](https://ko-fi.com/rcsaquino).
|
|
223
183
|
|
|
224
|
-
|
|
184
|
+
<a href='https://ko-fi.com/rcsaquino' target='_blank'><img height='72' style='border:0px;height:72px;' src='https://storage.ko-fi.com/cdn/kofi2.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
|