memory

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2026 License: AGPL-3.0 Imports: 19 Imported by: 0

Documentation

Overview

Package memory implements durable agent memory: project-scoped and org-scoped entries with a strict Markdown format. Storage is SQLite by default, with an in-memory backend for tests and ephemeral sessions.

One entry is one row; the content column holds the rendered Markdown. The format is the contract: clean, tidy, concrete entries with a title, a short summary, what worked, what did not work, and why. Agents write entries through the memory_save and memory_search tools; humans can read the same Markdown directly.

Index

Constants

View Source
const (
	BackendMemory = "memory"
	BackendSQLite = "sqlite"
)

Backend names.

View Source
const (
	DefaultMaxEntries       = 500
	DefaultMaxSearchResults = 8
)

Store defaults.

View Source
const CoreTierCap = 24

CoreTierCap bounds the number of "core" entries per (scope, org) bucket (decision 1: 24 rows, sized to keep the auto-injected block small).

View Source
const (
	DefaultMaxEntryBytes = 8192
)

Limits defaults. The rendered template stays small by design: a memory is a digest of a learning, not a document.

Variables

View Source
var ErrCoreTierFull = fmt.Errorf("memory: core tier is full (max %d entries); merge or archive an existing core entry first", CoreTierCap)

ErrCoreTierFull is returned by PromoteToCore when the target (scope, org) bucket already holds CoreTierCap core entries.

View Source
var ErrDumpUnsupported = errors.New("memory: dump is only supported for the sqlite backend")

ErrDumpUnsupported is returned by Dump for a non-sqlite-backed Store.

View Source
var ErrEntryNotFound = errors.New("memory: entry not found")

ErrEntryNotFound is returned by PromoteToCore when no entry with the given id exists in any store this Store has access to.

Functions

func Dump

func Dump(store Store, w io.Writer) error

Dump writes store's rows as deterministic JSONL to w (D5). Only the sqlite backend supports it - dump exists to make a committed .mivia/memory.db reviewable, and the in-memory backend has nothing committed to review. store must be a value returned by Open with Backend: BackendSQLite; any other Store returns ErrDumpUnsupported.

func NormalizeOrgID

func NormalizeOrgID(s string) (string, error)

NormalizeOrgID validates and normalizes a user-supplied org identity.

The identity is a plain string column in the org store; it never becomes a filesystem path. It may contain letters, digits, dots, hyphens, underscores and slashes (host/org), is case-insensitive, and is stored lowercase.

Types

type Config

type Config struct {
	// Backend is "memory" or "sqlite". Empty defaults to "sqlite".
	Backend string
	// ProjectPath is the project memory database file. Required for sqlite.
	// A repo owner may point it at a tracked path and commit memories with
	// the repository.
	ProjectPath string
	// OrgPath is the user-level org memory database file. Optional; without
	// it org scope is unavailable.
	OrgPath string
	// OrgID is the user-owned org identity. Empty means org scope is
	// unavailable. It must come from the user config, never from a workspace
	// file: a workspace config is repo-controlled and must not name the org
	// store its agents write into.
	OrgID string
	// MaxEntryBytes caps one rendered entry. Default 8192.
	MaxEntryBytes int
	// MaxEntries caps the row count per store file. Default 500.
	MaxEntries int
	// MaxSearchResults caps search results. Default 8.
	MaxSearchResults int
	// BlockPatterns are regexes; matching content is refused at save.
	BlockPatterns []string
	// ReadOnly opens the store without writing the database file: open skips
	// the journal_mode(WAL) switch, the schema CREATE, and the FTS5 rebuild
	// backfill; Close skips the WAL checkpoint; Save is refused. Search
	// works via the LIKE fallback with identical results; the file must
	// already exist with the schema. Zero value false = read-write.
	ReadOnly bool
	// HardenTempStore marks ProjectPath as an ad-hoc, OS-temp-dir-backed store
	// (config.TempStorePath) rather than an operator-managed project path.
	// When true, openSQLiteStore chmods the project database file to 0600 and
	// its parent directory to 0700, failing closed on error, the same way the
	// org store is always hardened: an ad-hoc temp-dir store has no project
	// directory whose permissions an operator manages, so mivia must protect
	// it itself.
	HardenTempStore bool
}

Config selects the backend and bounds.

type Entry

type Entry struct {
	Title      string
	Scope      Scope
	Verdict    Verdict
	Tags       []string
	Created    string // YYYY-MM-DD; empty means "today" at save time
	Summary    string
	Good       string
	Bad        string
	Why        string
	References []string
}

