Skip to content

RFC: Add version-aware M2 Episode memory for Agent development history #451

Description

@Anduin9527

Motivation

Libra already records Intent, Task, Run, evidence, decisions, patch sets, Agent sessions, and code commits. These objects preserve the development process, but an Agent still has to traverse several records and long sessions to explain why code changed, what was attempted, and how an earlier conclusion relates to the current code version.

This issue proposes M2 development-process memory (Episode): structured summaries compiled from Libra's existing development records and linked to their source evidence and code versions.

It should help an Agent answer:

  • Why was this code introduced or changed?
  • Which requirement, attempts, and decisions led to the current implementation?
  • What succeeded or failed in earlier work?
  • Does an earlier conclusion apply to the current code version?

Design

M2 adds two summary levels:

  • Task Episode Summary: summarizes the Runs of one Task.
  • Intent Iteration Summary: summarizes the Task Episodes of one Intent.

Task completion, failure, or cancellation can trigger a Task summary. Intent revision, completion, or cancellation can trigger an Intent summary. Successful, failed, cancelled, partial, and no-code-change attempts are all useful development history.

The compiler keeps observations and Agent inferences as separate fields. Both link back to typed source references (EvidenceRef). Code context records the base/result commit OIDs, branch, and related paths.

flowchart TB
    subgraph Facts["Existing Libra development records"]
        I[Intent] --> T[Task] --> R[Run]
        R --> E[Evidence · Decision · PatchSet]
        R --> C[Session · code OID · paths]
    end

    Facts --> W["MemoryWriter<br/>resolve sources · redact · compile"]
    W --> S["Two-level Episode memory<br/>Task Episode Summary<br/>Intent Iteration Summary"]
    S --> H["MemoryNote revisions + MemoryEvent<br/>content-addressed history"]
    H --> P["SQLite projection<br/>current revision · path index · FTS5/BM25"]
    P --> Q["Agent retrieval<br/>task · time · path · code version<br/>Top K summaries · EvidenceRef expansion"]
Loading

Record and storage model

Each Episode is stored as an episodic MemoryNote; changes create a new revision and a MemoryEvent. The standard MemoryNote envelope carries versioning, provenance, policy, and code applicability. An optional EpisodePayloadV1 carries the development summary.

MemoryNote envelope

Part Fields Role in M2
Identity schema_version, note_id, content_digest Identify the logical note, its schema, and its canonical content
Memory cell scope, namespace, path, kind, lifecycle Place the note in a stable Repo-scoped episodic cell
Visibility and policy visibility, acl_policy_id, confidence, trust, sensitivity Describe who may use the note and how strongly it is supported
Readable content body, rationale, tags Store the compact summary shown to an Agent
Provenance and relations evidence_refs, links, entities, parents Link the summary to source records, related notes, and earlier revisions
Time and code applicability valid_from, valid_until, effective_from_commit, effective_until_commit, expires_at Bind the note to business time and the relevant code history
Production record author, created_at, compile_record Record which compiler, rules, prompt, model, policy, and source fingerprints produced this revision
Episode extension episode: Option<EpisodePayloadV1> Store the structured Task or Intent development summary

EpisodePayloadV1

Field Type Meaning
schema_version integer Episode payload schema version
root_kind, root_id task | intent, object ID Identify the Task or Intent represented by the Episode
related_intent_ids, related_task_ids, related_run_ids ordered object ID lists Preserve the relationship to Libra development objects
started_at, ended_at optional timestamps Describe the development interval
goal, outcome text, enum Record the intended result and observed completion state
observations list of { claim, evidence_refs } Store facts derived from Runs, events, tools, tests, and patches
inferences list of { claim, confidence, evidence_refs } Store Agent-generated explanations, including root-cause hypotheses
decisions structured list Record choices made during the Task or Intent iteration
failed_attempts structured list Record attempted approaches and their observed results
unresolved structured list Record open questions and remaining work
code { base_oid, result_oid, branch_ref, paths } Bind the Episode to the code versions and files it describes

