Skip to content

Add SQLite memory system with FTS5 full-text search#9

Merged
chinmaymk merged 22 commits intomainfrom
claude/add-sqlite-memory-system-lXGVv
Mar 8, 2026
Merged

Add SQLite memory system with FTS5 full-text search#9
chinmaymk merged 22 commits intomainfrom
claude/add-sqlite-memory-system-lXGVv

Conversation

@chinmaymk
Copy link
Copy Markdown
Owner

Implements a persistent memory system backed by SQLite with FTS5 for
full-text search. Memories can be saved/searched via agent tools and
auto-extracted from conversations via configurable middleware.

  • MemoryStore: SQLite + FTS5 with configurable path, max size, and TTL
  • DefaultMemoryExtractor: extracts [REMEMBER:] markers and user preferences
  • memory_search / memory_save tools exposed to the agent
  • Auto-extraction middleware (beforeLoopBegin prunes, afterLoopIteration extracts)
  • Config: memory.enabled, path, maxSizeMB, ttlDays, extractor, autoExtract
  • Env vars: RA_MEMORY_ENABLED, RA_MEMORY_PATH, RA_MEMORY_MAX_SIZE_MB, etc.
  • Custom extractors via memory.extractor config path

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx

claude added 22 commits March 8, 2026 05:11
Implements a persistent memory system backed by SQLite with FTS5 for
full-text search. Memories can be saved/searched via agent tools and
auto-extracted from conversations via configurable middleware.

- MemoryStore: SQLite + FTS5 with configurable path, max size, and TTL
- DefaultMemoryExtractor: extracts [REMEMBER:] markers and user preferences
- memory_search / memory_save tools exposed to the agent
- Auto-extraction middleware (beforeLoopBegin prunes, afterLoopIteration extracts)
- Config: memory.enabled, path, maxSizeMB, ttlDays, extractor, autoExtract
- Env vars: RA_MEMORY_ENABLED, RA_MEMORY_PATH, RA_MEMORY_MAX_SIZE_MB, etc.
- Custom extractors via memory.extractor config path

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
…LLM reflection

Layered memory:
- Two memory layers: session (ephemeral, per-conversation) and long-term (durable)
- Session memories auto-expire via sessionTTLHours (default: 24h)
- Long-term memories persist with ttlDays (default: 90 days)
- promote() to upgrade session memories to long-term
- Size enforcement prioritizes removing session memories first

Configurable extraction patterns:
- PatternExtractor with configurable regex patterns, role filters, max length, capture modes
- DEFAULT_PATTERNS provides baseline (REMEMBER markers, user preferences)
- Custom patterns via config (merged with defaults)
- Deduplication within extraction passes

LLM-driven reflective extraction:
- ReflectiveExtractor sends conversation to an LLM for structured learning extraction
- Runs on afterLoopComplete (end of conversation, not per-iteration)
- Best-effort: never fails the main flow
- Configurable model (use a cheaper model for reflection)

New config options: sessionTTLHours, patterns[], reflect, reflectionModel
New tool: memory_delete
New env vars: RA_MEMORY_SESSION_TTL_HOURS, RA_MEMORY_REFLECT, RA_MEMORY_REFLECTION_MODEL

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
…pt injection

The LLM discovers when to save/search memories purely from the tool
descriptions (which include PROACTIVELY directives). The middleware
stays focused on pruning and pattern extraction — no message injection.

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
- ReflectiveExtractor accepts optional custom prompt (must contain {CONVERSATION})
- Export DEFAULT_REFLECTION_PROMPT for reference when writing custom prompts
- Config: memory.reflectionPrompt, env: RA_MEMORY_REFLECTION_PROMPT
- Thread through middleware options and src/index.ts wiring

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
Instead of relying on the LLM to call memory_search, inject the top N
most recent long-term and session memories as a <recalled-memories> user
message at the start of each loop. This gives the LLM context without
extra tool calls.

- Configurable via memory.injectLimit (default: 20, set 0 to disable)
- Env var: RA_MEMORY_INJECT_LIMIT
- Long-term memories shown with tags, session memories tagged with session ID

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
…flection