Entry is one memory. Render produces the stored Markdown; Parse reads it back tolerantly.

func Parse

func Parse(data []byte) (Entry, error)

Parse reads a stored or hand-edited memory document back into an Entry. It is tolerant: missing sections become empty fields, unknown header keys and extra lines are ignored. It never panics.

func (Entry) Clamp

func (e Entry) Clamp() Entry

Clamp returns a copy of e with every free-text field truncated to its rune limit, so a save never fails on an over-length field. It is the lenient counterpart to Validate: agents routinely over-shoot the summary (400), why (1000), title (120), and body (2000) limits, and a hard rejection just makes them retry the same long text. Clamp keeps the leading content (the most informative part) and drops the tail. It never changes scope, verdict, tags, or references, and it never makes a field empty that was non-empty.

func (Entry) Render

func (e Entry) Render() string

Render returns the stored Markdown for the entry. Callers validate first; Render itself never fails and always emits the strict template.

func (Entry) Validate

func (e Entry) Validate(lim Limits) error

Validate checks the entry against the limits. It refuses control characters (except LF and TAB), oversized fields, an oversized rendered size, malformed metadata, and content that matches a block pattern.

type Limits

type Limits struct {
	// MaxEntryBytes caps the rendered entry size. Default 8192.
	MaxEntryBytes int
	// BlockPatterns are regexes; content matching any of them is refused.
	// Configuration-only, like the privacy redaction patterns: nothing is
	// compiled into the binary.
	BlockPatterns []string
}

Limits bounds one entry. Zero values use the defaults.

type Query

type Query struct {
	Text       string
	Scope      Scope // ScopeProject, ScopeOrg, or ScopeAll
	MaxResults int   // 0 uses the store default
}

Query is a search request.

type Result

type Result struct {
	ID      string
	Scope   Scope
	Org     string
	Title   string
	Verdict Verdict
	Tags    []string
	Created string
	Snippet string
}

Result is one search hit.

type Scope

type Scope string

Scope is the visibility scope of a memory.

const (
	// ScopeProject scopes a memory to one workspace. The project store is a
	// per-workspace database, so it never leaks into other projects.
	ScopeProject Scope = "project"
	// ScopeOrg scopes a memory to the configured org. The org store is a
	// user-level database shared by every project of that org on this machine.
	ScopeOrg Scope = "org"
	// ScopeAll selects both scopes in a search.
	ScopeAll Scope = "all"
)

type Store

type Store interface {
	// Save validates and stores one entry. An identical re-save is
	// idempotent: it returns the existing result and stores no duplicate.
	// Save never sets tier: every entry it writes lands as "archive" (the
	// schema default). Promotion to "core" is a separate, operator-facing
	// action (PromoteToCore) - not reachable from Save, by design (D1a).
	Save(ctx context.Context, e Entry) (Result, error)
	// Search returns up to the configured limit ranked matches. ScopeAll
	// merges project and org results. Org scope without a configured org
	// identity returns an empty result, never an error.
	Search(ctx context.Context, q Query) ([]Result, error)
	// Count returns the number of stored entries for one scope.
	Count(ctx context.Context, scope Scope) (int, error)
	// PromoteToCore marks one existing entry (by id) as tier "core", subject
	// to CoreTierCap per (scope, org). Promoting an already-core entry is a
	// no-op. Returns ErrEntryNotFound if no entry with that id exists, or
	// ErrCoreTierFull if the bucket is already at CoreTierCap.
	PromoteToCore(ctx context.Context, id string) error
	// CoreEntries returns up to CoreTierCap "core"-tier entries for scope,
	// ordered by created DESC, title ASC, id ASC (the same tie-break Search
	// uses). Not a search - no query text, just the current core set. Used
	// to build the auto-injected system-prompt block (D1).
	CoreEntries(ctx context.Context, scope Scope) ([]Result, error)
	// Delete removes one entry (by id) from whichever store this Store has
	// access to (project, then org). Returns ErrEntryNotFound if no entry
	// with that id exists in any store. Refused on a read-only store.
	Delete(ctx context.Context, id string) error
	Close() error
}

Store is the durable memory backend. Implementations must be safe for concurrent use: subagents share one store per session.

func Open

func Open(cfg Config) (Store, error)

Open returns a Store for cfg.

type Verdict

type Verdict string

Verdict is the agent's assessment of the recorded experience.

const (
	VerdictGood    Verdict = "good"
	VerdictBad     Verdict = "bad"
	VerdictMixed   Verdict = "mixed"
	VerdictNeutral Verdict = "neutral"
)

Jump to

Keyboard shortcuts

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