
Local-first memory and prompt-cache layer for coding agents: Claude Code and Codex.
Docs · npm

Somtum (Thai: ส้มตำ) is named after the vibrant, shredded green papaya salad. Just like its namesake, Somtum blends durable observations from your Claude Code and Codex 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.
Zero-config: one somtum init and every session end is captured automatically. No server, no cloud account, no mandatory tuning.
Table of Contents
- Why Somtum?
- How it works
- Requirements
- Install
- Quickstart
- Verifying the setup
- Dashboard
- CLI Reference
- MCP Server
- Storage Layout
- Configuration
- Privacy
- Token Accounting
- Performance
- Development
- Troubleshooting
- License
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
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
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
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
Why Somtum?
Coding agents like Claude Code and Codex start every session with a blank slate. That leads to:
- Repetitive context — re-explaining the same architectural choices every session
- Regressions — the agent suggests a fix you already tried and discarded
- Token waste — reading large files just to "set the scene"
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.
What a session looks like with Somtum
Without Somtum With Somtum
──────────────────── ──────────────────────────────────────
Session 1: "We use pnpm Session 1: same work
because of workspace
hoisting"
Session 2: Claude suggests Session 2: Claude already knows about
npm, you correct it pnpm, the auth decisions, and the
again bugfixes from last week
How it works
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.
Memory lifecycle
┌─────────────────────────────────────────────────────────────┐
│ Claude Code or Codex session │
│ │
│ you code · debug · review · make decisions │
└──────────────────────────────┬──────────────────────────────┘
│ SessionEnd / PreCompact
▼
┌─────────────────────────────────────────────────────────────┐
│ Capture Pipeline │
│ │
│ session transcript ──► Haiku extracts observations │
│ │
│ decisions · bug fixes · learnings · commands │
│ │
│ PreCompact ─── writes warm-start file ──► next session │
└──────────────────────────────┬──────────────────────────────┘
│ persisted locally
▼
┌─────────────────────────┐
│ ~/.somtum/projects/ │
│ <project-hash>/ │
│ │
│ db.sqlite │
│ index.md │
│ memories/YYYY-MM/ │
└────────────┬────────────┘
│ every prompt (UserPromptSubmit)
▼
┌─────────────────────────────────────────────────────────────┐
│ Auto-Inject Pipeline (new) │
│ │
│ 1. Prompt cache lookup (exact + fuzzy match) │
│ 2. BM25 recall — top-k relevant memories │
│ 3. Warm-start context (if session just compacted) │
│ │
│ all injected as additionalContext automatically │
└─────────────────────────────────────────────────────────────┘
What gets captured — a concrete example
You work a session debugging an auth bug and refactoring a module. At session end, Somtum extracts something like:
[
{
"kind": "bugfix",
"title": "JWT refresh loop caused by missing expiry check",
"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.",
"files": ["src/auth/refresh.ts"]
},
{
"kind": "decision",
"title": "Use pnpm workspaces — npm hoisting breaks shared types",
"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.",
"files": ["package.json", "pnpm-workspace.yaml"]
}
]
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.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Claude Code / Codex / MCP client │
└──────────┬──────────────────────────────┬───────────────────┘
│ hooks │ MCP tools
▼ ▼
┌─────────────────────┐ ┌──────────────────────────┐
│ Hooks │ │ MCP Tools │
│ │ │ │
│ UserPromptSubmit ──┼─cache──▶│ cache_lookup │
│ ──┼─inject─▶│ recall / get │
│ SessionEnd ────────┼─capture▶│ remember / update │
│ PreCompact ────────┼─warmst─▶│ forget │
│ PreToolUse (Read) ─┼─gate───▶│ stats │
│ │ │ report_false_hit │
└──────────┬──────────┘ └────────────┬─────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ Core (TypeScript) │
│ │
│ ┌──────────────┐ ┌─────────────────┐ ┌───────────────┐ │
│ │ PromptCache │ │ MemoryStore │ │ Retriever │ │
│ │ │ │ │ │ │ │
│ │ exact hash │ │ observations │ │ bm25(default) │ │
│ │ fuzzy embed │ │ scope: project │ │ embeddings │ │
│ │ fingerprint │ │ global │ │ index │ │
│ │ false_hits │ │ workspace │ │ hybrid │ │
│ └──────────────┘ │ last_confirmed │ └───────────────┘ │
│ └─────────────────┘ │
└─────────────────────────────────┬───────────────────────────┘
│
▼
┌─────────────────────────────┐
│ SQLite WAL + ~/.somtum/ │
│ /projects/<hash>/ │
│ db.sqlite │
│ index.md │
│ memories/YYYY-MM/<ulid>.md│
│ /session/lh_<id>.json │
│ /warmstart/ws_<id>.json │
└─────────────────────────────┘
Retrieval strategies
| Strategy | How it works | Best for | Cost |
|---|
bm25 | Keyword search over title + body + tags (SQLite FTS5 — no external dependencies) | Exact terms, offline setups | Near-zero |
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 |
index | Sends a compact memory catalog to Haiku; the model picks relevant IDs | Paraphrased or fuzzy queries | 1 Haiku API call |
hybrid | BM25 + embeddings results merged and re-ranked by Haiku | General case (best recall) | BM25 + embeddings + 1 Haiku call |
Default is bm25 — works offline, no setup. Enable hybrid once you have embeddings downloaded.
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:
somtum config set retrieval.strategy bm25 # match what's actually running
# or, to use real hybrid:
somtum config set retrieval.embeddings.enabled true && somtum reindex
Requirements
-
Node 20+
-
Claude Code or Codex — Somtum hooks into their SessionEnd, PreCompact and UserPromptSubmit events. Both agents share one memory store per project.
-
An extraction backend, picked automatically in this order:
ANTHROPIC_API_KEY, or ANTHROPIC_AUTH_TOKEN + ANTHROPIC_BASE_URL for Anthropic-compatible providers such as GLM
- the
claude CLI (Claude Code subscribers need no separate key)
- the
codex CLI (ChatGPT/Codex subscribers need no separate key)
Override with somtum config set extraction.backend anthropic|claude-cli|codex-cli.
Install
npm install -g somtum
pnpm users: pnpm add -g somtum works if you have run pnpm setup first (sets PNPM_HOME). If you haven't, use npm above.
yarn users: yarn global add is not supported in Yarn v2+ (Berry). Use npm above.
From source