Session is now the default layer for all memory operations:
- store.save() defaults to session
- memory_save tool defaults to session
- Pattern extractor saves to session
- Only the reflective extractor (afterLoopComplete) promotes to long-term

The reflection prompt is updated to set a high bar: only extract facts
with proven, lasting importance — reinforced preferences, architectural
decisions, recurring patterns.

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
Delete remains available on MemoryStore for programmatic use but is not
exposed as an agent tool.

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
Drop layers, extractors, and reflection in favor of a single flat store
with three tools (memory_save, memory_search, memory_forget). Fix forget()
returning inflated count from FTS triggers and list() ordering by
second-precision timestamp instead of ID.

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
- Remove unused UPDATE trigger and buggy size-based enforceMaxSize loop
- Replace maxSizeMB with count-based maxMemories (reliable, no WAL issues)
- Combine schema init into single exec call
- Add memory section to README, configuration, tools, and concepts docs

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
- Guard search/forget against empty queries and FTS5 syntax errors
  (unmatched quotes, parens, bare operators) that would throw at runtime
- Add PRAGMA busy_timeout for safe multi-process access
- Add 12 new edge case tests: FTS special chars, empty queries,
  FTS sync after forget, persistence across reopen, trim/prune no-ops

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
- memory_save: directive language, concrete examples, dedup guidance
  (forget old version before saving updated one)
- memory_search: explains that recent memories are already injected,
  use this for targeted lookups beyond the recalled set
- memory_forget: broadened triggers to include contradictions and
  pre-update cleanup, not just explicit user requests
- Tags: suggest concrete categories (preference, project, convention,
  team, tooling) instead of vague "comma-separated tags"
- Query hints: "single keywords work best" to avoid FTS syntax issues
- Injection message: explains what recalled memories are and tells
  the LLM to forget outdated ones

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
- --memory CLI flag enables memory without editing config
- /memories [n] lists stored memories in the REPL
- /forget <query> lets users manually delete memories by search
- Update help text, README, and REPL docs

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
The REPL /forget command called store.forget(query) without a limit,
defaulting to 10. Users expect /forget to delete all matching memories,
not just the first 10.

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
ra --memory --memories prints all stored memories and exits,
providing a quick way to inspect memory contents without starting
a REPL session.

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
- `ra --memories` now auto-enables memory (no need for `--memory --memories`)
- `ra --forget "dark mode"` deletes matching memories and exits
- `ra --forget "dark mode" --dry-run` previews matches without deleting
- --forget and --memories both imply --memory automatically

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
…-forget

Replace --dry-run workflow with a simpler pattern:
  ra --memories              # list all memories
  ra --memories dark mode    # search memories matching "dark mode"
  ra --forget dark mode      # delete memories matching "dark mode"

Users search first with --memories, then use the same query with --forget.
Both flags use positionals as the query and auto-enable memory.

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
ra --memories "dark mode"   # search
ra --forget "dark mode"     # delete matches
ra --memories               # list all (no query)

Pre-extracts --memories/--forget from argv before parseArgs since
util.parseArgs doesn't support optional string values.

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
- Merge conflict in shutdown(): keep try/catch from main + memoryStore.close()
- Consistent error messages across CLI and REPL
- README: document --memories and --forget CLI flags
- Config docs: add --memory CLI flag to table

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
Keeps context lean by default — inject only the 5 most recent
memories per loop. Users can increase via config if needed.

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
…ions

FTS5 handles multiple keywords well (implicit AND). Updated search
and forget tool descriptions to show multi-keyword examples.

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
Replace hacky pre-extraction loop with standard util.parseArgs options.
--memories is now a regular string arg, --list-memories is a boolean
for listing all, and --forget is a regular string arg.

https://claude.ai/code/session_01UES55H4Pujmi9K3ggjuosx
@chinmaymk chinmaymk merged commit 8dd710e into main Mar 8, 2026
1 check passed
@chinmaymk chinmaymk deleted the claude/add-sqlite-memory-system-lXGVv branch March 8, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants