Skip to content

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, one store per project, shared by both agents. On every subsequent prompt, Somtum retrieves the most relevant memories and injects them into context.

Supported agents ​

AgentCaptureAuto-injectMCP toolsInstall
Claude CodeSessionEnd, PreCompactUserPromptSubmit (with --all or --cache).mcp.jsonsomtum init --all
CodexSessionEnd, PreCompactUserPromptSubmit (default).codex/config.tomlsomtum init --agent codex
Any other MCP client——point it at somtum mcpmanual

Both agents send hooks the same JSON payload and accept the same reply, so one set of hook handlers serves both. Only transcript parsing differs: Claude Code writes ~/.claude/projects/**.jsonl, Codex writes ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl. Somtum detects the format automatically.

Extraction backends ​

Extraction uses the first available of: the Anthropic API (ANTHROPIC_API_KEY, or ANTHROPIC_AUTH_TOKEN + ANTHROPIC_BASE_URL for GLM and other compatible providers), the claude CLI, or the codex CLI. Before sending, Somtum keeps the conversation and trims tool output and tool-call arguments (whole files inside edits, for example) so you don't pay to send file contents the extractor doesn't need. Pin a backend with extraction.backend.

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                      │
│                                                             │
│  1. Prompt cache lookup (exact + fuzzy match)               │
│  2. BM25 recall — top-k memories, min_relevance filter      │
│  3. Warm-start context (if session just compacted)          │
│  4. Token budget line prepended (show_budget=true)          │
│                                                             │
│      all injected as additionalContext automatically        │
└─────────────────────────────────────────────────────────────┘

What gets captured — an example ​

You debug an auth bug and refactor a module. At session end, Somtum extracts something like:

json
[
  {
    "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, in either agent, when you ask "why are we using pnpm?" or open 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                    │
│  (Claude Code only) │         │                          │
│                     │         │ 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        │  │
│  └──────────────┘  └─────────────────┘  └───────────────┘  │
└─────────────────────────────┬───────────────────────────────┘
                              │
                              ▼
                ┌─────────────────────────────┐
                │  SQLite WAL + ~/.somtum/     │
                └─────────────────────────────┘

Retrieval strategies ​

StrategyHow it worksBest forCost
bm25Keyword search over title + body + tags (SQLite FTS5, no external dependencies)Exact terms, offline setupsNear-zero
embeddingsSemantic similarity using a 30 MB local ONNX model (bge-small-en-v1.5, fully in-process)"What did we decide about auth?" style queries~5 ms at 10k memories
indexSends a compact memory catalog to Haiku; the model picks relevant IDsParaphrased or fuzzy queries1 Haiku API call
hybridBM25 + embeddings results merged and re-ranked by HaikuGeneral case (best recall)BM25 + embeddings + 1 Haiku call

Default is bm25 — works offline, no setup required. Enable hybrid once you have embeddings downloaded.

To switch strategy:

bash
# Enable semantic search (downloads 30 MB model once)
somtum config set retrieval.embeddings.enabled true
somtum reindex

# Switch to hybrid for best recall
somtum config set retrieval.strategy hybrid

See Configuration for the full options.

Memory kinds ​

Somtum captures observations in six categories:

KindDescription
decisionArchitectural or design choices and their rationale
learningThings discovered during debugging or exploration
bugfixA fix and its root cause
commandUseful CLI commands or workflows
file_summaryA summary of what a file or module does
otherAnything else worth remembering

Released under the MIT License.