memory

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jun 21, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package memory implements OK's persistent memory. It mirrors Claude Code's two-layer model while honoring OK's cache-first architecture:

  • Hierarchical doc memory: AGENTS.md / OK.md files discovered from the user config dir and up the project tree, with "@path" imports. This is the analog of CLAUDE.md.
  • Auto-memory store: per-project fact files with frontmatter plus a MEMORY.md index, which the model maintains via the `remember` tool (see store.go).

All of it folds into the durable system-prompt prefix exactly once at boot (see Compose), so it rides DeepSeek's automatic prefix cache at zero per-turn cost. Mid-session changes never mutate that prefix; they take effect through the controller's transient tail-injection and fold into the prefix on the next session.

Index

Constants

View Source
const MaxMemoryEntries = 80

MaxMemoryEntries caps the number of auto-memory files per project. Beyond this limit the oldest entries are pruned on each Save AND at load time to keep the system-prompt prefix lean and prevent unbounded disk growth.

View Source
const MaxQuickNotes = 30

MaxQuickNotes caps the number of bullet entries under ## Notes in a doc-memory file. Older entries are trimmed when new ones are added beyond this limit, preventing unbounded prefix bloat.

View Source
const MaxSharedMemoryEntries = 30

MaxSharedMemoryEntries caps shared memory files. Shared memories load into every project's system prefix, so they must stay much leaner than per-project memories. Beyond this limit the oldest entries are pruned on each Save.

Variables

This section is empty.

Functions

func AppendDoc

func AppendDoc(path, note string) error

AppendDoc appends a one-line note as a bullet under a "## Notes" section in the doc-memory file at path, creating the file (and section) when absent. The note is normalised to a single line so it can't corrupt the section. This is the write side of the "#" quick-add: a plain file edit the user can later reorganise by hand.

Uses a temp-file + rename to avoid TOCTOU: concurrent quick-adds or external edits between read and write are visible as a rename failure instead of a silent overwrite.

func Compose

func Compose(base string, s *Set) string

Compose folds the memory block onto the base system prompt and returns the durable cached-prefix string. Base stays first (it is the most stable text, so it remains a valid cache prefix even when memory changes between sessions); memory follows. With no memory, base is returned unchanged.

func NewRememberTool

func NewRememberTool(store Store) tool.Tool

NewRememberTool returns the `remember` tool bound to store. A zero/disabled store yields a tool that reports the store is unavailable rather than silently dropping saves.

Types

type Memory

type Memory struct {
	Name        string // kebab-case slug; also the file stem (<name>.md)
	Description string // one-line summary used for the index and recall
	Type        Type
	Body        string // the fact itself (Markdown)
}

Memory is one stored fact.

type Options

type Options struct {
	CWD     string
	UserDir string
	Store   Store // optional: reuse an existing store instead of creating a new one
}

Options configures discovery. CWD defaults to "." and UserDir is the user config root (config.MemoryUserDir()); a "" UserDir disables user-global docs and the auto-memory store. Store, when non-zero, reuses an existing store instead of creating a new one — use this to keep the `remember` tool's handle consistent across memory refreshes.

type Scope

type Scope string

Scope labels where a doc source was discovered, so the assembled block can attribute each chunk and callers (e.g. the `#` quick-add picker) can offer meaningful targets.

const (
	ScopeUser     Scope = "user"     // ~/.config/ok/OK.md
	ScopeAncestor Scope = "ancestor" // a memory doc above the project root
	ScopeProject  Scope = "project"  // ./OK.md (committed, shared)
	ScopeLocal    Scope = "local"    // ./OK.local.md (personal, git-ignored)
)

type Set

type Set struct {
	Docs    []Source // memory docs, ascending precedence
	Store   Store    // auto-memory store (may be a zero/disabled Store)
	Index   string   // MEMORY.md contents at load time
	CWD     string   // project working dir used for discovery
	UserDir string   // user config root (may be "")
}

Set is everything memory loaded for one session: the hierarchical docs and a handle to the auto-memory store (whose index is captured at load time). It is assembled once at boot and folded into the system prompt by Compose. CWD and UserDir are retained so the controller can resolve quick-add targets without re-deriving discovery context.

func Load

func Load(opts Options) *Set

Load discovers all memory for a session: the hierarchical docs and the auto-memory index. It is best-effort and never errors — missing files just mean less memory — so boot can call it unconditionally.

On every load, the auto-memory store is compacted: oldest entries beyond MaxMemoryEntries are deleted and the index is rebuilt. This prevents unbounded growth from auto-learned entries and keeps the disk footprint small. Runs inside the ok process — not subject to sandbox file-access restrictions.

