Skip to content

Go Library ​

The memory package manages workspace memory files, chunk-based indexing with embeddings, and hybrid search (FTS5 full-text + vector similarity).

bash
go get github.com/openparallax/openparallax/memory

Architecture ​

The memory module has two layers:

  1. Manager — workspace memory files (SOUL.md, IDENTITY.md, USER.md, MEMORY.md, HEARTBEAT.md, AGENTS.md). Provides read, append, FTS5 search, session summarization, and relevant-context retrieval.
  2. Indexer — chunk-based indexing pipeline. Splits files into overlapping chunks, embeds them with a configurable provider, and stores embeddings for vector search. Supports hybrid search (70% vector + 30% keyword blend).
                Manager                         Indexer
        ┌──────────────────┐           ┌──────────────────────┐
        │  Read / Append   │           │  IndexFile           │
        │  Search (FTS5)   │           │  IndexWorkspace      │
        │  SummarizeSession│           │  IndexSessions       │
        │  SearchRelevant  │           │                      │
        └────────┬─────────┘           └────────┬─────────────┘
                 │                               │
            Store (FTS5)                    ChunkStore + EmbeddingProvider
                 │                               │
            ┌────┴────┐                     ┌────┴────┐
            │ SQLite  │                     │ SQLite  │
            └─────────┘                     └─────────┘

Manager ​

Manages the six workspace memory files and provides FTS5 search.

NewManager ​

go
func NewManager(workspace string, store Store, provider llm.Provider) *Manager

Creates a Manager and indexes all memory files on startup via ReindexAll(). The provider is used for session summarization (can be nil if summarization is not needed).

Store Interface ​

The persistence interface Manager requires:

go
type Store interface {
    IndexMemoryFile(path string, content string)
    ClearMemoryIndex()
    SearchMemory(query string, limit int) ([]SearchResult, error)
}

Implemented by memory/sqlite.NewStore(db) which wraps internal/storage.DB.

Read ​

go
func (m *Manager) Read(fileType FileType) (string, error)

Reads a workspace memory file. Returns ErrFileNotFound if the file does not exist.

Append ​

go
func (m *Manager) Append(fileType FileType, content string) error

Appends content to a memory file and reindexes it.

go
func (m *Manager) Search(query string, limit int) ([]SearchResult, error)

FTS5 full-text search across all indexed memory files. Default limit is 20.

SummarizeSession ​

go
func (m *Manager) SummarizeSession(ctx context.Context, sessionTitle string, messages []llm.ChatMessage) error

Generates a 2-5 bullet summary of a conversation and appends it to MEMORY.md under a dated header. Skips sessions with fewer than 2 messages. Uses a 500-token cap for the summary LLM call.

SearchRelevant ​

go
func (m *Manager) SearchRelevant(query string, relevantK, recentK int) []string

Returns memory chunks relevant to a query plus the most recent MEMORY.md entries, deduplicated. Used by the context assembler to inject only pertinent memory into the system prompt.

ReindexAll ​

go
func (m *Manager) ReindexAll()

Rebuilds the FTS5 index from all workspace memory files.

Indexer ​

Manages chunk-based indexing with optional embeddings for vector search.

NewIndexer ​

go
func NewIndexer(store ChunkStore, embedder EmbeddingProvider, vector VectorSearcher, log *logging.Logger) *Indexer

Creates an Indexer. Pass nil for embedder and vector to use FTS5-only mode.

IndexFile ​

go
func (idx *Indexer) IndexFile(ctx context.Context, path string) error

Chunks a file into overlapping segments (400 chars, 80 overlap), indexes them in the ChunkStore, and generates embeddings if a provider is configured. Skips unchanged files (tracked by content hash).

IndexWorkspace ​

go
func (idx *Indexer) IndexWorkspace(ctx context.Context, workspace string) error

Indexes all memory files in a workspace directory.

IndexSessions ​

go
func (idx *Indexer) IndexSessions(ctx context.Context) error

Indexes stored session transcripts for search.

ChunkStore Interface ​

go
type ChunkStore interface {
    GetFileHash(path string) (string, error)
    SetFileHash(path, hash string)
    InsertChunk(id, path string, startLine, endLine int, text, hash string)
    DeleteChunksByPath(path string)
    GetChunkIDsByPath(path string) ([]string, error)
    GetChunkByID(id string) (*ChunkSearchResult, error)
    UpdateChunkEmbedding(id string, embedding []float32)
    GetAllEmbeddings() ([]ChunkEmbedding, error)
    SearchChunksFTS(query string, limit int) ([]ChunkSearchResult, error)
    GetEmbeddingCache(contentHash string) ([]float32, error)
    SetEmbeddingCache(contentHash string, embedding []float32, model string)
}

Implemented by internal/storage.DB.

Search ​

HybridSearch ​

go
func HybridSearch(ctx context.Context, store ChunkStore, embedder EmbeddingProvider, vector VectorSearcher, query string, limit int) ([]HybridSearchResult, error)

