Documentation
¶
Overview ¶
Package memfile is ogcode's per-turn markdown memory: after a turn completes, a structured summary of that turn is written as one dated markdown file under the project's .ogcode/memory/, and an incremental index of that folder lets a read-only recall agent find and read the right file cheaply.
It is the token-lean successor to the graph/embedding memory in internal/memory. The whole subsystem is gated by TurnMemoryEnabled (env OGCODE_TURN_MEMORY): off by default, so a build with these types linked in behaves exactly as before until the flag is set.
Index ¶
- Constants
- func Filename(createdAt time.Time, sessionID, title string) string
- func MemoryDir(projectDir string) string
- func TurnMemoryEnabled() bool
- func Write(projectDir string, meta Meta, body string) (string, error)
- type Entry
- type Manager
- type Meta
- type Store
- func (s *Store) IndexFile(path string, meta Meta) error
- func (s *Store) IsIndexed(path string) (bool, error)
- func (s *Store) ListByProject(projectID string) ([]*Entry, error)
- func (s *Store) ListBySession(sessionID string) ([]*Entry, error)
- func (s *Store) PurgeMissing(projectID string) error
- func (s *Store) Upsert(e *Entry) error
Constants ¶
const SummarySystemPrompt = `You are a memory scribe. You are given a digest of one completed turn between a developer and a coding agent: the developer's request, the agent's tool calls (their inputs and intent only — results are omitted), and the agent's final response.
Write a single, self-contained markdown summary of what happened in this turn, so a future agent reading only this file understands the request, what was done, and the outcome — without access to the original conversation.
STRUCTURE (this is mandatory — the summary is indexed and read by its headings):
- Begin with exactly one H1 (` + "`# `" + `) title: a short, specific noun phrase naming the turn's subject.
- Group the body under H2 (` + "`## `" + `) sections, and use H3 (` + "`### `" + `) for sub-points within a section. Never skip a level.
- Suggested sections, included only when they apply: "## Request" (what the developer asked), "## What was done" (the actions taken and why, grounded in the tool calls), "## Key files & symbols" (concrete paths / names touched or examined), "## Outcome" (the result, decisions made, and anything left open).
- Prefer short paragraphs and tight bullet lists under the deepest relevant heading. Put concrete facts — file paths, symbol names, commands, values, decisions — where they belong in the hierarchy, not in a flat wall of text.
RULES:
- Be faithful to the digest. Do not invent files, symbols, or outcomes that are not evidenced by it.
- Be concise. Capture what matters for later recall; omit filler and restated boilerplate.
- Output ONLY the markdown summary, starting with the ` + "`#`" + ` title. No preamble, no code fence around the whole thing, no trailing commentary.`
SummarySystemPrompt instructs the synthesis LLM to turn a turn's digest into a tightly-structured markdown summary. The hierarchy demand is not cosmetic: the recall agent navigates these files through the file-map outline, which is built from the heading levels — a clean H1/H2/H3 tree is what makes a lookup land on the right section and read only a handful of lines.
Variables ¶
This section is empty.
Functions ¶
func Filename ¶
Filename builds a turn summary's filename. The UTC timestamp leads so a lexical sort of the folder is chronological; a short session tag groups a conversation's turns and lets session-scoped recall filter by name; the slug makes the file recognisable at a glance. Example:
2026-09-09T143005Z--a1b2c3d4--wire-the-recall-agent.md
func MemoryDir ¶
MemoryDir returns the absolute path to a project's turn-summary folder. It does not create the directory — Write does that on demand.
func TurnMemoryEnabled ¶
func TurnMemoryEnabled() bool
TurnMemoryEnabled reports whether the per-turn markdown memory subsystem is switched on. It is the project's memory by default — a single process-wide env gate turns it OFF (OGCODE_TURN_MEMORY=0/false/off) for the rare case that wants the legacy graph route or no memory at all. Any other value, or an unset variable, leaves it on. It is deliberately env-only rather than a settings-DB field so memory does not depend on the UI toggle.
func Write ¶
Write persists a turn summary as a dated markdown file under the project's .ogcode/memory/ folder and returns its absolute path. body is the synthesized markdown (starting with its own H1); Write prepends YAML frontmatter carrying the Meta so recall can scope/attribute the file, and picks a collision-free filename.
Types ¶
type Entry ¶
type Entry struct {
Path string
SessionID string
ProjectID string
Title string
Outline string
CreatedAt int64 // unix millis; the turn's time, used for temporal ordering
IndexedAt int64 // unix millis; when this row was written
}
Entry is one indexed turn summary. path is the primary key and holds the absolute file path; outline is the rendered markdown heading tree (with line ranges) that lets recall jump straight to a section.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager is the barrier between background turn-summary work and recall. A turn summary is synthesized, written, and indexed on a detached goroutine, so a recall that fires immediately afterwards could otherwise read a stale or missing index. Recall calls Wait(project) first; the background job brackets itself with Begin/Done, so Wait blocks until the project's in-flight summaries have all landed in the index.
The counter is keyed by project so a summary in one workspace never blocks recall in another. A sync.Cond (not a per-project WaitGroup) is used because WaitGroup forbids Add concurrent with Wait — exactly the pattern here, where a new turn can begin while a recall is waiting.
func (*Manager) Begin ¶
Begin records that a background summary for project has started. Call it synchronously, before launching the goroutine, so a recall that follows the turn immediately observes the in-flight work.
type Meta ¶
type Meta struct {
SessionID string
ProjectID string
SessionType string
Title string
CreatedAt time.Time
}
Meta is the identifying context for one turn summary, carried through both the file's frontmatter and the index row so recall can scope and attribute a summary without opening its body.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the incremental index over a project's turn-summary folder. It mirrors internal/docindex: existence-keyed, one row per file. Turn summaries are immutable once written, so an existence check is a complete freshness check — a file is indexed exactly once and never re-parsed.
func (*Store) IndexFile ¶
IndexFile parses one summary file's heading outline and upserts its row. It is the incremental unit: called once for a freshly written file, it never touches any other row. meta supplies the scoping/attribution the index stores.
func (*Store) ListByProject ¶
ListByProject returns every indexed summary for a project, newest first.
func (*Store) ListBySession ¶
ListBySession returns every indexed summary for one conversation, newest first.
func (*Store) PurgeMissing ¶
PurgeMissing drops rows for a project whose files no longer exist on disk, so a deleted summary stops showing up in recall. Cheap to run: it stats one file per indexed row.