func (*Set) Block

func (s *Set) Block() string

Block renders the memory as a single Markdown section, or "" when empty. It is deterministic given the same files, which is what keeps it a stable cache prefix across sessions that don't change their memory.

func (*Set) DocPath

func (s *Set) DocPath(scope Scope) string

DocPath returns the doc-memory file a given scope writes to. To avoid splitting a project's memory across conventions, it prefers a file that already exists (AGENTS.md / CLAUDE.md, in that order); when none exists it creates the universal default (AGENTS.md / AGENTS.local.md). ScopeUser → <userDir>, ScopeLocal → <cwd> with the *.local.md names, anything else → <cwd>. Returns "" for ScopeUser when no user dir is configured.

func (*Set) Empty

func (s *Set) Empty() bool

Empty reports whether the set carries nothing to inject, so Compose can leave the base prompt byte-for-byte untouched (and the cache prefix maximal) when there is no memory at all.

func (*Set) WriteDoc

func (s *Set) WriteDoc(path, body string) (string, error)

WriteDoc overwrites a doc-memory file with body, after checking path is a recognized memory file (see allowedDocPaths). It is the save side of the desktop panel's in-place editor. The write lands on disk immediately but does NOT mutate the cache-stable system prefix — the edit folds into the prefix on the next session; to make it apply this session, the controller separately queues a turn-tail note. Returns the path written.

type Source

type Source struct {
	Path  string
	Scope Scope
	Body  string
}

Source is one loaded memory file with provenance and @import-expanded body.

type Store

type Store struct {
	Dir string // ...ok/projects/<slug>/memory
	// contains filtered or unexported fields
}

Store is the per-project auto-memory: a directory of one-fact-per-file Markdown notes with frontmatter, plus a MEMORY.md index of one line per fact. The model maintains it through the `remember` tool; the index loads into the cached system-prompt prefix at boot so the model always knows what it has saved, and reads individual facts on demand with read_file. The whole thing is plain files the user can edit by hand.

func SharedStoreFor

func SharedStoreFor(userDir string) Store

SharedStoreFor returns a Store that is NOT scoped to a specific project. Facts saved here load for every project the user runs. Use sparingly — only for truly cross-cutting knowledge (e.g. "user prefers tab indentation in every project", "global coding conventions across all projects", etc.).

Shared memories appear in the system prompt alongside project-specific memories, but are stored under ~/.config/ok/shared/memory/.

func StoreFor

func StoreFor(userDir, cwd string) Store

StoreFor resolves the auto-memory directory for a project working dir under the user config root, e.g. ~/.config/ok/projects/-Users-me-proj/memory. A "" userDir (config dir unresolvable) yields a zero Store, which all methods treat as a disabled no-op.

func (Store) Compact

func (s Store) Compact()

Compact prunes oldest entries beyond MaxMemoryEntries. When files are actually deleted, it also rebuilds the index so MEMORY.md never references missing entries. When nothing is pruned, the index is left untouched — this preserves cache stability (byte-identical system prefix) and any hand-edits the user made to MEMORY.md. Idempotent; nil store or empty dir is a no-op.

func (Store) Index

func (s Store) Index() string

Index returns the MEMORY.md contents (the per-line index of saved memories), or "" if there are none yet. This is what loads into the cached prefix.

func (Store) List

func (s Store) List() []Memory

List returns the saved memories parsed from their files, sorted by name. Used by `/memory` and the desktop memory panel. Files that fail to parse are skipped so one bad file never hides the rest.

func (Store) Path

func (s Store) Path(name string) string

Path returns the absolute file path a memory with the given name lives at.

func (Store) Save

func (s Store) Save(m Memory) (string, error)

Save writes (or overwrites) a memory file and refreshes its MEMORY.md index line. It is the single mutation entry point — the `remember` tool, the desktop editor, and any future importer all go through here so the index never drifts from the files. Returns the path written.

type Type

type Type string

Type classifies a memory, mirroring the auto-memory taxonomy.

const (
	TypeUser      Type = "user"      // who the user is: role, preferences, expertise
	TypeFeedback  Type = "feedback"  // guidance on how to work (with why + how-to-apply)
	TypeProject   Type = "project"   // ongoing work / goals / constraints not in the code
	TypeReference Type = "reference" // pointers to external resources (URLs, tickets)
)

func NormalizeType

func NormalizeType(s string) Type

NormalizeType coerces an arbitrary string to a known Type, defaulting to TypeProject so a sloppy tool argument never blocks a save.

Jump to

Keyboard shortcuts

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