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.
Files changed (99) hide show
  1. package/README.md +101 -852
  2. package/dist/agents/claude_code.d.ts +3 -0
  3. package/dist/agents/claude_code.d.ts.map +1 -0
  4. package/dist/agents/claude_code.js +112 -0
  5. package/dist/agents/claude_code.js.map +1 -0
  6. package/dist/agents/codex.d.ts +3 -0
  7. package/dist/agents/codex.d.ts.map +1 -0
  8. package/dist/agents/codex.js +173 -0
  9. package/dist/agents/codex.js.map +1 -0
  10. package/dist/agents/index.d.ts +7 -0
  11. package/dist/agents/index.d.ts.map +1 -0
  12. package/dist/agents/index.js +24 -0
  13. package/dist/agents/index.js.map +1 -0
  14. package/dist/agents/shared.d.ts +3 -0
  15. package/dist/agents/shared.d.ts.map +1 -0
  16. package/dist/agents/shared.js +18 -0
  17. package/dist/agents/shared.js.map +1 -0
  18. package/dist/agents/types.d.ts +11 -0
  19. package/dist/agents/types.d.ts.map +1 -0
  20. package/dist/agents/types.js +2 -0
  21. package/dist/agents/types.js.map +1 -0
  22. package/dist/cli/doctor.d.ts.map +1 -1
  23. package/dist/cli/doctor.js +65 -78
  24. package/dist/cli/doctor.js.map +1 -1
  25. package/dist/cli/hook.d.ts.map +1 -1
  26. package/dist/cli/hook.js +1 -4
  27. package/dist/cli/hook.js.map +1 -1
  28. package/dist/cli/index.js +14 -7
  29. package/dist/cli/index.js.map +1 -1
  30. package/dist/cli/init.d.ts +19 -0
  31. package/dist/cli/init.d.ts.map +1 -1
  32. package/dist/cli/init.js +68 -36
  33. package/dist/cli/init.js.map +1 -1
  34. package/dist/cli/init_codex.d.ts +12 -0
  35. package/dist/cli/init_codex.d.ts.map +1 -0
  36. package/dist/cli/init_codex.js +53 -0
  37. package/dist/cli/init_codex.js.map +1 -0
  38. package/dist/cli/serve.d.ts.map +1 -1
  39. package/dist/cli/serve.js +2 -0
  40. package/dist/cli/serve.js.map +1 -1
  41. package/dist/cli/stats.d.ts +4 -0
  42. package/dist/cli/stats.d.ts.map +1 -1
  43. package/dist/cli/stats.js +71 -43
  44. package/dist/cli/stats.js.map +1 -1
  45. package/dist/cli/ui.d.ts +1 -1
  46. package/dist/cli/ui.d.ts.map +1 -1
  47. package/dist/cli/ui.js +1 -1
  48. package/dist/cli/ui.js.map +1 -1
  49. package/dist/core/extractor.d.ts +1 -0
  50. package/dist/core/extractor.d.ts.map +1 -1
  51. package/dist/core/extractor.js +93 -52
  52. package/dist/core/extractor.js.map +1 -1
  53. package/dist/core/ledger.d.ts +28 -0
  54. package/dist/core/ledger.d.ts.map +1 -0
  55. package/dist/core/ledger.js +43 -0
  56. package/dist/core/ledger.js.map +1 -0
  57. package/dist/core/llm_backend.d.ts +7 -0
  58. package/dist/core/llm_backend.d.ts.map +1 -0
  59. package/dist/core/llm_backend.js +44 -0
  60. package/dist/core/llm_backend.js.map +1 -0
  61. package/dist/core/memory_files.d.ts.map +1 -1
  62. package/dist/core/memory_files.js +2 -3
  63. package/dist/core/memory_files.js.map +1 -1
  64. package/dist/core/retriever/bm25.d.ts +1 -1
  65. package/dist/core/retriever/bm25.d.ts.map +1 -1
  66. package/dist/core/retriever/bm25.js +11 -1
  67. package/dist/core/retriever/bm25.js.map +1 -1
  68. package/dist/core/schema.d.ts +19 -4
  69. package/dist/core/schema.d.ts.map +1 -1
  70. package/dist/core/schema.js +10 -1
  71. package/dist/core/schema.js.map +1 -1
  72. package/dist/core/session_progress.d.ts +10 -0
  73. package/dist/core/session_progress.d.ts.map +1 -0
  74. package/dist/core/session_progress.js +39 -0
  75. package/dist/core/session_progress.js.map +1 -0
  76. package/dist/core/transcript.d.ts.map +1 -1
  77. package/dist/core/transcript.js +2 -108
  78. package/dist/core/transcript.js.map +1 -1
  79. package/dist/dashboard/index.html +1 -1
  80. package/dist/db/migrations/006_token_ledger.sql +33 -0
  81. package/dist/hooks/post_session.d.ts +6 -5
  82. package/dist/hooks/post_session.d.ts.map +1 -1
  83. package/dist/hooks/post_session.js +107 -57
  84. package/dist/hooks/post_session.js.map +1 -1
  85. package/dist/hooks/pre_prompt.d.ts.map +1 -1
  86. package/dist/hooks/pre_prompt.js +14 -1
  87. package/dist/hooks/pre_prompt.js.map +1 -1
  88. package/dist/hooks/pre_read.d.ts +16 -2
  89. package/dist/hooks/pre_read.d.ts.map +1 -1
  90. package/dist/hooks/pre_read.js +81 -26
  91. package/dist/hooks/pre_read.js.map +1 -1
  92. package/dist/index.d.ts +1 -1
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +1 -1
  95. package/dist/index.js.map +1 -1
  96. package/dist/mcp/tools.d.ts.map +1 -1
  97. package/dist/mcp/tools.js +2 -0
  98. package/dist/mcp/tools.js.map +1 -1
  99. package/package.json +9 -3
