Skip to content

Add memory storage engine #236

@theantichris

Description

@theantichris

Summary

Add the core memory storage engine that handles Markdown file I/O, SQLite indexing, text chunking, and hybrid search (vector + BM25).

Details

New dependency:

  • modernc.org/sqlite — pure Go SQLite driver (no CGo, preserves clean cross-compilation)

New files:

  • internal/memory/store.go
  • internal/memory/store_test.go

Key types:

type EmbedFunc func(ctx context.Context, text string) ([]float64, error)

type Store struct {
    db      *sql.DB
    dir     string       // ~/.config/ghost/memory
    embedFn EmbedFunc
    mu      sync.RWMutex
}

type SearchResult struct {
    Source  string  // e.g. "daily/2026-02-07.md" or "MEMORY.md"
    Content string
    Score   float64
}

SQLite schema:

  • chunks table: id, source, chunk_index, content, embedding (BLOB)
  • chunks_fts FTS5 virtual table with sync triggers
  • WAL mode + busy_timeout for concurrency

Functions:

  • NewStore(dir, embedFn) — create directory structure, open DB, create schema
  • SaveToDaily(ctx, content) — append to daily/YYYY-MM-DD.md, index new content
  • SaveToLongTerm(ctx, content) — append to MEMORY.md, index new content
  • IndexFile(ctx, source) — chunk file, embed chunks, upsert into SQLite
  • Search(ctx, query, topK) — hybrid retrieval (70% cosine similarity + 30% BM25)
  • chunkText(text, maxChars, overlapChars) — paragraph-aware chunking (~400 tokens, 80 overlap)
  • cosineSimilarity(a, b []float64) — vector math helper
  • Close() — close SQLite connection

File structure on disk:

~/.config/ghost/memory/
  MEMORY.md
  daily/
    2026-02-07.md
  index.db

Design decisions:

  • EmbedFunc injection (not an interface) for testability
  • Brute-force vector search (corpus is small enough, no ANN needed)
  • Markdown files are source of truth; SQLite index is derived and rebuildable
  • Embedding vectors serialized as binary (compact, fast)

Testing:

  • Tests use temp dirs + mock EmbedFunc returning deterministic vectors
  • TestChunkText, TestCosineSimilarity, TestNewStore, TestSaveToDaily, TestSaveToLongTerm, TestSearch, TestIndexFile

Dependencies

Acceptance Criteria

  • Directory structure created on NewStore()
  • SQLite schema with FTS5 created correctly
  • SaveToDaily creates/appends daily Markdown files
  • SaveToLongTerm creates/appends MEMORY.md
  • IndexFile chunks text and stores embeddings
  • Search returns relevant results with hybrid scoring
  • All tests pass with mock embedding function

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    Status

    Backlog

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions