memory

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 10, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package memory loads optional context files that are auto-injected into the system prompt at session start.

Layout:

~/.yottacode/USER.md                                      — global preferences (curated, human-only)
<cwd>/.yottacode/YOTTACODE.md                             — per-repo context (curated, agent-writable)
~/.yottacode/memory/<name>.md                             — user-scope agent-managed memories
~/.yottacode/projects/<project_slug>/memory/<name>.md     — project-scope agent-managed memories

USER.md and YOTTACODE.md are the trust anchor: they always inject in full. The agent-managed memory dirs are managed via the memory_save / memory_forget tools — the agent decides in-band when something is worth remembering. MEMORY.md inside each memory dir is an auto-generated index that always renders too; the per-file bodies are filtered per turn by the retrieval orchestrator (see retrieve.go).

The project_slug is derived by ProjectSlug(cwd) — see path.go.

Package memory — retrieval orchestrator.

Agent-managed memory grows over time. By v0.4 a heavy user can accumulate dozens of typed memory files; concatenating every body into the system prompt on every turn taxes both the context window and the model's attention.

This file scores each MemoryEntry against the current user prompt and returns a ranked, length-bounded subset. It deliberately does NOT touch USER.md / YOTTACODE.md — those are the trust anchor: short, curated, and always injected in full. USER.md is human-only; YOTTACODE.md is human-seeded and the agent keeps it fresh as the project evolves (parity with how Claude Code maintains CLAUDE.md).

MEMORY.md (the per-scope index) is also unfiltered — it's the table of contents, and the model needs to know what files exist even when their bodies aren't injected. Only per-entry bodies pass through Select.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EnsureProjectMemoryDir

func EnsureProjectMemoryDir(cwd string) (string, error)

EnsureProjectMemoryDir creates the project-scope memory directory.

func EnsureUserMemoryDir

func EnsureUserMemoryDir() (string, error)

EnsureUserMemoryDir creates the user-scope memory directory if missing.

func MemoryFilePath

func MemoryFilePath(scope, name, cwd string) (string, error)

MemoryFilePath validates a memory name and returns the absolute file path under the chosen scope. Scope must be "user" or "project".

func ProjectMemoryDir

func ProjectMemoryDir(cwd string) (string, error)

ProjectMemoryDir returns ~/.yottacode/projects/<slug>/memory/ — the per-project, per-user agent-managed memory directory.

func ProjectSlug

func ProjectSlug(cwd string) string

ProjectSlug returns a stable, slug-safe identifier for the project rooted at cwd. Strategy (highest-priority first):

  1. Git remote URL of `origin`. Survives renames of cwd, and is the same string across machines and clones — project memory follows the project, not the directory it happens to live in. Parsed from formats like `https://github.com/user/repo.git`, `git@github.com:user/repo.git`, `ssh://git@host/path/repo`.
  2. `filepath.Base(cwd)` slugified. Used when no git remote is configured (uncommitted scratch dir, vendored copy without git, brand-new project pre-init).

Returns "default" when both lookups fail (empty cwd, root-only path, exotic edge cases). The returned string is guaranteed to match projectSlugPattern, so callers can use it directly as a path component without further sanitization.

Two unrelated repos with the same basename and no git remote will collide. The collision is documented; users who care can either initialize a git repo (which gets them a unique remote-derived slug) or live with the merge.

func RegenerateMemoryIndex

func RegenerateMemoryIndex(scope, cwd string) error

RegenerateMemoryIndex re-scans the chosen scope's memory dir and rewrites MEMORY.md atomically. Used by memory_save and memory_forget after every mutation. If the dir is empty or missing after the mutation, MEMORY.md is removed instead of being written as an empty stub.

func RenderFrontmatter

func RenderFrontmatter(name, memType, description string, created time.Time) string

RenderFrontmatter writes the four-field header. Description is expected to already be one line (caller strips newlines before passing); the writer doesn't re-validate. Created is rendered as RFC3339 in UTC.

func RenderMemoryIndex

func RenderMemoryIndex(scope string, entries []MemoryEntry) string

