memfile

package
v0.36.1 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2026 License: MIT Imports: 9 Imported by: 0

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

View Source
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

func Filename(createdAt time.Time, sessionID, title string) string

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

func MemoryDir(projectDir string) string

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

func Write(projectDir string, meta Meta, body string) (string, error)

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 NewManager

func NewManager() *Manager

NewManager returns a ready Manager.

func (*Manager) Begin

func (m *Manager) Begin(project string)

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.

func (*Manager) Done

func (m *Manager) Done(project string)

Done records that a background summary for project has finished (file written and indexed). It wakes any waiter.

func (*Manager) Wait

func (m *Manager) Wait(project string)

Wait blocks until no background summary for project is in flight.

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 NewStore

func NewStore(database *db.DB) *Store

NewStore creates a Store backed by the given (project-local) database.

func (*Store) IndexFile

func (s *Store) IndexFile(path string, meta Meta) error

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) IsIndexed

func (s *Store) IsIndexed(path string) (bool, error)

IsIndexed reports whether a row already exists for path.

func (*Store) ListByProject

func (s *Store) ListByProject(projectID string) ([]*Entry, error)

ListByProject returns every indexed summary for a project, newest first.

func (*Store) ListBySession

func (s *Store) ListBySession(sessionID string) ([]*Entry, error)

ListBySession returns every indexed summary for one conversation, newest first.

func (*Store) PurgeMissing

func (s *Store) PurgeMissing(projectID string) error

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.

func (*Store) Upsert

func (s *Store) Upsert(e *Entry) error

Upsert inserts or replaces one index row.

Jump to

Keyboard shortcuts

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