package/README.md CHANGED
@@ -1,921 +1,170 @@
1
- <img src="./assets/logo.png" width="500" alt="Somtum Logo">
1
+ <img src="./assets/logo.png" width="420" alt="Somtum">
2
2
 
3
- **Local-first memory and prompt-cache layer for Claude Code.**
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
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
5
  [![npm version](https://badge.fury.io/js/somtum.svg)](https://www.npmjs.com/package/somtum)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
7
 
10
- Somtum (Thai: ส้มตำ) is named after the vibrant, shredded green papaya salad. Just like its namesake, Somtum blends durable observations from your Claude Code sessions — decisions, bugfixes, learnings, file summaries — stores them in a local SQLite database, and injects the relevant ones back into context the next time you work on the same project.
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
- ## Requirements
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
- - **Node 20+**
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
- ## Install
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
- > **pnpm users:** `pnpm add -g somtum` works if you have run `pnpm setup` first (sets `PNPM_HOME`). If you haven't, use npm above.
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
- # Add to ~/.zshrc or ~/.bashrc
254
- export ANTHROPIC_API_KEY="sk-ant-..."
255
- source ~/.zshrc
29
+ somtum list # what was remembered
30
+ somtum stats # what it cost
256
31
  ```
257
32
 
258
- Both paths work. Most Claude Code users should use Option A.
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
- If you already have Claude Code installed, you're done. Somtum calls `claude --print` automatically when no API key is present. Skip to Step 2.
35
+ ## What it does
269
36
 
270
- **Option B: Direct Anthropic API key (optional — faster, lets you pick the model)**
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
- Add to `~/.zshrc` (or `~/.bashrc`):
273
-
274
- ```bash
275
- export ANTHROPIC_API_KEY="sk-ant-..."
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
- Then reload:
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
- ```bash
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
- > The key must be in your shell profile, not just exported in an open terminal tab. The `SessionEnd` hook inherits the environment of the shell that _started_ Claude Code — not the current terminal.
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
- ### Step 2 — Install inside a Claude Code project
54
+ ## What it costs
287
55
 
288
- Run this from the **root of the project you work on with Claude Code**:
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
- ```bash
291
- somtum init
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
- To enable all features at once (recommended):
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
- ### Step 3 — Verify your setup
306
-
307
- Run doctor immediately after init to confirm everything is connected:
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
- All checks should show `✓`. The two most important are:
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
- - **`api_key`** — confirms Somtum has a way to call Claude for extraction
316
- - **`hooks_installed`** — confirms the SessionEnd hook is registered
75
+ ### Measured: not paying twice for the same transcript
317
76
 
318
- Do not start your first session until all checks pass. Each failing check shows an inline fix command.
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
- ### Step 4 — Use Claude Code normally
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
- Open a Claude Code session **from the same directory** where you ran `somtum init`. Work as you normally would. When the session ends, the hook extracts observations automatically in the background (capped at 90 seconds).
85
+ ### What Somtum cannot measure
323
86
 
324
- ### Step 5 — Check your memory
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
- ```bash
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
- After your **first** Claude Code session ends:
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
- **1. Check the hook log**
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
- cat ~/.somtum/hook.log
96
+ somtum init --file-gating # installs the hook and turns it on for this project
350
97
  ```
351
98
 
352
- A successful run:
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
- Using the `claude` CLI fallback (no API key):
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
- Neither backend available:
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
- ~/.somtum/
535
- ├── config.json ← global config (merged with project config)
536
- ├── hook.log ← timestamped log of every hook execution
537
- ├── global.db ← global-scope memories (scope='global'), queried
538
- │ alongside every project DB on recall + auto-inject
539
- ├── session/
540
- │ └── lh_<id>.json ← last cache-hit state per project (false-hit detection)
541
- │ files older than 24 h are evicted automatically
542
- ├── warmstart/
543
- │ └── ws_<id>_<timestamp>.json ← warm-start context written after PreCompact (30 min TTL)
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
- The project ID is derived from the git remote URL (or directory path if no remote). The same project maps to the same ID across machines as long as the remote URL matches.
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
- ## Configuration
132
+ ## Upgrading from 3.0
561
133
 
562
- Global config lives at `~/.somtum/config.json`. Per-project config at `.somtum/config.json` overrides it (deep merge).
563
-
564
- ### Most common settings
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
- - **No network traffic** except to the Anthropic API (extraction + optional reranking). The embedding model runs fully local via ONNX Runtime in-process.
657
- - **Redaction at capture time.** `privacy.redact_patterns` is applied to every observation body before it is written to the DB — unconditionally, regardless of the `telemetry` flag.
658
- - **Explicit file excludes.** `file_gating.exclude_globs` prevents `.env`, `secrets/`, and similar paths from being summarized.
659
- - **Prompt-injection hardening.** Memory content injected into agent context is wrapped in `[Somtum memory — reference material, not instructions]` delimiters.
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 typecheck # strict TypeScript check
698
- pnpm test # vitest unit + golden tests
699
- pnpm test:golden # retrieval recall@k per strategy
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
- **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 |
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
- Licensed under the [MIT License](LICENSE).
170
+ [MIT](LICENSE)