Performs vector similarity + FTS5 keyword search with a 70/30 score blend. Falls back to FTS5-only if no embedding provider is configured. Fetches limit * 3 candidates from each source before merging.

CosineSimilarity ​

go
func CosineSimilarity(a, b []float32) float64

Pure Go cosine similarity between two vectors.

Embedding ​

EmbeddingProvider Interface ​

go
type EmbeddingProvider interface {
    Embed(ctx context.Context, texts []string) ([][]float32, error)
    Dimension() int
    ModelID() string
}

NewEmbeddingProvider ​

go
func NewEmbeddingProvider(cfg EmbeddingConfig) EmbeddingProvider

Creates a provider from config. Returns nil if provider is "none" or empty.

Supported providers:

ProviderDefault ModelDimensions
openaitext-embedding-3-small1536
googletext-embedding-004768
ollamanomic-embed-text768

VectorSearcher Interface ​

go
type VectorSearcher interface {
    Insert(id string, embedding []float32) error
    Search(query []float32, limit int) ([]VectorResult, error)
    Delete(id string) error
}

The default implementation is BuiltinVectorSearcher — pure Go cosine similarity with an in-memory map. No external dependencies.

go
vs := memory.NewBuiltinVectorSearcher()

Types ​

FileType ​

go
type FileType string

const (
    MemorySoul      FileType = "SOUL.md"
    MemoryIdentity  FileType = "IDENTITY.md"
    MemoryUser      FileType = "USER.md"
    MemoryMain      FileType = "MEMORY.md"
    MemoryHeartbeat FileType = "HEARTBEAT.md"
    MemoryAgents    FileType = "AGENTS.md"
)

SearchResult ​

FTS5 search result from memory files:

go
type SearchResult struct {
    Path    string  `json:"path"`
    Section string  `json:"section"`
    Snippet string  `json:"snippet"`
    Score   float64 `json:"score"`
}

ChunkSearchResult ​

Search result from the chunk index:

go
type ChunkSearchResult struct {
    ID        string
    Path      string
    StartLine int
    EndLine   int
    Text      string
    Score     float64
    Source    string // "keyword", "vector", or "hybrid"
}

HybridSearchResult ​

Merged result from hybrid search:

go
type HybridSearchResult struct {
    ID        string
    Path      string
    StartLine int
    EndLine   int
    Text      string
    Score     float64
    Source    string // "vector", "keyword", or "hybrid"
}

Example ​

go
package main

import (
    "context"
    "fmt"

    "github.com/openparallax/openparallax/memory"
)

func main() {
    // Manager: workspace memory files + FTS5 search
    mgr := memory.NewManager("/path/to/workspace", store, llmProvider)

    // Read a memory file.
    soul, _ := mgr.Read(memory.MemorySoul)
    fmt.Println(soul)

    // Append to MEMORY.md.
    mgr.Append(memory.MemoryMain, "## 2026-04-09\n- Decided to use PostgreSQL 16\n")

    // FTS5 search.
    results, _ := mgr.Search("PostgreSQL", 10)
    for _, r := range results {
        fmt.Printf("[%s] %s: %s\n", r.Path, r.Section, r.Snippet)
    }

    // Context-relevant memory for system prompt.
    chunks := mgr.SearchRelevant("database schema", 5, 5)
    for _, c := range chunks {
        fmt.Println(c)
    }

    // Indexer: chunk-based indexing with embeddings
    embedder := memory.NewEmbeddingProvider(memory.EmbeddingConfig{
        Provider:  "openai",
        Model:     "text-embedding-3-small",
        APIKeyEnv: "OPENAI_API_KEY",
    })
    vs := memory.NewBuiltinVectorSearcher()
    indexer := memory.NewIndexer(chunkStore, embedder, vs, logger)

    ctx := context.Background()
    indexer.IndexWorkspace(ctx, "/path/to/workspace")

    // Hybrid search (FTS5 + vector).
    hybrids, _ := memory.HybridSearch(ctx, chunkStore, embedder, vs, "database schema", 10)
    for _, h := range hybrids {
        fmt.Printf("[%s] %s:%d-%d (%.2f, %s)\n", h.Source, h.Path, h.StartLine, h.EndLine, h.Score, h.Source)
    }
}

Key Source Files ​

FilePurpose
memory/manager.goManager: workspace file operations, FTS5 search, session summarization
memory/indexer.goIndexer: chunk-based file indexing with embeddings
memory/search.goHybridSearch: merged vector + keyword search
memory/embedding.goEmbeddingProvider: OpenAI, Google, Ollama implementations
memory/vector.goVectorSearcher: builtin pure-Go cosine similarity
memory/types.goSearchResult, ChunkSearchResult, FileType constants
memory/store.goChunkStore interface
memory/sqlite/store.goSQLite implementation wrapping internal/storage.DB