RenderMemoryIndex builds the MEMORY.md text for one scope: a header, a stable preamble warning humans not to edit it, and a per-type section listing each entry as a markdown link with its description. Empty entries produce a minimal index (just the preamble) so the scanner still recognizes the file as ours.

func Score

func Score(entry MemoryEntry, query string) float64

Score returns a relevance score in [0.0, 1.0] for the given entry against the query. Pure and deterministic.

func SystemPrompt

func SystemPrompt(base string, l Loaded) string

SystemPrompt composes the base prompt with every loaded memory section. Each section is framed as background reference — not as a topic to describe.

func SystemPromptFor

func SystemPromptFor(base string, l Loaded, query string, cfg config.RetrievalConfig) string

SystemPromptFor is the per-turn variant of SystemPrompt: USER.md and YOTTACODE.md inject in full as before, both MEMORY.md indexes inject in full (they're the table of contents), and per-entry bodies pass through Select(query, cfg) first.

func UserMemoryDir

func UserMemoryDir() (string, error)

UserMemoryDir returns ~/.yottacode/memory/ — the cross-project agent-managed memory directory. Memories saved here apply to every session for this user.

Types

type Frontmatter

type Frontmatter struct {
	Name        string
	Type        string
	Description string
	Created     string
}

Frontmatter is the YAML-ish header on every agent-managed memory file. Real YAML is overkill for four flat fields — a tolerant key:value scanner keeps the writer one-line-per-field and the reader tiny.

func ParseFrontmatter

func ParseFrontmatter(data []byte) (fm Frontmatter, body string, ok bool)

ParseFrontmatter splits frontmatter from body. Returns ok=false when the frontmatter block is missing or malformed; in that case fm is zero and body equals the input. Tolerant of files written by hand (no frontmatter at all is fine — caller defaults Type to "reference" and Name to the basename).

type Loaded

type Loaded struct {
	UserPath    string
	UserText    string
	ProjectPath string // YOTTACODE.md
	ProjectText string

	// User-scope agent-managed memories.
	UserMemoryDir   string
	UserMemoryIndex string // raw MEMORY.md text (rendered if missing on disk)
	UserMemories    []MemoryEntry

	// Project-scope agent-managed memories (per ProjectSlug(cwd)).
	ProjectMemoryDir   string
	ProjectMemoryIndex string
	ProjectMemories    []MemoryEntry
}

Loaded carries the raw contents (and resolved paths) of every memory source read at session start. The two trust anchors (USER.md and YOTTACODE.md) sit alongside the user-scope and project-scope agent-managed memory directories. ProjectPath / ProjectText refer to YOTTACODE.md (the field name is historical from the YOTTACODE.md era).

func Load

func Load(cwd string) (Loaded, error)

Load reads every memory source for the session: USER.md, YOTTACODE.md, and both agent-managed memory dirs. Missing files / dirs leave the corresponding fields empty without returning an error.

func (Loaded) Summary

func (l Loaded) Summary() Summary

type MemoryEntry

type MemoryEntry struct {
	Path        string
	Scope       string // "user" | "project"
	Name        string // basename without .md
	Type        string // user | feedback | project | reference
	Description string
	Body        string
}

MemoryEntry is one parsed memory file: enough to render the prompt and the MEMORY.md index. Body is raw markdown (frontmatter stripped).

func Select

func Select(entries []MemoryEntry, query string, cfg config.RetrievalConfig) []MemoryEntry

Select ranks entries against the query and returns at most cfg.TopK with score >= cfg.MinScore.

type Scored

type Scored struct {
	Entry MemoryEntry
	Score float64
}

Scored pairs a memory entry with the relevance score the orchestrator assigned it for a particular query. Score is in [0.0, 1.0]; deterministic across runs.

type Summary

type Summary struct {
	User       bool
	Project    bool
	UserMem    int
	ProjectMem int
}

Summary is the short tag used by the TUI status bar — a human-friendly one-liner describing which memory sources are active.

func (Summary) String

func (s Summary) String() string

String renders the Summary as something compact like "USER+YOTTA" or "USER+UMEM(3)+PMEM(7)" or "" (when nothing was loaded).

Jump to

Keyboard shortcuts

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