memory

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package memory implements OpenClaw-style persistent project memory.

Memory is stored as plain Markdown files in the workspace:

.decsr/memory/MEMORY.md            — persistent facts/decisions (pinned)
.decsr/memory/DREAMS.md            — optional consolidated digest
.decsr/memory/daily/YYYY-MM-DD.md  — daily event log appended by the pipeline
.decsr/memory/tasks/<task-id>.md   — per-task summary

Files are indexed into a local SQLite database (.decsr/memory.db) using FTS5/BM25 for fast keyword search. When an embedder is configured the store additionally stores dense vectors for hybrid (BM25 + cosine) ranking.

The package is intentionally agnostic about which embedder backend is used; callers inject an embedder.Embedder via Open's options or leave it nil for pure BM25.

Index

Constants

View Source
const (
	// MemoryFile holds persistent facts/decisions/preferences, loaded into
	// every agent prompt verbatim. Keep it small.
	MemoryFile = "MEMORY.md"
	// DreamsFile holds (optional) consolidated digests of past daily logs.
	DreamsFile = "DREAMS.md"
	// DailyDir is the directory for date-stamped event logs.
	DailyDir = "daily"
	// TasksDir is the directory for per-task summaries.
	TasksDir = "tasks"
)

Workspace memory directory layout (relative to .decsr/memory).

Variables

This section is empty.

Functions

func ExtractDecisions

func ExtractDecisions(doc string, markers []string) []string

ExtractDecisions parses a Markdown document and returns bullet items under any heading whose title contains one of the markers (case-insensitive). Bullet items are recognised as lines starting with "-", "*", or "1." etc.

Types

type Chunk

type Chunk struct {
	Ord       int    // 0-based order within the file
	StartLine int    // 1-based start line in the source file
	EndLine   int    // 1-based end line, inclusive
	Tokens    int    // estimated token count
	Body      string // verbatim content
}

Chunk is a slice of a Markdown file ready to be indexed.

func ChunkMarkdown

func ChunkMarkdown(content string, sizeTokens, overlapTokens int) []Chunk

ChunkMarkdown splits content into chunks of approximately sizeTokens with overlapTokens overlap between successive chunks. The splitter prefers heading boundaries (`#`, `##`, ...) and falls back to a sliding window when a single segment is larger than sizeTokens.

Mirrors the OpenClaw chunking strategy: 400-token chunks with 80-token overlap by default.

type Fact

type Fact struct {
	Source string // e.g. "architecture.md#Decisions"
	Text   string // single line of decision/fact
}

Fact represents a single line/bullet promoted to MEMORY.md.

type FileRef

type FileRef struct {
	// Path is the workspace-relative path to the memory file
	// (e.g. "MEMORY.md", "daily/2026-05-19.md").
	Path string
}

FileRef identifies a memory file by workspace-relative path.

type Hit

type Hit struct {
	File      string // workspace-relative path
	StartLine int
	EndLine   int
	Score     float64 // hybrid score (higher = better)
	BM25      float64
	Cosine    float64
	Body      string
}

Hit is a single search result.

func (Hit) String

func (h Hit) String() string

String formats a hit for debug output.

type Layout

type Layout struct {
	// Root is the absolute path to the memory directory (e.g.
	// "/path/to/repo/.decsr/memory").
	Root string
}

Layout describes where memory lives on disk for a single workspace.

func NewLayout

func NewLayout(memDir string) (Layout, error)

NewLayout returns a Layout rooted at memDir and ensures all expected subdirectories exist.

func (Layout) AppendDaily

func (l Layout) AppendDaily(now time.Time, stage, body string) error

AppendDaily appends a timestamped entry to today's daily log.

## HH:MM — <stage>

<body>

func (Layout) DailyPath

func (l Layout) DailyPath(date time.Time) string

DailyPath returns the absolute path of the daily log file for the given date.

func (Layout) DreamsPath

func (l Layout) DreamsPath() string

DreamsPath returns the absolute path of DREAMS.md.

func (Layout) MemoryFiles

func (l Layout) MemoryFiles() []string

