Memory#
The cross-harness memory store: Markdown entries in layered roots, with indexing,
supersession, and recall. See Memory for the user guide and
gptme-util memory.
Cross-harness memory store: CC-compatible markdown entries with layered roots.
Storage depends on gptme.dirs; triggered delivery lazily adapts entries
to LessonMatcher. See gptme/gptme#3734.
- class gptme.memory.AuditIssue#
One actionable consistency problem in a memory root.
- class gptme.memory.MemoryEntry#
MemoryEntry(name: ‘str’, description: ‘str’ = ‘’, type: ‘str’ = ‘general’, body: ‘str’ = ‘’, title: ‘str | None’ = None, status: ‘str’ = ‘living’, supersedes: ‘list[str]’ = <factory>, superseded_by: ‘str | None’ = None, provenance: ‘dict[str, Any]’ = <factory>, confidence: ‘float | None’ = None, keywords: ‘list[str]’ = <factory>, recheck: ‘str | None’ = None, metadata: ‘dict[str, Any]’ = <factory>, path: ‘Path | None’ = None, scope: ‘str | None’ = None)
- __init__(name: str, description: str = '', type: str = 'general', body: str = '', title: str | None = None, status: str = 'living', supersedes: list[str] = <factory>, superseded_by: str | None = None, provenance: dict[str, Any] = <factory>, confidence: float | None = None, keywords: list[str] = <factory>, recheck: str | None = None, metadata: dict[str, Any] = <factory>, path: Path | None = None, scope: str | None = None) None#
- exception gptme.memory.MemoryFrontmatterError#
Raised when strict parsing is required but the YAML is invalid.
- exception gptme.memory.MemoryParseError#
Raised when a file is not a memory entry (no or unusable frontmatter).
- class gptme.memory.MemoryRoot#
MemoryRoot(scope: ‘str’, path: ‘Path’)
- class gptme.memory.MemoryStore#
Reads union every root (nearest layer wins on name); writes target one scope.
- __init__(roots: Iterable[MemoryRoot])#
- audit(*, scope: str | None = None) list[AuditIssue]#
Return parse and supersession consistency issues for one root.
- check_index(scope: str | None = None, *, budget: int | None = None) bool#
True when the on-disk index equals the regenerated one byte for byte.
Falls back to an unlocked read on read-only roots (same reasoning as
render_root_index).
- index_entries(scope: str | None = None) list[MemoryEntry]#
Entries that belong in the index of one physical root.
entries(scope=...)unions every root with that scope name, which would put later-directory filenames into the first directory’sMEMORY.md. Index generation is always per-directory.Policy-managed roots reference entries by filename, so every physical file must appear even when two share the same
namefield (deduplicate=False). Legacy roots keep the original deduplication behaviour to avoid emitting duplicate lines on upgrade.
- static render_index(entries: Iterable[MemoryEntry], *, budget: int | None = None) str#
Generate the always-on index: living entries grouped by type, one line each.
budgetcaps the output in bytes. Entries that do not fit — including every later type group — are replaced by one trailing line naming how many were omitted. The marker is included in the cap, so the returned text never exceedsbudget.
- render_root_index(scope: str | None = None, *, budget: int | None = None) str#
Render one root using its persistent selection and budget, if present.
Falls back to an unlocked read on read-only roots: no concurrent writer can mutate a read-only root, so the TOCTOU race is not a concern there.
- save(name: str, description: str, body: str = '', *, type: str | None = None, scope: str | None = None, title: str | None = None, metadata: dict[str, Any] | None = None, keywords: list[str] | None = None) Path#
Write an entry, preserving existing lifecycle and omitted metadata.
A policy-managed root regenerates its selected view within the stored budget, committing entry and index together. New entries remain available to recall but are not selected automatically. Legacy roots upsert living pointers and remove retired pointers, preserving unrelated index prose and committing the curated index and the entry together as well.
The root lock serialises this write against concurrent
supersedeandupdate_index_linecalls. It stays valid across index inode replacement.
- supersede(old_name: str, new_name: str, *, scope: str | None = None) tuple[MemoryEntry, MemoryEntry]#
Mark
old_namesuperseded bynew_nameand link both entries.Supersession is scoped to one root so a project memory can never mutate a same-named user memory. Strict parsing prevents the write from normalizing malformed frontmatter through the lenient read fallback. A root-scoped lock serializes concurrent supersedes so two replacements cannot both observe the same living entry and corrupt the links.
Raised when a caller forces a recall backend that is not installed.
- class gptme.memory.RecallHit#
One ranked memory entry.
- class gptme.memory.RecallResult#
Ranked hits plus the backend that actually produced them.
- gptme.memory.parse_entry(path: Path, scope: str | None = None, *, strict: bool = False) MemoryEntry#
Parse one memory file. Raises
MemoryParseErrorfor non-entries.
- gptme.memory.recall(store: MemoryStore, query: str, *, limit: int = 3, backend: RecallBackend = 'auto') RecallResult#
Recall living entries across every layered root.
autoprefers gptme-rag’s TF-IDF backend and falls back to the built-in overlap scorer only when the optional backend is unavailable. A forcedtfidfrequest fails instead of silently changing semantics.
- gptme.memory.render_recall(result: RecallResult, *, body_chars: int = 1200) str#
Render bounded context suitable for injection into another harness.
- gptme.memory.update_index_line(memory_dir: Path, entry: MemoryEntry) None#
Update a legacy pointer, or regenerate a policy-managed root’s view.
Legacy root (no .memory-index.json): upserts a
- [title](file) — descriptionpointer inMEMORY.mdfor living entries, or removes the pointer for retired entries without rewriting unrelated index prose.Policy-managed root: regenerates the full selected view from
.memory-index.json. Only the explicitly selected entries appear in the always-on index;entryis reflected only if its filename is already in the policy’sselectedlist. Direct-file writers that want their entry visible in the always-on view must add it to the policy first. This is intentional: the policy is the authoritative selection list; appending unselected pointers would bypass its byte-budget guarantee.