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