MemoryFiles lists every memory file (relative to Root) currently on disk. Order is deterministic: MEMORY.md, DREAMS.md, daily/* sorted desc, tasks/* sorted.

func (Layout) MemoryPath

func (l Layout) MemoryPath() string

MemoryPath returns the absolute path of MEMORY.md.

func (Layout) PromoteFacts

func (l Layout) PromoteFacts(now time.Time, taskID string, facts []Fact) (int, error)

PromoteFacts appends facts to MEMORY.md under a dated heading, skipping any fact whose sha256 hash is already present in the file. Returns the number of newly written facts.

func (Layout) ReadMemory

func (l Layout) ReadMemory() string

ReadMemory returns the content of MEMORY.md, or "" if missing.

func (Layout) TaskPath

func (l Layout) TaskPath(taskID string) string

TaskPath returns the absolute path of the per-task summary file.

func (Layout) WriteTaskSummary

func (l Layout) WriteTaskSummary(taskID, title, body string) error

WriteTaskSummary writes (or overwrites) the per-task summary file.

type Memory

type Memory struct {
	Layout Layout
	Store  *Store
}

Memory bundles a Layout and an indexed Store for ergonomic use from the rest of the codebase.

func OpenMemory

func OpenMemory(ctx context.Context, memDir, dbPath string, opts Options) (*Memory, error)

Open prepares the memory subsystem for memDir: ensures the layout exists, opens the SQLite store at dbPath, and reindexes any file whose hash has changed since the last open. Returns a Memory ready for Recall/AppendDaily.

func (*Memory) Close

func (m *Memory) Close() error

Close releases the underlying store.

func (*Memory) Recall

func (m *Memory) Recall(ctx context.Context, query string, opts SearchOptions, pinnedCap int) (Recalled, error)

Recall builds a context payload for an agent: pinned MEMORY.md plus search hits relevant to query. pinnedCap caps the pinned section in chars.

func (*Memory) Reindex

func (m *Memory) Reindex(ctx context.Context) error

Reindex walks every memory file on disk and re-indexes anything stale. Also drops index entries for files that have been deleted on disk.

type Options

type Options struct {
	// Embedder is optional. When non-nil, Store computes and persists dense
	// vectors for every chunk and Search can perform hybrid ranking.
	Embedder embedder.Embedder
	// ChunkTokens is the target chunk size in tokens (default 400).
	ChunkTokens int
	// OverlapTokens is the overlap between chunks (default 80).
	OverlapTokens int
}

Options configure Open.

type Recalled

type Recalled struct {
	// Pinned is the verbatim content of MEMORY.md (truncated to PinnedCap).
	Pinned string
	// Hits are search results from the rest of the memory corpus.
	Hits []Hit
}

Recalled bundles everything an agent needs to know about the project from past work. Construct via (*Memory).Recall.

func (Recalled) PromptFragment

func (r Recalled) PromptFragment() string

PromptFragment renders Recalled as a Markdown section ready to be appended to an agent system prompt. Returns "" if there is nothing to inject.

type SearchOptions

type SearchOptions struct {
	K                int     // top results to return (default 8)
	HybridAlpha      float64 // weight of BM25 vs cosine; 1.0 = pure BM25, 0 = pure cosine (zero value; only out-of-range values default to 0.5)
	MaxChars         int     // total body chars across results (0 = unlimited)
	RerankCandidates int     // how many BM25 candidates to rerank by cosine (default 4*K)
}

SearchOptions tunes a search query.

type Stats

type Stats struct {
	Files      int
	Chunks     int
	Embeddings int
}

Stats reports basic counts for diagnostics.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is the persistent FTS5/BM25 (+ optional vector) index over Markdown memory files in a single workspace.

func Open

func Open(dbPath, memDir string, opts Options) (*Store, error)

Open opens (creating if necessary) the SQLite database at dbPath. memDir is the workspace memory root (used to resolve relative paths during reindex).

func (*Store) AllFiles

func (s *Store) AllFiles(ctx context.Context) ([]string, error)

AllFiles returns every memory file currently indexed.

func (*Store) Close

func (s *Store) Close() error

Close releases the underlying database handle.

func (*Store) IndexFile

func (s *Store) IndexFile(ctx context.Context, relPath string) (bool, error)

IndexFile reindexes a single memory file. relPath is workspace-memory-root relative (e.g. "MEMORY.md", "daily/2026-05-19.md"). Returns true if the file was (re)indexed, false if it was already up-to-date.

func (*Store) Search

func (s *Store) Search(ctx context.Context, query string, opts SearchOptions) ([]Hit, error)

Search runs a hybrid BM25 + (optional) cosine search.

Strategy:

  1. SELECT top RerankCandidates by BM25 from FTS5.
  2. If embedder is available, fetch their vectors, compute cosine vs the query embedding, and blend: score = α·bm25_norm + (1-α)·cosine.
  3. Truncate combined body to MaxChars (best-first).

func (*Store) Stats

func (s *Store) Stats(ctx context.Context) (Stats, error)

Stats reports basic counts for diagnostics.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL