somtum 2.3.0 → 3.1.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/README.md +101 -852
- package/dist/agents/claude_code.d.ts +3 -0
- package/dist/agents/claude_code.d.ts.map +1 -0
- package/dist/agents/claude_code.js +112 -0
- package/dist/agents/claude_code.js.map +1 -0
- package/dist/agents/codex.d.ts +3 -0
- package/dist/agents/codex.d.ts.map +1 -0
- package/dist/agents/codex.js +173 -0
- package/dist/agents/codex.js.map +1 -0
- package/dist/agents/index.d.ts +7 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +24 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/shared.d.ts +3 -0
- package/dist/agents/shared.d.ts.map +1 -0
- package/dist/agents/shared.js +18 -0
- package/dist/agents/shared.js.map +1 -0
- package/dist/agents/types.d.ts +11 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +2 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +65 -78
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/hook.d.ts.map +1 -1
- package/dist/cli/hook.js +1 -4
- package/dist/cli/hook.js.map +1 -1
- package/dist/cli/index.js +14 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.d.ts +19 -0
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +68 -36
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/init_codex.d.ts +12 -0
- package/dist/cli/init_codex.d.ts.map +1 -0
- package/dist/cli/init_codex.js +53 -0
- package/dist/cli/init_codex.js.map +1 -0
- package/dist/cli/serve.d.ts.map +1 -1
- package/dist/cli/serve.js +2 -0
- package/dist/cli/serve.js.map +1 -1
- package/dist/cli/stats.d.ts +4 -0
- package/dist/cli/stats.d.ts.map +1 -1
- package/dist/cli/stats.js +71 -43
- package/dist/cli/stats.js.map +1 -1
- package/dist/cli/ui.d.ts +1 -1
- package/dist/cli/ui.d.ts.map +1 -1
- package/dist/cli/ui.js +1 -1
- package/dist/cli/ui.js.map +1 -1
- package/dist/core/extractor.d.ts +1 -0
- package/dist/core/extractor.d.ts.map +1 -1
- package/dist/core/extractor.js +93 -52
- package/dist/core/extractor.js.map +1 -1
- package/dist/core/ledger.d.ts +28 -0
- package/dist/core/ledger.d.ts.map +1 -0
- package/dist/core/ledger.js +43 -0
- package/dist/core/ledger.js.map +1 -0
- package/dist/core/llm_backend.d.ts +7 -0
- package/dist/core/llm_backend.d.ts.map +1 -0
- package/dist/core/llm_backend.js +44 -0
- package/dist/core/llm_backend.js.map +1 -0
- package/dist/core/memory_files.d.ts.map +1 -1
- package/dist/core/memory_files.js +2 -3
- package/dist/core/memory_files.js.map +1 -1
- package/dist/core/retriever/bm25.d.ts +1 -1
- package/dist/core/retriever/bm25.d.ts.map +1 -1
- package/dist/core/retriever/bm25.js +11 -1
- package/dist/core/retriever/bm25.js.map +1 -1
- package/dist/core/schema.d.ts +19 -4
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +10 -1
- package/dist/core/schema.js.map +1 -1
- package/dist/core/session_progress.d.ts +10 -0
- package/dist/core/session_progress.d.ts.map +1 -0
- package/dist/core/session_progress.js +39 -0
- package/dist/core/session_progress.js.map +1 -0
- package/dist/core/transcript.d.ts.map +1 -1
- package/dist/core/transcript.js +2 -108
- package/dist/core/transcript.js.map +1 -1
- package/dist/dashboard/index.html +1 -1
- package/dist/db/migrations/006_token_ledger.sql +33 -0
- package/dist/hooks/post_session.d.ts +6 -5
- package/dist/hooks/post_session.d.ts.map +1 -1
- package/dist/hooks/post_session.js +107 -57
- package/dist/hooks/post_session.js.map +1 -1
- package/dist/hooks/pre_prompt.d.ts.map +1 -1
- package/dist/hooks/pre_prompt.js +14 -1
- package/dist/hooks/pre_prompt.js.map +1 -1
- package/dist/hooks/pre_read.d.ts +16 -2
- package/dist/hooks/pre_read.d.ts.map +1 -1
- package/dist/hooks/pre_read.js +81 -26
- package/dist/hooks/pre_read.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +2 -0
- package/dist/mcp/tools.js.map +1 -1
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -1,921 +1,170 @@
|
|
|
1
|
-
<img src="./assets/logo.png" width="
|
|
1
|
+
<img src="./assets/logo.png" width="420" alt="Somtum">
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Long-term memory for Claude Code and Codex that meters every token it spends.**
|
|
4
4
|
|
|
5
|
-
[**Docs**](https://riz007.github.io/somtum/) · [**npm**](https://www.npmjs.com/package/somtum)
|
|
6
|
-
|
|
7
|
-
[](https://opensource.org/licenses/MIT)
|
|
8
5
|
[](https://www.npmjs.com/package/somtum)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
Zero-config: one `somtum init` and every session end is captured automatically. No server, no cloud account, no mandatory tuning.
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## Table of Contents
|
|
17
|
-
|
|
18
|
-
- [Why Somtum?](#why-somtum)
|
|
19
|
-
- [How it works](#how-it-works)
|
|
20
|
-
- [Requirements](#requirements)
|
|
21
|
-
- [Install](#install)
|
|
22
|
-
- [Quickstart](#quickstart)
|
|
23
|
-
- [Verifying the setup](#verifying-the-setup)
|
|
24
|
-
- [Dashboard](#dashboard)
|
|
25
|
-
- [CLI Reference](#cli-reference)
|
|
26
|
-
- [MCP Server](#mcp-server)
|
|
27
|
-
- [Storage Layout](#storage-layout)
|
|
28
|
-
- [Configuration](#configuration)
|
|
29
|
-
- [Privacy](#privacy)
|
|
30
|
-
- [Token Accounting](#token-accounting)
|
|
31
|
-
- [Performance](#performance)
|
|
32
|
-
- [Development](#development)
|
|
33
|
-
- [Troubleshooting](#troubleshooting)
|
|
34
|
-
- [License](#license)
|
|
35
|
-
|
|
36
|
-
> **v2.0.0** — Global DB (`~/.somtum/global.db`) · cross-project workspace recall · memory deduplication (`superseded_by`) · `--show-superseded` on `somtum list` · stats instrumentation fix · dashboard dark-mode redesign
|
|
37
|
-
>
|
|
38
|
-
> **v1.5.0** — Multi-page VitePress docs site · `somtum list` · `somtum reset` · `somtum forget --all` · embeddings timeout safety · config crash-resilience · `injection.max_chars` wired up · warm-start race fix · auth-error hints
|
|
39
|
-
>
|
|
40
|
-
> **v1.3.0** — Auto-inject memories on every prompt · `update` MCP tool · warm-start after compaction · false-hit detection · workspace scope · `suggest-claude-md` · stale memory detection in `doctor`
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Why Somtum?
|
|
45
|
-
|
|
46
|
-
LLM agents like Claude Code start every session with a blank slate. That leads to:
|
|
47
|
-
|
|
48
|
-
- **Repetitive context** — re-explaining the same architectural choices every session
|
|
49
|
-
- **Regressions** — Claude suggests a fix you already tried and discarded
|
|
50
|
-
- **Token waste** — reading large files just to "set the scene"
|
|
51
|
-
|
|
52
|
-
**Somtum gives Claude a long-term memory.** Once a decision is made or a bug is fixed, it's remembered across all future sessions — without bloating your context window.
|
|
53
|
-
|
|
54
|
-
### What a session looks like with Somtum
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
Without Somtum With Somtum
|
|
58
|
-
──────────────────── ──────────────────────────────────────
|
|
59
|
-
Session 1: "We use pnpm Session 1: same work
|
|
60
|
-
because of workspace
|
|
61
|
-
hoisting"
|
|
62
|
-
|
|
63
|
-
Session 2: Claude suggests Session 2: Claude already knows about
|
|
64
|
-
npm, you correct it pnpm, the auth decisions, and the
|
|
65
|
-
again bugfixes from last week
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## How it works
|
|
71
|
-
|
|
72
|
-
At the end of each Claude Code session, Somtum reads the session transcript and asks Claude Haiku to extract the parts worth keeping — decisions, bug fixes, things learned. Those observations are stored locally in SQLite. **On every subsequent prompt**, Somtum automatically retrieves the most relevant memories and injects them into context — no manual recall needed.
|
|
73
|
-
|
|
74
|
-
### Memory lifecycle
|
|
75
|
-
|
|
76
|
-
```
|
|
77
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
78
|
-
│ Claude Code Session │
|
|
79
|
-
│ │
|
|
80
|
-
│ you code · debug · review · make decisions │
|
|
81
|
-
└──────────────────────────────┬──────────────────────────────┘
|
|
82
|
-
│ SessionEnd / PreCompact
|
|
83
|
-
▼
|
|
84
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
85
|
-
│ Capture Pipeline │
|
|
86
|
-
│ │
|
|
87
|
-
│ session transcript ──► Haiku extracts observations │
|
|
88
|
-
│ │
|
|
89
|
-
│ decisions · bug fixes · learnings · commands │
|
|
90
|
-
│ │
|
|
91
|
-
│ PreCompact ─── writes warm-start file ──► next session │
|
|
92
|
-
└──────────────────────────────┬──────────────────────────────┘
|
|
93
|
-
│ persisted locally
|
|
94
|
-
▼
|
|
95
|
-
┌─────────────────────────┐
|
|
96
|
-
│ ~/.somtum/projects/ │
|
|
97
|
-
│ <project-hash>/ │
|
|
98
|
-
│ │
|
|
99
|
-
│ db.sqlite │
|
|
100
|
-
│ index.md │
|
|
101
|
-
│ memories/YYYY-MM/ │
|
|
102
|
-
└────────────┬────────────┘
|
|
103
|
-
│ every prompt (UserPromptSubmit)
|
|
104
|
-
▼
|
|
105
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
106
|
-
│ Auto-Inject Pipeline (new) │
|
|
107
|
-
│ │
|
|
108
|
-
│ 1. Prompt cache lookup (exact + fuzzy match) │
|
|
109
|
-
│ 2. BM25 recall — top-k relevant memories │
|
|
110
|
-
│ 3. Warm-start context (if session just compacted) │
|
|
111
|
-
│ │
|
|
112
|
-
│ all injected as additionalContext automatically │
|
|
113
|
-
└─────────────────────────────────────────────────────────────┘
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### What gets captured — a concrete example
|
|
117
|
-
|
|
118
|
-
You work a session debugging an auth bug and refactoring a module. At session end, Somtum extracts something like:
|
|
119
|
-
|
|
120
|
-
```json
|
|
121
|
-
[
|
|
122
|
-
{
|
|
123
|
-
"kind": "bugfix",
|
|
124
|
-
"title": "JWT refresh loop caused by missing expiry check",
|
|
125
|
-
"body": "The refresh token loop was triggered because we checked token.exp < Date.now() instead of token.exp < Date.now() / 1000. Unix timestamps are in seconds, not milliseconds.",
|
|
126
|
-
"files": ["src/auth/refresh.ts"]
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
"kind": "decision",
|
|
130
|
-
"title": "Use pnpm workspaces — npm hoisting breaks shared types",
|
|
131
|
-
"body": "Switched from npm to pnpm because npm's hoisting puts shared type packages in the wrong node_modules scope, breaking type inference across packages.",
|
|
132
|
-
"files": ["package.json", "pnpm-workspace.yaml"]
|
|
133
|
-
}
|
|
134
|
-
]
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
Next session, when you ask "why are we using pnpm?" or touch `src/auth/refresh.ts`, Claude finds these memories and already has the context.
|
|
138
|
-
|
|
139
|
-
### Architecture
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
143
|
-
│ Claude Code / Agent │
|
|
144
|
-
└──────────┬──────────────────────────────┬───────────────────┘
|
|
145
|
-
│ hooks │ MCP tools
|
|
146
|
-
▼ ▼
|
|
147
|
-
┌─────────────────────┐ ┌──────────────────────────┐
|
|
148
|
-
│ Hooks │ │ MCP Tools │
|
|
149
|
-
│ │ │ │
|
|
150
|
-
│ UserPromptSubmit ──┼─cache──▶│ cache_lookup │
|
|
151
|
-
│ ──┼─inject─▶│ recall / get │
|
|
152
|
-
│ SessionEnd ────────┼─capture▶│ remember / update │
|
|
153
|
-
│ PreCompact ────────┼─warmst─▶│ forget │
|
|
154
|
-
│ PreToolUse (Read) ─┼─gate───▶│ stats │
|
|
155
|
-
│ │ │ report_false_hit │
|
|
156
|
-
└──────────┬──────────┘ └────────────┬─────────────┘
|
|
157
|
-
│ │
|
|
158
|
-
▼ ▼
|
|
159
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
160
|
-
│ Core (TypeScript) │
|
|
161
|
-
│ │
|
|
162
|
-
│ ┌──────────────┐ ┌─────────────────┐ ┌───────────────┐ │
|
|
163
|
-
│ │ PromptCache │ │ MemoryStore │ │ Retriever │ │
|
|
164
|
-
│ │ │ │ │ │ │ │
|
|
165
|
-
│ │ exact hash │ │ observations │ │ bm25(default) │ │
|
|
166
|
-
│ │ fuzzy embed │ │ scope: project │ │ embeddings │ │
|
|
167
|
-
│ │ fingerprint │ │ global │ │ index │ │
|
|
168
|
-
│ │ false_hits │ │ workspace │ │ hybrid │ │
|
|
169
|
-
│ └──────────────┘ │ last_confirmed │ └───────────────┘ │
|
|
170
|
-
│ └─────────────────┘ │
|
|
171
|
-
└─────────────────────────────────┬───────────────────────────┘
|
|
172
|
-
│
|
|
173
|
-
▼
|
|
174
|
-
┌─────────────────────────────┐
|
|
175
|
-
│ SQLite WAL + ~/.somtum/ │
|
|
176
|
-
│ /projects/<hash>/ │
|
|
177
|
-
│ db.sqlite │
|
|
178
|
-
│ index.md │
|
|
179
|
-
│ memories/YYYY-MM/<ulid>.md│
|
|
180
|
-
│ /session/lh_<id>.json │
|
|
181
|
-
│ /warmstart/ws_<id>.json │
|
|
182
|
-
└─────────────────────────────┘
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
### Retrieval strategies
|
|
186
|
-
|
|
187
|
-
| Strategy | How it works | Best for | Cost |
|
|
188
|
-
| ---------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------- | -------------------------------- |
|
|
189
|
-
| **`bm25`** | Keyword search over title + body + tags (SQLite FTS5 — no external dependencies) | Exact terms, offline setups | Near-zero |
|
|
190
|
-
| **`embeddings`** | Semantic similarity using a 30 MB local model (bge-small-en-v1.5, runs fully in-process) | "What did we decide about auth?" style queries | ~5 ms at 10k memories |
|
|
191
|
-
| **`index`** | Sends a compact memory catalog to Haiku; the model picks relevant IDs | Paraphrased or fuzzy queries | 1 Haiku API call |
|
|
192
|
-
| **`hybrid`** | BM25 + embeddings results merged and re-ranked by Haiku | General case (best recall) | BM25 + embeddings + 1 Haiku call |
|
|
193
|
-
|
|
194
|
-
**Default is `bm25`** — works offline, no setup. Enable `hybrid` once you have embeddings downloaded.
|
|
195
|
-
|
|
196
|
-
> **Caution:** Setting `strategy=hybrid` without enabling embeddings causes a silent fallback to BM25 while paying hybrid overhead. Run `somtum doctor` — if it shows `strategy=hybrid` alongside `embeddings: disabled`, fix it:
|
|
197
|
-
>
|
|
198
|
-
> ```bash
|
|
199
|
-
> somtum config set retrieval.strategy bm25 # match what's actually running
|
|
200
|
-
> # or, to use real hybrid:
|
|
201
|
-
> somtum config set retrieval.embeddings.enabled true && somtum reindex
|
|
202
|
-
> ```
|
|
203
|
-
|
|
204
|
-
---
|
|
8
|
+
[Docs](https://riz007.github.io/somtum/) · [What it costs](https://riz007.github.io/somtum/guide/costs) · [CLI reference](https://riz007.github.io/somtum/reference/cli) · [Changelog](CHANGELOG.md)
|
|
205
9
|
|
|
206
|
-
|
|
10
|
+
Your coding agent forgets everything when a session ends or its context compacts. Somtum keeps the parts worth keeping (decisions, root causes, commands that finally worked) in a local SQLite database and hands the relevant ones back on later prompts. Claude Code and Codex share the same memory.
|
|
207
11
|
|
|
208
|
-
|
|
209
|
-
- **Claude Code** — Somtum hooks into Claude Code's `SessionEnd`, `UserPromptSubmit`, and `PreToolUse` events
|
|
210
|
-
- **`ANTHROPIC_API_KEY`** _(optional)_ — if set, Somtum uses the Anthropic API directly for extraction. If not set, Somtum falls back to the `claude` CLI that ships with Claude Code, so **no separate API key is required for Claude Code subscribers**.
|
|
12
|
+
Memory is paid for in tokens, so Somtum is built to never multiply your bill. It only sends what it hasn't sent before, skips work that can't pay off, caps everything it adds to a prompt, and writes every token it spends to a ledger you can read with `somtum stats`.
|
|
211
13
|
|
|
212
|
-
|
|
14
|
+
Named after ส้มตำ, the Thai green papaya salad: shredded fine, only what's fresh.
|
|
213
15
|
|
|
214
|
-
##
|
|
16
|
+
## Quick start
|
|
215
17
|
|
|
216
18
|
```bash
|
|
217
19
|
npm install -g somtum
|
|
20
|
+
cd your-project # the directory you launch your agent from
|
|
21
|
+
somtum init # Claude Code: capture + recall hooks, MCP server
|
|
22
|
+
somtum init --agent codex # Codex (run both if you use both)
|
|
23
|
+
somtum doctor # every line should show ✓
|
|
218
24
|
```
|
|
219
25
|
|
|
220
|
-
|
|
221
|
-
>
|
|
222
|
-
> **yarn users:** `yarn global add` is not supported in Yarn v2+ (Berry). Use npm above.
|
|
223
|
-
|
|
224
|
-
### From source
|
|
225
|
-
|
|
226
|
-
```bash
|
|
227
|
-
git clone https://github.com/riz007/somtum
|
|
228
|
-
cd somtum
|
|
229
|
-
pnpm install
|
|
230
|
-
pnpm build
|
|
231
|
-
pnpm link --global
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### Native module note
|
|
235
|
-
|
|
236
|
-
Somtum uses [`better-sqlite3`](https://github.com/WiseLibs/better-sqlite3), which contains a native C++ addon. On most platforms (macOS, Linux x64/arm64, Windows x64) a prebuilt binary is downloaded automatically. On Alpine Linux / musl or unusual architectures, the addon compiles from source — `python`, `make`, and `gcc` must be available. If the install fails with a node-gyp error, install those build tools and retry.
|
|
237
|
-
|
|
238
|
-
---
|
|
239
|
-
|
|
240
|
-
## Quickstart
|
|
241
|
-
|
|
242
|
-
### Before you begin — pick your setup
|
|
243
|
-
|
|
244
|
-
**Using Claude Code (subscription)?**
|
|
245
|
-
You do not need an API key. Somtum calls the `claude` CLI that ships with Claude Code.
|
|
246
|
-
Confirm it is installed: `which claude`
|
|
247
|
-
If nothing prints, reinstall Claude Code or add its binary to your PATH.
|
|
248
|
-
|
|
249
|
-
**Using the Anthropic API directly?**
|
|
250
|
-
Add your key to your shell profile (not just the current terminal tab):
|
|
26
|
+
Then use your agent as usual. Memories appear after your first substantial session ends or compacts:
|
|
251
27
|
|
|
252
28
|
```bash
|
|
253
|
-
#
|
|
254
|
-
|
|
255
|
-
source ~/.zshrc
|
|
29
|
+
somtum list # what was remembered
|
|
30
|
+
somtum stats # what it cost
|
|
256
31
|
```
|
|
257
32
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
---
|
|
261
|
-
|
|
262
|
-
### Step 1 — Choose your extraction backend
|
|
263
|
-
|
|
264
|
-
Somtum needs to call a Claude model at session end to extract observations. Pick one:
|
|
265
|
-
|
|
266
|
-
**Option A: Claude Code subscription (no extra setup)**
|
|
33
|
+
Requires Node 20+ and one way to run a small model for extraction. Somtum uses the first one it finds: `ANTHROPIC_API_KEY` (or an Anthropic-compatible provider through `ANTHROPIC_AUTH_TOKEN` + `ANTHROPIC_BASE_URL`), then the `claude` CLI, then the `codex` CLI. If you can run your agent, you already have one.
|
|
267
34
|
|
|
268
|
-
|
|
35
|
+
## What it does
|
|
269
36
|
|
|
270
|
-
**
|
|
37
|
+
**Captures.** When a session ends or compacts, Somtum sends the turns it hasn't seen yet to a small model (Claude Haiku by default) and stores what comes back as short typed records:
|
|
271
38
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"kind": "bugfix",
|
|
42
|
+
"title": "JWT refresh loop: exp is in seconds, not ms",
|
|
43
|
+
"body": "Compared token.exp against Date.now(); must divide by 1000.",
|
|
44
|
+
"files": ["src/auth/refresh.ts"]
|
|
45
|
+
}
|
|
276
46
|
```
|
|
277
47
|
|
|
278
|
-
|
|
48
|
+
**Recalls.** On each prompt, a local keyword search (SQLite FTS5, no network) picks up to 3 relevant memories and adds them to the agent's context, capped at 1,500 characters. Nothing is added when nothing matches, and a memory that's already in the session's context isn't added again.
|
|
279
49
|
|
|
280
|
-
|
|
281
|
-
source ~/.zshrc
|
|
282
|
-
```
|
|
50
|
+
**Shares.** Claude Code and Codex read and write one memory per project. Any MCP client can use the `recall` and `remember` tools. Memories saved with `scope: "global"` follow you into every project.
|
|
283
51
|
|
|
284
|
-
|
|
52
|
+
Everything is stored under `~/.somtum/`. Data leaves your machine only in model calls through the backend you chose: extraction, plus file summaries if you turn on file gating.
|
|
285
53
|
|
|
286
|
-
|
|
54
|
+
## What it costs
|
|
287
55
|
|
|
288
|
-
|
|
56
|
+
Somtum spends tokens in two places: on extraction, and on the context it adds to your prompts. Both are bounded, and both are metered.
|
|
289
57
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
58
|
+
| Cost | When | Bound | Turn it down |
|
|
59
|
+
| --- | --- | --- | --- |
|
|
60
|
+
| Extraction | Session end or compaction | Only turns not yet extracted, at most 60k tokens. No call when fewer than 500 new tokens. | `extraction.min_new_tokens`, `extraction.max_observations_per_session` |
|
|
61
|
+
| Injected memories | A prompt that matches stored memories | Up to 3 memories, 1,500 characters (about 375 tokens). A memory already in context is not re-sent. | `injection.k`, `injection.max_chars`, `injection.enabled` |
|
|
62
|
+
| File summaries | Only if you enable file gating | One small-model call per large file that changed | `file_gating.enabled` (off by default) |
|
|
293
63
|
|
|
294
|
-
|
|
64
|
+
`somtum stats` reads the ledger. This is real output:
|
|
295
65
|
|
|
296
|
-
```bash
|
|
297
|
-
somtum init --all
|
|
298
|
-
# Installs:
|
|
299
|
-
# - SessionEnd capture hook (memory extraction)
|
|
300
|
-
# - UserPromptSubmit cache hook (prompt cache lookup)
|
|
301
|
-
# - PreToolUse file-gating hook (large file summarization)
|
|
302
|
-
# - MCP server in .mcp.json (Claude can call recall/remember tools)
|
|
303
66
|
```
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
```bash
|
|
310
|
-
somtum doctor
|
|
67
|
+
Somtum's own token use, metered (all time)
|
|
68
|
+
extraction 4 calls 54,785 tok 1 skipped
|
|
69
|
+
injected context 14 prompts 4,060 tok added to your agent's input
|
|
70
|
+
total 58,845 tok
|
|
311
71
|
```
|
|
312
72
|
|
|
313
|
-
|
|
73
|
+
Use `somtum stats --since 7d` for a window, or `--json` to feed it into something else. Extraction runs on whatever backend you configured. On the `claude` or `codex` CLI, it draws on your existing plan rather than a separate bill.
|
|
314
74
|
|
|
315
|
-
|
|
316
|
-
- **`hooks_installed`** — confirms the SessionEnd hook is registered
|
|
75
|
+
### Measured: not paying twice for the same transcript
|
|
317
76
|
|
|
318
|
-
|
|
77
|
+
Through v3.0, a session that compacted and then ended was extracted twice, and the second call re-sent everything the first had already processed. Somtum now keeps a per-session cursor and sends only new turns. These numbers come from replaying three real Claude Code sessions through the pipeline with a stub model, each compacting once at 60% of its length. Tokens are counted over the exact extraction requests, using the same tokenizer approximation `somtum stats` uses:
|
|
319
78
|
|
|
320
|
-
|
|
79
|
+
| Session | Turns | v3.0 extraction tokens | v3.1 extraction tokens | Saved |
|
|
80
|
+
| --- | ---: | ---: | ---: | ---: |
|
|
81
|
+
| Web app redesign | 309 | 64,577 | 41,756 | 35% |
|
|
82
|
+
| API service | 36 | 47,892 | 25,498 | 47% |
|
|
83
|
+
| Course assignment | 132 | 21,966 | 13,029 | 41% |
|
|
321
84
|
|
|
322
|
-
|
|
85
|
+
### What Somtum cannot measure
|
|
323
86
|
|
|
324
|
-
|
|
87
|
+
The tokens you save because the agent already knew something (the npm-vs-pnpm argument you didn't have again) never show up in any transcript, so Somtum can't count them. `somtum stats` shows a heuristic estimate for this and labels it as one. Somtum also only sees what's in transcripts: model calls your agent makes that never appear there are invisible to it. For whole-agent spend, use your agent's own usage reporting, such as Claude Code's OpenTelemetry export.
|
|
325
88
|
|
|
326
|
-
|
|
327
|
-
# How many observations were captured?
|
|
328
|
-
somtum stats
|
|
329
|
-
|
|
330
|
-
# Search memory
|
|
331
|
-
somtum search "auth jwt rotation"
|
|
332
|
-
somtum search "why we use pnpm" --strategy hybrid
|
|
333
|
-
|
|
334
|
-
# Open the visual dashboard
|
|
335
|
-
somtum serve
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
If `somtum stats` shows `memories 0` after a session, see [Troubleshooting](#troubleshooting).
|
|
339
|
-
|
|
340
|
-
---
|
|
341
|
-
|
|
342
|
-
## Verifying the setup
|
|
89
|
+
## File gating (opt-in)
|
|
343
90
|
|
|
344
|
-
|
|
91
|
+
With file gating on, the first time the agent tries to read a whole large file in a session, Somtum answers with a summary of it, generated earlier, as long as the file hasn't changed since. If the agent needs the actual contents, it reads the file again and that read goes through. Partial reads (with an offset or limit) are never gated.
|
|
345
92
|
|
|
346
|
-
|
|
93
|
+
Whether this saves anything depends on how often a summary is enough, so it's metered on both sides. `somtum stats` shows full reads avoided, summary tokens shown, and files read anyway, plus the net. After 10 gated reads, `somtum doctor` tells you to turn it off if the net is negative.
|
|
347
94
|
|
|
348
95
|
```bash
|
|
349
|
-
|
|
96
|
+
somtum init --file-gating # installs the hook and turns it on for this project
|
|
350
97
|
```
|
|
351
98
|
|
|
352
|
-
|
|
99
|
+
Claude Code only.
|
|
353
100
|
|
|
354
|
-
|
|
355
|
-
2026-04-30T10:15:42.123Z [post_session] starting
|
|
356
|
-
2026-04-30T10:15:44.891Z [post_session] ok — inserted=4 superseded=1 cache=2 summaries=1
|
|
357
|
-
```
|
|
101
|
+
## Everyday commands
|
|
358
102
|
|
|
359
|
-
|
|
103
|
+
| Command | What it does |
|
|
104
|
+
| --- | --- |
|
|
105
|
+
| `somtum doctor` | Checks setup: backend, hooks, database, and whether file gating pays off |
|
|
106
|
+
| `somtum stats` | Metered token use, memory counts, cache stats |
|
|
107
|
+
| `somtum list` / `somtum search <query>` | Browse or search memories |
|
|
108
|
+
| `somtum show <id>` / `somtum edit <id>` / `somtum forget <id>` | Read, fix or delete one memory |
|
|
109
|
+
| `somtum serve` | Local dashboard: memory browser, graph, analytics |
|
|
110
|
+
| `somtum suggest-claude-md` | Suggest `CLAUDE.md` additions from your memories |
|
|
111
|
+
| `somtum export` / `somtum import` | Move memories as JSON, JSONL or Markdown |
|
|
360
112
|
|
|
361
|
-
|
|
362
|
-
2026-04-30T10:15:42.123Z [post_session] starting
|
|
363
|
-
2026-04-30T10:15:42.124Z [post_session] ANTHROPIC_API_KEY not set — will use claude CLI fallback
|
|
364
|
-
2026-04-30T10:15:44.891Z [post_session] ok — inserted=4 superseded=1 cache=2 summaries=1
|
|
365
|
-
```
|
|
113
|
+
Full list: [CLI reference](https://riz007.github.io/somtum/reference/cli). Settings: [configuration](https://riz007.github.io/somtum/reference/configuration).
|
|
366
114
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
```
|
|
370
|
-
2026-04-30T10:15:42.123Z [post_session] ERROR: Neither ANTHROPIC_API_KEY nor the claude CLI is available.
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
**2. Check stats**
|
|
374
|
-
|
|
375
|
-
```bash
|
|
376
|
-
somtum stats
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
You should see `memories > 0` after a substantive session. Short or trivial sessions (no decisions, no bug fixes) correctly return 0 — the extractor only keeps durable observations.
|
|
380
|
-
|
|
381
|
-
**3. Run doctor**
|
|
382
|
-
|
|
383
|
-
```bash
|
|
384
|
-
somtum doctor
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
All checks should show `✓`. The `api_key` and `hooks_installed` checks are the two most commonly failing.
|
|
388
|
-
|
|
389
|
-
---
|
|
390
|
-
|
|
391
|
-
## Dashboard
|
|
392
|
-
|
|
393
|
-
```bash
|
|
394
|
-
somtum serve
|
|
395
|
-
# Opens http://localhost:3000
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
The dashboard has four views:
|
|
399
|
-
|
|
400
|
-
- **Memory browser** — searchable, filterable list of all captured observations. Switch between BM25, hybrid, and embeddings strategies live. Click any memory to see its full body, files, and tags.
|
|
401
|
-
- **Knowledge graph** — nodes are memories, edges connect memories that share files or tags. Click a node to open it in the detail panel.
|
|
402
|
-
- **Analytics** — kind breakdown, cache hit rate, retrieval strategy usage, top-referenced files.
|
|
403
|
-
- **Forget button** — soft-delete any memory directly from the browser.
|
|
404
|
-
|
|
405
|
-
| Flag | Default | Description |
|
|
406
|
-
| ------------ | ------- | ---------------------------------------- |
|
|
407
|
-
| `--port <n>` | 3000 | Listen on a custom port |
|
|
408
|
-
| `--no-open` | — | Start server without opening the browser |
|
|
409
|
-
|
|
410
|
-
Press `Ctrl-C` to stop.
|
|
411
|
-
|
|
412
|
-
---
|
|
413
|
-
|
|
414
|
-
## CLI Reference
|
|
415
|
-
|
|
416
|
-
### Setup
|
|
417
|
-
|
|
418
|
-
| Command | Description |
|
|
419
|
-
| --------------------------- | ------------------------------------------------------------ |
|
|
420
|
-
| `somtum init` | Install the SessionEnd capture hook |
|
|
421
|
-
| `somtum init --cache` | Also install the UserPromptSubmit cache + auto-inject hook |
|
|
422
|
-
| `somtum init --file-gating` | Also install the PreToolUse file-gating hook |
|
|
423
|
-
| `somtum init --all` | Install all hooks + MCP server |
|
|
424
|
-
| `somtum init --force` | Reinstall even if hooks already present |
|
|
425
|
-
| `somtum doctor` | Check DB health, migrations, hooks, API key, breakeven ratio, stale memories |
|
|
426
|
-
|
|
427
|
-
### Memory
|
|
428
|
-
|
|
429
|
-
| Command | Description |
|
|
430
|
-
| -------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
431
|
-
| `somtum list` | List stored memories (most recent first, superseded hidden by default) |
|
|
432
|
-
| `somtum list --kind decision` | Filter by kind: `decision \| learning \| bugfix \| command \| file_summary` |
|
|
433
|
-
| `somtum list --limit 20` | Limit to 20 results |
|
|
434
|
-
| `somtum list --json` | Machine-readable JSON output |
|
|
435
|
-
| `somtum list --show-superseded` | Include memories that have been superseded by a newer duplicate |
|
|
436
|
-
| `somtum search <query>` | Search observations (default: `bm25` strategy) |
|
|
437
|
-
| `somtum search <query> --strategy hybrid` | Force a specific retrieval strategy |
|
|
438
|
-
| `somtum search <query> -k 16` | Return more results |
|
|
439
|
-
| `somtum show <id>` | Print the full body of an observation |
|
|
440
|
-
| `somtum remember` | Manually store an observation |
|
|
441
|
-
| `somtum forget <id>` | Soft-delete an observation by id |
|
|
442
|
-
| `somtum forget --all` | Soft-delete **all** observations in the current project |
|
|
443
|
-
| `somtum edit <id>` | Open an observation body in `$EDITOR` |
|
|
444
|
-
| `somtum rebuild` | Regenerate `index.md` from all observations |
|
|
445
|
-
| `somtum reindex` | Recompute embeddings (after enabling embeddings or changing model) |
|
|
446
|
-
| `somtum suggest-claude-md` | Suggest CLAUDE.md additions from accumulated observations (interactive) |
|
|
447
|
-
| `somtum suggest-claude-md --dry-run` | Preview suggestions without writing |
|
|
448
|
-
| `somtum suggest-claude-md --yes --limit 20` | Auto-confirm, limit to top 20 by tokens saved |
|
|
449
|
-
|
|
450
|
-
### Stats & Visibility
|
|
451
|
-
|
|
452
|
-
| Command | Description |
|
|
453
|
-
| ------------------------- | ------------------------------------------------- |
|
|
454
|
-
| `somtum stats` | Tokens saved, cache hit rate, retrieval breakdown |
|
|
455
|
-
| `somtum stats --json` | Machine-readable JSON output |
|
|
456
|
-
| `somtum serve` | Open the visual dashboard in the browser |
|
|
457
|
-
| `somtum serve --port <n>` | Use a custom port (default 3000) |
|
|
458
|
-
| `somtum serve --no-open` | Start server without opening the browser |
|
|
459
|
-
|
|
460
|
-
### Data Management
|
|
461
|
-
|
|
462
|
-
| Command | Description |
|
|
463
|
-
| ------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
464
|
-
| `somtum export` | Export observations to stdout as JSON |
|
|
465
|
-
| `somtum export --format jsonl --output obs.jsonl` | Export as JSONL file |
|
|
466
|
-
| `somtum export --format markdown` | Export as readable Markdown |
|
|
467
|
-
| `somtum export --include-deleted` | Include soft-deleted entries |
|
|
468
|
-
| `somtum import <file>` | Import observations from JSON or JSONL |
|
|
469
|
-
| `somtum purge --older-than 30d` | Hard-delete soft-deleted entries older than 30 days |
|
|
470
|
-
| `somtum purge --older-than 30d --dry-run` | Preview without deleting |
|
|
471
|
-
| `somtum reset` | **Permanently** wipe all memories for the current project (asks to confirm) |
|
|
472
|
-
| `somtum reset --yes` | Skip confirmation (useful in CI or scripts) |
|
|
473
|
-
|
|
474
|
-
### Configuration
|
|
475
|
-
|
|
476
|
-
| Command | Description |
|
|
477
|
-
| -------------------------------------------------------------- | --------------------------------- |
|
|
478
|
-
| `somtum config get` | Print the full resolved config |
|
|
479
|
-
| `somtum config get retrieval.strategy` | Read a single key (dot-separated) |
|
|
480
|
-
| `somtum config set retrieval.strategy hybrid` | Write to `.somtum/config.json` |
|
|
481
|
-
| `somtum config set retrieval.embeddings.enabled true --global` | Write to `~/.somtum/config.json` |
|
|
482
|
-
|
|
483
|
-
### Sync
|
|
484
|
-
|
|
485
|
-
| Command | Description |
|
|
486
|
-
| -------------------- | ----------------------------------------- |
|
|
487
|
-
| `somtum sync status` | Compare local vs remote observation count |
|
|
488
|
-
| `somtum sync push` | Export and scp observations to remote |
|
|
489
|
-
| `somtum sync pull` | scp from remote and merge into local DB |
|
|
490
|
-
|
|
491
|
-
Set your remote: `somtum config set sync.remote "user@host:/path/.somtum/projects/<id>"`
|
|
492
|
-
|
|
493
|
-
Somtum uses hostname-aware syncing — merging observations from multiple machines without data loss.
|
|
494
|
-
|
|
495
|
-
---
|
|
496
|
-
|
|
497
|
-
## MCP Server
|
|
498
|
-
|
|
499
|
-
When you run `somtum init --all`, Somtum registers an MCP server that Claude can call autonomously during a session:
|
|
500
|
-
|
|
501
|
-
| Tool | What Claude does with it |
|
|
502
|
-
| ------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
503
|
-
| `recall` | Searches memories when unsure about a project detail. Merges project + global DB results. Accepts `strategy` |
|
|
504
|
-
| `get` | Retrieves full observation bodies by ID. Checks global DB if not found in project DB. Bumps `last_confirmed_at` |
|
|
505
|
-
| `remember` | Stores an observation manually. `scope='global'` routes to `~/.somtum/global.db`; returns `stored_in` field |
|
|
506
|
-
| `update` | Updates an existing observation's title, body, tags, or files. Redaction applied |
|
|
507
|
-
| `cache_lookup` | Checks the prompt cache directly |
|
|
508
|
-
| `report_false_hit` | Reports that a cached response didn't answer the question (tunes fuzzy threshold data) |
|
|
509
|
-
| `forget` | Soft-deletes an observation |
|
|
510
|
-
| `stats` | Reports tokens saved, cache hit rate, false-hit count, corpus size, and `global_memories` count |
|
|
511
|
-
|
|
512
|
-
Every MCP response includes a `tokens` field so Claude can account for retrieval cost.
|
|
513
|
-
|
|
514
|
-
### Memory scope
|
|
515
|
-
|
|
516
|
-
Observations now carry a `scope` field:
|
|
517
|
-
|
|
518
|
-
| Scope | Meaning | Use it when |
|
|
519
|
-
| ----------- | --------------------------------------------------------------- | ---------------------------------------------------- |
|
|
520
|
-
| `project` | Default. Visible only in this project. | Most decisions, bugfixes, and learnings. |
|
|
521
|
-
| `workspace` | Shared across projects via the `recall` MCP tool. | Team conventions, preferred libraries, global rules. |
|
|
522
|
-
| `global` | Same as workspace; reserved for personal preferences that span all your projects. | Your personal coding preferences. |
|
|
523
|
-
|
|
524
|
-
```
|
|
525
|
-
# Store a workspace-scoped observation from within a session:
|
|
526
|
-
remember("Always use pnpm for Node projects", body="...", scope="workspace")
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
---
|
|
530
|
-
|
|
531
|
-
## Storage Layout
|
|
115
|
+
## How it works
|
|
532
116
|
|
|
533
117
|
```
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
│
|
|
539
|
-
|
|
540
|
-
│
|
|
541
|
-
│
|
|
542
|
-
|
|
543
|
-
│
|
|
544
|
-
│ timestamped so concurrent windows don't clobber each other
|
|
545
|
-
└── projects/
|
|
546
|
-
└── <project_id>/
|
|
547
|
-
├── db.sqlite ← source of truth (SQLite WAL)
|
|
548
|
-
├── index.md ← human-readable mirror (regenerated)
|
|
549
|
-
└── memories/
|
|
550
|
-
└── YYYY-MM/
|
|
551
|
-
└── <ulid>.md ← per-observation markdown files
|
|
118
|
+
Claude Code / Codex
|
|
119
|
+
│ SessionEnd, PreCompact ─────► extract new turns ─► small model ─► observations
|
|
120
|
+
│ │
|
|
121
|
+
│ UserPromptSubmit ◄───── top memories (FTS5/BM25, local) ◄──────┤
|
|
122
|
+
│ │
|
|
123
|
+
│ PreToolUse Read (opt-in) ◄───── file summary instead of full read ◄────┤
|
|
124
|
+
│ ▼
|
|
125
|
+
│ MCP: recall · remember · get · update · forget · stats ~/.somtum/projects/<id>/db.sqlite
|
|
126
|
+
│ ~/.somtum/global.db
|
|
127
|
+
│ token ledger (every event above)
|
|
552
128
|
```
|
|
553
129
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
SQLite is the source of truth. Edit observations with `somtum edit <id>`, not by hand.
|
|
557
|
-
|
|
558
|
-
---
|
|
130
|
+
Details, including retrieval strategies, deduplication and warm starts after compaction: [How it works](https://riz007.github.io/somtum/guide/how-it-works).
|
|
559
131
|
|
|
560
|
-
##
|
|
132
|
+
## Upgrading from 3.0
|
|
561
133
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
```bash
|
|
567
|
-
# Enable semantic (embedding-based) search — downloads a 30 MB model once
|
|
568
|
-
somtum config set retrieval.embeddings.enabled true
|
|
569
|
-
somtum reindex
|
|
570
|
-
|
|
571
|
-
# Switch to hybrid retrieval (BM25 + embeddings + rerank) for best recall
|
|
572
|
-
somtum config set retrieval.strategy hybrid
|
|
573
|
-
|
|
574
|
-
# Use LLM-based retrieval (no embeddings required, costs one Haiku call per query)
|
|
575
|
-
somtum config set retrieval.index.enabled true
|
|
576
|
-
somtum config set retrieval.strategy index
|
|
577
|
-
|
|
578
|
-
# Disable file-gating (on by default — intercepts large file reads and serves cached summary)
|
|
579
|
-
somtum config set file_gating.enabled false
|
|
580
|
-
|
|
581
|
-
# Limit observations extracted per session (default: 10)
|
|
582
|
-
somtum config set extraction.max_observations_per_session 5
|
|
583
|
-
|
|
584
|
-
# Control automatic memory injection on every prompt (default: on)
|
|
585
|
-
somtum config set injection.enabled false # turn off auto-inject
|
|
586
|
-
somtum config set injection.k 5 # inject more memories (default: 3)
|
|
587
|
-
somtum config set injection.max_chars 3000 # raise injection size cap (default: 1500)
|
|
588
|
-
```
|
|
589
|
-
|
|
590
|
-
### Full config reference
|
|
591
|
-
|
|
592
|
-
```jsonc
|
|
593
|
-
{
|
|
594
|
-
"extraction": {
|
|
595
|
-
"model": "claude-haiku-4-5-20251001",
|
|
596
|
-
"trigger": ["SessionEnd", "PreCompact"],
|
|
597
|
-
"max_observations_per_session": 10,
|
|
598
|
-
},
|
|
599
|
-
"cache": {
|
|
600
|
-
"enabled": true,
|
|
601
|
-
"fuzzy_match": true,
|
|
602
|
-
"fuzzy_threshold": 0.92, // raise to 0.95 once you have false-hit signal
|
|
603
|
-
"max_entries": 10000,
|
|
604
|
-
"ttl_days": 90,
|
|
605
|
-
},
|
|
606
|
-
"retrieval": {
|
|
607
|
-
"strategy": "bm25", // bm25 | embeddings | index | hybrid
|
|
608
|
-
"k": 8,
|
|
609
|
-
"rerank_model": "claude-haiku-4-5-20251001",
|
|
610
|
-
"bm25": { "enabled": true },
|
|
611
|
-
"embeddings": {
|
|
612
|
-
"enabled": false, // set true to download the 30 MB ONNX model
|
|
613
|
-
"model": "Xenova/bge-small-en-v1.5",
|
|
614
|
-
},
|
|
615
|
-
"index": {
|
|
616
|
-
"enabled": false, // set true to use Haiku as the retriever
|
|
617
|
-
"model": "claude-haiku-4-5-20251001",
|
|
618
|
-
},
|
|
619
|
-
},
|
|
620
|
-
// Auto-inject: BM25-retrieved memories prepended to every UserPromptSubmit.
|
|
621
|
-
// Uses the hot path (< 2 ms at 1k memories). Disable if you prefer pull-only.
|
|
622
|
-
"injection": {
|
|
623
|
-
"enabled": true,
|
|
624
|
-
"k": 3, // max memories injected per prompt
|
|
625
|
-
"max_chars": 1500, // hard cap on injected text
|
|
626
|
-
"min_relevance_score": 0, // raise (e.g. 1.0) to only inject high-scoring matches
|
|
627
|
-
"show_budget": true, // prepend "[somtum] injected N/M memories (~X tokens)" line
|
|
628
|
-
},
|
|
629
|
-
"file_gating": {
|
|
630
|
-
"enabled": true, // intercepts large file reads; serves cached summary instead
|
|
631
|
-
"min_file_size_tokens": 300,
|
|
632
|
-
"exclude_globs": ["**/*.env", "**/secrets/**"],
|
|
633
|
-
},
|
|
634
|
-
"privacy": {
|
|
635
|
-
"telemetry": false,
|
|
636
|
-
"redact_patterns": [
|
|
637
|
-
"api[_-]?key\\s*[:=]\\s*[\"']?[A-Za-z0-9_\\-]{8,}[\"']?",
|
|
638
|
-
"bearer\\s+[A-Za-z0-9_\\-.]+",
|
|
639
|
-
"sk-[A-Za-z0-9_\\-]{20,}",
|
|
640
|
-
"xox[baprs]-[A-Za-z0-9-]{10,}",
|
|
641
|
-
"AKIA[0-9A-Z]{16}",
|
|
642
|
-
],
|
|
643
|
-
},
|
|
644
|
-
"sync": {
|
|
645
|
-
"enabled": false,
|
|
646
|
-
"backend": "ssh",
|
|
647
|
-
"remote": null, // e.g. "user@host:/home/user/.somtum/projects/<id>"
|
|
648
|
-
},
|
|
649
|
-
}
|
|
650
|
-
```
|
|
651
|
-
|
|
652
|
-
---
|
|
134
|
+
- `somtum init` now installs the recall hook by default, matching Codex. `--all` is no longer needed; use `--no-cache` for capture only.
|
|
135
|
+
- File gating is now **off by default**. In 3.0 it was on, and it generated file summaries at every session end even in projects that never installed its hook. If you used it, `somtum doctor` will say so: run `somtum init --file-gating --force` to turn it back on and update the hook to match `Read` only.
|
|
136
|
+
- File gating now answers a whole-file read with the summary *instead* of the file. In 3.0 it added the summary *on top of* the full read, so it could only cost tokens.
|
|
137
|
+
- `somtum stats` leads with metered numbers. The old `breakeven` ratio divided an estimate by an undercount, so it was removed from the human-readable output and from `doctor`. The JSON fields are unchanged.
|
|
653
138
|
|
|
654
139
|
## Privacy
|
|
655
140
|
|
|
656
|
-
-
|
|
657
|
-
-
|
|
658
|
-
-
|
|
659
|
-
-
|
|
660
|
-
- **Soft delete by default.** `somtum forget <id>` marks observations deleted. `somtum purge --older-than 30d` permanently removes them.
|
|
661
|
-
|
|
662
|
-
---
|
|
663
|
-
|
|
664
|
-
## Token Accounting
|
|
665
|
-
|
|
666
|
-
Every `stats` figure is labelled _estimated_. Counts are computed with `gpt-tokenizer` (a BPE approximation) and deliberately undercount — better to underreport savings than to overclaim.
|
|
667
|
-
|
|
668
|
-
The breakeven ratio (`tokens_saved / tokens_spent`) measures whether extraction cost is paying off. A ratio below 1.5× triggers a warning in `somtum stats` and `somtum doctor`.
|
|
669
|
-
|
|
670
|
-
**A low ratio is normal on a fresh project** (< 20 memories, few recall calls). It improves as memories accumulate and get retrieved more frequently.
|
|
671
|
-
|
|
672
|
-
If the ratio stays low after a few weeks, check for the hybrid/embeddings mismatch first (`somtum doctor`). If the config is correct, reduce injection scope: lower `injection.k` or `injection.max_chars` to cut overhead.
|
|
673
|
-
|
|
674
|
-
---
|
|
675
|
-
|
|
676
|
-
## Performance
|
|
677
|
-
|
|
678
|
-
| Scenario | p95 budget | Actual (benchmark) |
|
|
679
|
-
| --------------------------------------- | ------------- | ------------------------ |
|
|
680
|
-
| `UserPromptSubmit` hook at 1k memories | 150 ms | < 2 ms (BM25 k=8) |
|
|
681
|
-
| `UserPromptSubmit` hook at 10k memories | 300 ms | < 30 ms (BM25 k=8) |
|
|
682
|
-
| Exact cache hash lookup | — | < 0.1 ms |
|
|
683
|
-
| `SessionEnd` hook (extract + embed) | 90 s hard cap | Exits cleanly on timeout |
|
|
684
|
-
|
|
685
|
-
Run benchmarks yourself:
|
|
686
|
-
|
|
687
|
-
```bash
|
|
688
|
-
pnpm test:bench
|
|
689
|
-
```
|
|
690
|
-
|
|
691
|
-
---
|
|
141
|
+
- Secrets matching `privacy.redact_patterns` (API keys, bearer tokens, AWS keys and similar) are redacted before anything is stored.
|
|
142
|
+
- `.env` files and `secrets/` directories are never summarized.
|
|
143
|
+
- Injected memories are wrapped in markers that tell the agent they are reference material, not instructions.
|
|
144
|
+
- No telemetry. `somtum forget` soft-deletes; `somtum purge` removes for good.
|
|
692
145
|
|
|
693
146
|
## Development
|
|
694
147
|
|
|
695
148
|
```bash
|
|
149
|
+
git clone https://github.com/riz007/somtum && cd somtum
|
|
696
150
|
pnpm install
|
|
697
|
-
pnpm
|
|
698
|
-
pnpm
|
|
699
|
-
pnpm
|
|
700
|
-
pnpm test:bench # hot-path latency benchmarks
|
|
701
|
-
pnpm lint # eslint
|
|
702
|
-
pnpm fmt # prettier
|
|
703
|
-
pnpm build # tsc + copy migrations + copy dashboard → dist/
|
|
704
|
-
```
|
|
705
|
-
|
|
706
|
-
### Project layout
|
|
707
|
-
|
|
708
|
-
```
|
|
709
|
-
src/
|
|
710
|
-
cli/
|
|
711
|
-
index.ts # commander CLI entry point
|
|
712
|
-
init.ts # somtum init — installs hooks + MCP config
|
|
713
|
-
serve.ts # somtum serve — local dashboard server
|
|
714
|
-
stats.ts # somtum stats
|
|
715
|
-
doctor.ts # somtum doctor — health checks
|
|
716
|
-
hook.ts # internal: dispatches hook events by name
|
|
717
|
-
search.ts / show.ts / forget.ts / edit.ts
|
|
718
|
-
list.ts # somtum list
|
|
719
|
-
reset.ts # somtum reset — wipe project DB
|
|
720
|
-
export.ts / import.ts / purge.ts / sync.ts / rebuild.ts / reindex.ts
|
|
721
|
-
config_cmd.ts
|
|
722
|
-
suggest_claude_md.ts # somtum suggest-claude-md
|
|
723
|
-
core/
|
|
724
|
-
db.ts # SQLite setup, migration runner
|
|
725
|
-
store.ts # MemoryStore — CRUD for observations
|
|
726
|
-
cache.ts # PromptCache — exact + fuzzy lookup
|
|
727
|
-
retriever/ # bm25, embeddings, hybrid, index, factory
|
|
728
|
-
extractor.ts # session transcript → observations (Claude Haiku)
|
|
729
|
-
index_gen.ts # renders index.md (incremental past 1k obs)
|
|
730
|
-
memory_files.ts # writes memories/<YYYY-MM>/<ulid>.md
|
|
731
|
-
retrieval_stats.ts
|
|
732
|
-
embeddings.ts # Embedder interface + encode/decode utils
|
|
733
|
-
privacy.ts # redact() — runs on every capture
|
|
734
|
-
tokens.ts # gpt-tokenizer wrapper
|
|
735
|
-
hooks/
|
|
736
|
-
post_session.ts # SessionEnd/PreCompact: extract → store → index → warm-start
|
|
737
|
-
pre_prompt.ts # UserPromptSubmit: cache lookup + auto-inject + false-hit detection
|
|
738
|
-
pre_read.ts # PreToolUse: file gating
|
|
739
|
-
mcp/ # MCP server + tool implementations
|
|
740
|
-
dashboard/
|
|
741
|
-
index.html # single-page dashboard (served by somtum serve)
|
|
742
|
-
config.ts # global + project config merge
|
|
743
|
-
index.ts # public API for embedding Somtum
|
|
744
|
-
src/db/migrations/ # NNN_name.sql migration files
|
|
745
|
-
test/
|
|
746
|
-
golden/ # per-strategy retrieval golden sets
|
|
747
|
-
bench/ # hot-path latency benchmarks
|
|
748
|
-
fixtures/ # synthetic session transcripts
|
|
749
|
-
```
|
|
750
|
-
|
|
751
|
-
### Adding a new observation kind
|
|
752
|
-
|
|
753
|
-
1. Extend the zod enum in `src/core/schema.ts`
|
|
754
|
-
2. Update the extractor prompt in `src/core/extractor.ts`
|
|
755
|
-
3. Add a fixture in `test/fixtures/` and an assertion
|
|
756
|
-
4. Update `src/core/index_gen.ts` to render the new section
|
|
757
|
-
|
|
758
|
-
### Adding a new MCP tool
|
|
759
|
-
|
|
760
|
-
1. Define args + response with zod in `src/mcp/tools.ts`
|
|
761
|
-
2. Register it in `src/mcp/server.ts`
|
|
762
|
-
3. Response **must** include a `tokens` field
|
|
763
|
-
4. Add an integration test in `src/mcp/server.test.ts`
|
|
764
|
-
|
|
765
|
-
---
|
|
766
|
-
|
|
767
|
-
## Troubleshooting
|
|
768
|
-
|
|
769
|
-
### `somtum stats` shows `memories 0` after a session
|
|
770
|
-
|
|
771
|
-
Check the hook log first:
|
|
772
|
-
|
|
773
|
-
```bash
|
|
774
|
-
cat ~/.somtum/hook.log
|
|
775
|
-
```
|
|
776
|
-
|
|
777
|
-
**`claude` CLI not found and no `ANTHROPIC_API_KEY` set**
|
|
778
|
-
|
|
779
|
-
- If you use Claude Code: run `which claude` — if nothing prints, reinstall Claude Code or add its binary to your `PATH`.
|
|
780
|
-
- If you prefer the direct API: add `export ANTHROPIC_API_KEY="sk-ant-..."` to `~/.zshrc` and `source ~/.zshrc`. Must be in your profile, not just exported in the current terminal tab.
|
|
781
|
-
|
|
782
|
-
Run `somtum doctor` — the `api_key` check tells you exactly which backend is available.
|
|
783
|
-
|
|
784
|
-
**Hook not installed in the right directory**
|
|
785
|
-
|
|
786
|
-
`somtum init` writes the hook to `.claude/settings.json` in the directory where you ran it. If you launch Claude Code from a different directory, it reads a different settings file.
|
|
787
|
-
|
|
788
|
-
Fix: run `somtum init` from the same directory you use to launch Claude Code.
|
|
789
|
-
|
|
790
|
-
```bash
|
|
791
|
-
cd ~/my-project
|
|
792
|
-
somtum init
|
|
793
|
-
claude # must be launched from ~/my-project
|
|
794
|
-
```
|
|
795
|
-
|
|
796
|
-
**Short or trivial session**
|
|
797
|
-
|
|
798
|
-
If the session had no decisions, bug fixes, or learnings (e.g. you just asked Claude to say hello), the extractor correctly returns 0 observations.
|
|
799
|
-
|
|
800
|
-
---
|
|
801
|
-
|
|
802
|
-
### `somtum serve` opens the browser but shows "Connection refused"
|
|
803
|
-
|
|
804
|
-
This was a bug fixed in v1.1.0. Upgrade:
|
|
805
|
-
|
|
806
|
-
```bash
|
|
807
|
-
npm install -g somtum@latest
|
|
808
|
-
```
|
|
809
|
-
|
|
810
|
-
If you installed from source, rebuild:
|
|
811
|
-
|
|
812
|
-
```bash
|
|
813
|
-
pnpm build
|
|
814
|
-
```
|
|
815
|
-
|
|
816
|
-
---
|
|
817
|
-
|
|
818
|
-
### `somtum serve` — port already in use
|
|
819
|
-
|
|
820
|
-
```bash
|
|
821
|
-
somtum serve --port 3001
|
|
822
|
-
```
|
|
823
|
-
|
|
824
|
-
---
|
|
825
|
-
|
|
826
|
-
### Agent appears to keep running after session ends
|
|
827
|
-
|
|
828
|
-
The `SessionEnd` hook has a hard 90-second timeout. If sessions appear stuck, verify you are on v1.1.0+:
|
|
829
|
-
|
|
830
|
-
```bash
|
|
831
|
-
somtum --version
|
|
832
|
-
tail -20 ~/.somtum/hook.log
|
|
151
|
+
pnpm test # unit, integration and golden retrieval tests
|
|
152
|
+
pnpm typecheck && pnpm lint
|
|
153
|
+
pnpm build # dist/, then `pnpm link --global` to try your build
|
|
833
154
|
```
|
|
834
155
|
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
### Installation fails (node-gyp / better-sqlite3)
|
|
838
|
-
|
|
839
|
-
Ensure build tools are installed:
|
|
840
|
-
|
|
841
|
-
- **macOS:** `xcode-select --install`
|
|
842
|
-
- **Ubuntu/Debian:** `sudo apt-get install build-essential python3`
|
|
843
|
-
- **Windows:** `npm install --global --production windows-build-tools`
|
|
844
|
-
|
|
845
|
-
---
|
|
846
|
-
|
|
847
|
-
### Embeddings are slow or the model won't download
|
|
848
|
-
|
|
849
|
-
The first `somtum reindex` downloads a ~30 MB ONNX model from Hugging Face. This requires internet access and may be slow. Subsequent runs use the cached model.
|
|
850
|
-
|
|
851
|
-
On an air-gapped machine or if you prefer not to use embeddings:
|
|
852
|
-
|
|
853
|
-
```bash
|
|
854
|
-
somtum config set retrieval.embeddings.enabled false
|
|
855
|
-
somtum config set retrieval.strategy bm25
|
|
856
|
-
```
|
|
857
|
-
|
|
858
|
-
BM25 works fully offline and is fast at any corpus size.
|
|
859
|
-
|
|
860
|
-
---
|
|
861
|
-
|
|
862
|
-
### Claude doesn't seem to have context from previous sessions
|
|
863
|
-
|
|
864
|
-
**Auto-inject is the first thing to check.** Since v1.3.0, Somtum automatically injects top-k memories into every `UserPromptSubmit` via the cache hook — no manual recall step needed.
|
|
865
|
-
|
|
866
|
-
1. Confirm the cache hook is installed: `somtum doctor` → look for `hooks_installed ✓`
|
|
867
|
-
2. If not installed: `somtum init --cache` (or `somtum init --all`)
|
|
868
|
-
3. Confirm injection is enabled: `somtum config get injection.enabled` → should be `true`
|
|
869
|
-
4. Check that memories actually exist: `somtum stats` → `memories > 0`
|
|
870
|
-
|
|
871
|
-
**Using the MCP server** (`somtum init --all`), Claude can also call `recall` directly when uncertain. If it's not happening:
|
|
872
|
-
|
|
873
|
-
1. Confirm `.mcp.json` exists: `cat .mcp.json`
|
|
874
|
-
2. Restart Claude Code to pick up the MCP config
|
|
875
|
-
|
|
876
|
-
### Stale memory warning in `somtum doctor`
|
|
877
|
-
|
|
878
|
-
`doctor` warns when memories are older than 90 days with no confirmed retrievals. These are observations that have never come up in a search. Options:
|
|
879
|
-
|
|
880
|
-
```bash
|
|
881
|
-
# Review them before deciding
|
|
882
|
-
somtum search "old topic"
|
|
883
|
-
|
|
884
|
-
# Promote useful ones to workspace scope via MCP
|
|
885
|
-
remember("...", scope="workspace")
|
|
886
|
-
|
|
887
|
-
# Remove irrelevant ones
|
|
888
|
-
somtum purge --older-than 90d
|
|
889
|
-
```
|
|
890
|
-
|
|
891
|
-
---
|
|
892
|
-
|
|
893
|
-
### Starting fresh — wiping all memories
|
|
894
|
-
|
|
895
|
-
To hard-reset a project's memory (irreversible):
|
|
896
|
-
|
|
897
|
-
```bash
|
|
898
|
-
somtum reset
|
|
899
|
-
# Permanently delete all memories for this project? [y/N] y
|
|
900
|
-
# somtum: reset complete — project <id> wiped.
|
|
901
|
-
```
|
|
902
|
-
|
|
903
|
-
To just clear everything softly (recoverable via `somtum export --include-deleted`):
|
|
904
|
-
|
|
905
|
-
```bash
|
|
906
|
-
somtum forget --all
|
|
907
|
-
```
|
|
908
|
-
|
|
909
|
-
---
|
|
910
|
-
|
|
911
|
-
## Contributing
|
|
912
|
-
|
|
913
|
-
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for the guide.
|
|
156
|
+
Where things live:
|
|
914
157
|
|
|
915
|
-
|
|
158
|
+
| Path | What |
|
|
159
|
+
| --- | --- |
|
|
160
|
+
| `src/hooks/` | The three hook handlers: `post_session` (capture), `pre_prompt` (recall), `pre_read` (file gating) |
|
|
161
|
+
| `src/core/` | Store, retrieval, extraction, token ledger, transcript parsing |
|
|
162
|
+
| `src/agents/` | One adapter per agent transcript format. Add an agent here |
|
|
163
|
+
| `src/cli/` | One file per command |
|
|
164
|
+
| `src/db/migrations/` | Numbered, additive SQL migrations |
|
|
916
165
|
|
|
917
|
-
|
|
166
|
+
Two rules for changes: a hook must never break or block the agent's session, and any new token spend must be bounded and recorded in the ledger. Every PR needs a changeset (`pnpm changeset`). See [CONTRIBUTING.md](CONTRIBUTING.md) and [SPEC.md](SPEC.md) for what's planned.
|
|
918
167
|
|
|
919
168
|
## License
|
|
920
169
|
|
|
921
|
-
|
|
170
|
+
[MIT](LICENSE)
|