For a Task Episode, the related-ID lists contain its parent Intent, root Task, and contributing Runs. For an Intent Iteration, they contain the root Intent plus all contributing Tasks and Runs. The outer MemoryNote.links pins every contributing Task Episode by note_id and revision_oid, so the higher-level summary can be traced to the exact Task summaries used during compilation.

A Task or Intent maps to a stable Memory cell:

Repo / default / episodic.tasks.<task-id>
Repo / default / episodic.intents.<intent-id>

The authoritative history uses Libra's content-addressed objects and a protected Memory ref such as refs/libra/memory/repo:

refs/libra/memory/repo
├── notes/<namespace>/<note_id>/<revision_oid>.json
├── events/<event_seq>-<event_id>.json
└── manifest.json

SQLite stores the current read projection in the existing .libra/libra.db. The projection can be rebuilt from the note and event history.

SQLite organization

erDiagram
    MEMORY_PROJECTION_STATE ||--o{ MEMORY_HEAD : "tracks scope"
    MEMORY_NOTE_INDEX ||--|| MEMORY_HEAD : locates
    MEMORY_NOTE_INDEX ||--o{ MEMORY_REVISION_INDEX : has
    MEMORY_REVISION_INDEX ||--o{ MEMORY_EPISODE_PATH : indexes
    MEMORY_REVISION_INDEX ||--o| MEMORY_EPISODE_SEARCH_DOC : projects
    MEMORY_EPISODE_SEARCH_DOC ||--|| MEMORY_EPISODE_FTS : ""

    MEMORY_PROJECTION_STATE {
        string scope_key PK
        string projected_ref_oid
        int last_event_seq
    }
    MEMORY_HEAD {
        string note_id FK
        string scope_key FK
        string live_revision_oid
    }
    MEMORY_NOTE_INDEX {
        string note_id PK
        string scope_key
        string namespace
        string path
    }
    MEMORY_REVISION_INDEX {
        string revision_oid PK
        string note_id FK
        string producer
    }
    MEMORY_EPISODE_PATH {
        string note_id
        string revision_oid FK
        string code_path
    }
    MEMORY_EPISODE_SEARCH_DOC {
        int rowid PK
        string revision_oid FK
        string root_kind
        string root_id
        string outcome
        string ended_at
    }
    MEMORY_EPISODE_FTS {
        int rowid PK, FK
        string goal
        string summary
    }
Loading

The SQLite projection is organized as follows:

Table/index Key and main columns Purpose
memory_head (scope_key, namespace, path, note_id), live_revision_oid, lifecycle/review state, trust, sensitivity, code applicability, last_event_seq Resolve the current visible revision of each Memory cell
memory_note_index note_id, cell coordinates, kind, lifecycle, origin, idempotency metadata Find the stable logical note and its cell
memory_revision_index revision_oid, note_id, producer, rules/prompt/model/policy versions, input fingerprints Trace how each revision was compiled
memory_projection_state scope_key, projected_ref_oid, last_event_seq, schema_version, policy_version, rebuilt_at Record the rebuilt watermark for each Memory scope
memory_episode_path (note_id, revision_oid, code_path) Filter Episode revisions by exact or prefix-related code paths
memory_episode_search_doc integer rowid, unique (note_id, revision_oid), root kind/ID, Intent/Task IDs, outcome, start/end time, goal, summary, decisions, failures, unresolved items Provide structured filter columns and one search document for each projected Episode revision
memory_episode_fts external-content FTS5 table sharing memory_episode_search_doc.rowid Build the lexical index and expose bm25() ranking

The Episode path and search indexes advance with the generic Memory projection under the same scope watermark.

Retrieval applies structured filters for Task, Intent, time, outcome, and path; FTS5 generates lexical matches and bm25() ranks them. Git ancestry and the stored code anchors determine whether a result applies to the current code version. The Agent receives the highest-ranked summaries and can follow EvidenceRef links to the original Run, event, session fragment, patch, or decision.

FTS5 and BM25 are provided by Libra's bundled SQLite, so this design fits the current local storage model.

References

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions