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
- func ExtractDecisions(doc string, markers []string) []string
- type Chunk
- type Fact
- type FileRef
- type Hit
- type Layout
- func (l Layout) AppendDaily(now time.Time, stage, body string) error
- func (l Layout) DailyPath(date time.Time) string
- func (l Layout) DreamsPath() string
- func (l Layout) MemoryFiles() []string
- func (l Layout) MemoryPath() string
- func (l Layout) PromoteFacts(now time.Time, taskID string, facts []Fact) (int, error)
- func (l Layout) ReadMemory() string
- func (l Layout) TaskPath(taskID string) string
- func (l Layout) WriteTaskSummary(taskID, title, body string) error
- type Memory
- type Options
- type Recalled
- type SearchOptions
- type Stats
- type Store
- func (s *Store) AllFiles(ctx context.Context) ([]string, error)
- func (s *Store) Close() error
- func (s *Store) IndexFile(ctx context.Context, relPath string) (bool, error)
- func (s *Store) Search(ctx context.Context, query string, opts SearchOptions) ([]Hit, error)
- func (s *Store) Stats(ctx context.Context) (Stats, error)
Constants ¶
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 ¶
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 ¶
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.
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 ¶
NewLayout returns a Layout rooted at memDir and ensures all expected subdirectories exist.
func (Layout) AppendDaily ¶
AppendDaily appends a timestamped entry to today's daily log.
## HH:MM — <stage> <body>
func (Layout) DailyPath ¶
DailyPath returns the absolute path of the daily log file for the given date.
func (Layout) DreamsPath ¶
DreamsPath returns the absolute path of DREAMS.md.
func (Layout) MemoryFiles ¶
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 ¶
MemoryPath returns the absolute path of MEMORY.md.
func (Layout) PromoteFacts ¶
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 ¶
ReadMemory returns the content of MEMORY.md, or "" if missing.
func (Layout) WriteTaskSummary ¶
WriteTaskSummary writes (or overwrites) the per-task summary file.
type Memory ¶
Memory bundles a Layout and an indexed Store for ergonomic use from the rest of the codebase.
func OpenMemory ¶
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.
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 ¶
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 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 ¶
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) IndexFile ¶
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 ¶
Search runs a hybrid BM25 + (optional) cosine search.
Strategy:
- SELECT top RerankCandidates by BM25 from FTS5.
- If embedder is available, fetch their vectors, compute cosine vs the query embedding, and blend: score = α·bm25_norm + (1-α)·cosine.
- Truncate combined body to MaxChars (best-first).