Open Specification · v2.1 · March 2026

The Engram Specification

An open standard for persistent AI agent memory. Engrams are atomic units of learned knowledge — individually addressable, activation-weighted, and decay-aware. They give agents the ability to remember corrections, learn preferences, and improve over time. This document specifies the data format, activation model, feedback loop, and search pipeline so that anyone can implement compatible agent memory.

Introduction

AI agents are stateless by default. Every session starts from zero — no memory of corrections, no recall of preferences, no knowledge of what tools exist. Users repeat themselves. Agents make the same mistakes. The problem is not intelligence but amnesia.

An engram is the smallest unit of persistent memory. The term comes from neuroscience — Richard Semon's 1904 hypothesis that experiences leave physical traces (engrams) in the brain. We borrow the concept: each engram is a single learned fact, correction, preference, or behavioral pattern that an agent can recall and apply.

The engram model draws on three lines of cognitive science research:

This is an open standard. The specification defines the data format and behavioral model — not a specific implementation. Any agent framework can implement engram-compatible memory. PLUR is one implementation; there should be others.

The benchmark results demonstrate that agents with engram memory outperform stateless agents in 31 of 35 decided contests (89%), with the strongest gains in convention adherence (12–0) and tool discoverability (10–2). The engram specification explains the data structures and algorithms behind those results.

Engram schema

An engram is a YAML object with a fixed set of fields. Every field has a defined type, default value, and purpose. The schema is designed to be human-readable (YAML, not binary), individually addressable (unique ID per engram), and self-describing (each engram carries its own metadata).

# A complete engram example (v2.1)
- id: ENG-2026-0131-001
  version: 2
  status: active
  type: behavioral
  scope: agent:dip-preparer
  visibility: private
  polarity: do
  statement: |
    Validate org-mode syntax before writing to .org files.
    Three incidents of malformed entries in January 2026 caused
    data loss. Always parse and validate before write.
  rationale: "Three incidents of malformed entries in January 2026."
  contraindications: ["Quick scratch notes that won't be parsed"]
  tags: [org-mode, validation]
  domain: "gtd/org-mode"
  activation:
    retrieval_strength: 0.85
    storage_strength: 0.6
    frequency: 5
    last_accessed: 2026-01-30
  entities:
    - name: org-mode
      type: technology
  temporal:
    learned_at: 2026-01-31
  episodic:
    emotional_weight: 8
    confidence: 9
    trigger_context: "Data loss from malformed org entries"
  usage:
    injections: 12
    hits: 8
    misses: 4
    last_hit_at: 2026-03-28
  associations:
    - target: "ENG-2026-0302-001"
      strength: 0.8
      type: semantic
  source: "user/personal"
  feedback_signals: {positive: 3, negative: 0, neutral: 2}

Core fields

Field Type Description
id string Unique identifier. Format: ENG-YYYY-MMDD-NNN. Prefixes: ENG (standard), ABS (abstract), META (meta-engram)
version integer Schema version (currently 2.1)
status enum active | dormant | retired | candidate
type enum behavioral | terminological | procedural | architectural
scope string Hierarchical namespace: agent:X | command:X | global | space:X
statement string The learned knowledge, written as actionable guidance (25–60 words)
rationale string Why this engram exists — the incident or pattern that prompted it
tags string[] Freeform tags for keyword matching during retrieval
visibility enum private | public | template. Default: private
domain string SKOS-style hierarchical domain (e.g., gtd/org-mode, dev/typescript)
contraindications string[] When this engram should not be applied
polarity enum | null do (directive) | dont (prohibition) | null (unclassified)
consolidated boolean Whether this engram survived reconsolidation. Default: false

Engram types

The type field classifies the kind of knowledge an engram encodes. This affects how agents apply it and how it surfaces during retrieval.

Type Description Example
behavioral How to act — preferences, corrections, habits "Validate org-mode syntax before writing to .org files"
terminological Definitions, naming, factual knowledge "The API returns snake_case, not camelCase"
procedural Step-by-step processes and workflows "Deploy via git pull then systemctl restart"
architectural System design, conventions, structural patterns "Tags use :colon: format in org-mode, #hash in PKM"

Activation fields

The activation block tracks how an engram decays and strengthens over time. These fields drive the ACT-R-inspired retrieval model described in the next section.

Field Type Description
retrieval_strength 0.0–1.0 How easily the engram can be recalled. Decays over time, increases on access.
storage_strength 0.0–1.0 How deeply encoded the engram is. Only increases (reinforcement, consolidation).
frequency integer Total number of times this engram has been accessed (injected, referenced).
last_accessed date When the engram was last injected into an agent session.

Associations

Engrams are connected to each other via weighted, typed links. These links form the graph structure that enables spreading activation during retrieval — finding related engrams that weren't directly matched by keyword search.

associations:
  - target: "ENG-2026-0302-001"
    strength: 0.8        # [0, 0.95]
    type: semantic      # semantic | temporal | causal | co_accessed

Strength is capped at 0.95. The co_accessed type is learned automatically: when two engrams are recalled together, their association strengthens by +0.05 (created at 0.3 for new pairs, max 5 co-access edges per engram). Co-access edges are bidirectional and only form between the top half of recall results. All co_accessed associations decay via exponential decay (lambda=0.01, floor=0.02).

Entities NEW IN v2.1

Typed entity references extracted from the engram statement. Enables graph queries across the knowledge base — find all engrams mentioning a person, technology, or project.

Field Type Description
entities[].name string Entity name
entities[].type enum person | organization | technology | concept | project | tool | place | event | standard | other
entities[].uri URL Optional canonical URI for the entity

Temporal anchoring NEW IN v2.1

Bi-temporal validity model inspired by Zep's temporal knowledge graph. Tracks when knowledge was learned and when it is valid — enabling time-scoped queries and automatic expiration.

Field Type Description
temporal.learned_at ISO date When the knowledge was acquired
temporal.valid_from ISO date When this knowledge becomes valid (optional)
temporal.valid_until ISO date When this knowledge expires (optional)

Episodic context NEW IN v2.1

Episodic memory fields capture the emotional significance and confidence level of a learning. Higher emotional weight slows decay — painful lessons persist longer.

Field Type Description
episodic.emotional_weight 1–10 Significance of this learning. Higher = slower decay. Default: 5
episodic.confidence 1–10 How certain this pattern holds. Affects injection priority. Default: 5
episodic.trigger_context string What situation prompted this learning
episodic.journal_ref string Reference to the journal entry where this was learned

Usage tracking NEW IN v2.1

Automatic hit/miss tracking for injection quality. Every time an engram is injected, the system records whether it was actually useful (hit) or irrelevant (miss). This data drives injection scoring over time.

Field Type Description
usage.injections integer Total times injected into agent sessions
usage.hits integer Times the injection was useful (positive feedback)
usage.misses integer Times the injection was irrelevant (negative feedback)
usage.last_hit_at ISO date When the last positive hit occurred

Exchange metadata NEW IN v2.1

Marketplace fitness metrics for engrams shared via the exchange protocol. Tracks how well an engram performs across different environments and users.

Field Type Description
exchange.fitness_score 0.0–1.0 Overall fitness for sharing (higher = more universally useful)
exchange.environmental_diversity integer Number of distinct environments where this engram is active
exchange.adoption_count integer How many users have installed this engram
exchange.contradiction_rate 0.0–1.0 How often this engram conflicts with local knowledge

Lineage & provenance

Field Type Description
source string Origin identifier (e.g., user/personal)
derivation_count integer How many times this pattern was independently captured. Default: 1
pack string | null Pack this engram belongs to (if installed from a pack)
abstract string | null ID of the abstract engram this was derived from
derived_from string | null ID of the parent engram this was derived from
feedback_signals object Counters: {positive, negative, neutral}

Structured data & extensibility NEW IN v2.1

The structured_data field is an open key-value map for domain-specific extensions. Meta-engrams use structured_data.meta to store structural templates, evidence chains, and falsification criteria. Other domains can add their own namespaced fields without modifying the core schema.

Engrams with high derivation_count are the most valuable — patterns independently re-derived across sessions represent convergent evolution. If three separate sessions captured the same insight, it is almost certainly important.

Episodes

While engrams store learned knowledge (assertions that persist and decay), episodes store events — timestamped records of what happened. Episodes answer "how did we fix this last time?" and "what happened on Tuesday?" They complement engrams the way a journal complements a reference library.

An episode is a YAML object with these fields:

Field Type Description
id string Unique identifier. Format: EP-YYYY-MMDD-NNN
timestamp ISO datetime When the event occurred
summary string What happened — a resolution, incident, decision, or milestone
agent string Which agent recorded this (e.g., claude-code, openclaw, hermes)
channel string Where it happened (e.g., terminal, telegram, slack)
session_id string Links episodes within the same work session

Episodes are stored in episodes.yaml alongside engrams.yaml. They are append-only — no decay, no activation model. Query by time range, agent, channel, or free text.

Engrams and episodes serve different purposes: engrams are knowledge (assertions the agent should remember), episodes are history (events the agent can reference). A typical session creates both: engrams from corrections, episodes from resolutions.

Activation model

The activation model determines which engrams are injected into an agent session and which are left dormant. It is inspired by ACT-R's base-level learning equation: memory items that are accessed frequently and recently have higher activation.

Retrieval strength decay

An engram's retrieval_strength decays over time based on days since last access. This implements Ebbinghaus's forgetting curve — without reinforcement, memories fade.

The emotional_weight field modifies the decay rate. Painful or significant lessons persist longer:

effective_decay = base_decay × (1 - emotional_weight / 20)

An engram with emotional_weight = 10 decays at half the normal rate. An engram with the default weight of 5 decays at 75% of the base rate.

Emotional weight also affects injection scoring as a multiplier: 1 + (emotional_weight - 5) × 0.04, mapping the [1,10] range to [0.84, 1.20]. This means emotionally significant memories are both slower to decay and more likely to be injected when relevant — a ±20% swing at extremes, neutral at the default of 5.

Activation thresholds

Retrieval strength determines an engram's lifecycle status and whether it gets injected into agent context:

Retrieval strength Status Effect
> 0.5 Active Injected into agent sessions when relevant
0.3 – 0.5 Fading Injected only if context budget allows
0.1 – 0.3 Dormant Retained in storage, not injected
< 0.1 Retirement candidate Flagged for review — retire or reinforce

Reinforcement

When an engram is accessed — injected into an agent session, referenced during review, or explicitly reinforced by the user — its retrieval_strength increases and frequency increments. The storage_strength only increases, never decreases, representing the depth of encoding.

Reconsolidation

When a new learning contradicts an existing engram, both surface as a pair during review. The user resolves the contradiction — keep one, merge them, or mark both as valid in different contexts. The survivor gains consolidated: true and a 2x storage_strength boost, making it more resistant to future decay.

Forgetting is not failure — it is curation. An unbounded memory that retains everything becomes a search problem worse than having no memory at all. The activation model ensures that frequently useful knowledge stays accessible while irrelevant knowledge gracefully fades.

Feedback loop

Engrams improve through use. Every session generates feedback signals that train the system on what to inject next time. This is the core learning loop that makes memory better over time, not just bigger.

Session lifecycle

1. session.start(task_description)
   # Agent describes what it's working on
   # System injects relevant engrams based on task + scope
2. work
   # Agent performs tasks with engram context loaded
   # New patterns captured as raw observations
3. feedback(engram_id, signal)
   # Agent or user rates injected engrams: positive | negative | neutral
   # Positive: engram was useful for this task
   # Negative: engram was irrelevant or misleading
4. learn(statement, type, scope)
   # Capture new knowledge discovered during work
   # Creates candidate engram for review
5. session.end(summary)
   # Co-access associations updated (Hebbian learning)
   # Decay recalculated for all engrams

Relevance scoring

Feedback signals directly affect future injection priority. An engram with consistently positive feedback scores higher during retrieval. An engram with negative feedback is deprioritized — even if its retrieval strength is high.

Signal Effect on retrieval When to use
Positive Boost Engram directly helped with the task
Neutral No change Engram was present but neither helped nor hurt
Negative Penalize Engram was irrelevant or misleading for this context

Promotion pipeline

Not every observation becomes an engram. Raw patterns go through a quality gate pipeline before promotion:

Expected pass rate is 30–50% of raw patterns. If consistently above 50%, the gates are too loose. Below 30%, too strict.

Lifecycle events

Every engram lifecycle change is logged to monthly JSONL files (history/YYYY-MM.jsonl). This creates an auditable trail for reporting, team dashboards, and the structural upgrade recommendations pipeline.

Event When fired
engram_created New engram added via learn()
engram_updated Engram content or activation modified (includes decay transitions)
engram_merged Two engrams consolidated into one during review
engram_retired Engram removed via forget()
engram_promoted Candidate engram approved and activated
feedback_received Positive, negative, or neutral signal recorded
recurrence_detected A new learning matches an existing engram (duplicate prevented, strength bumped)
contradiction_detected A new learning conflicts with an existing engram (flagged for reconsolidation)
scope_promoted Project-scoped engram promoted to global (appeared in multiple projects)
buffer_pruned Raw learning file entries removed after engram promotion
weekly_review Batch decay run, escalation analysis, and health metrics computed

Similarity search

similaritySearch() returns cosine similarity scores alongside engrams, enabling automated dedup classification. Scores are clamped to [0, 1]. Thresholds: > 0.9 = duplicate, 0.7 – 0.9 = related, < 0.7 = new knowledge.

Batch decay

batchDecay() applies ACT-R exponential decay to all primary store engrams. Emotional weight slows decay for painful lessons. Scope-matched engrams are immune (returning to a project after months gives full memory). Status transitions are logged to the event history.

Search pipeline

When an agent starts a session, the system must find the most relevant engrams from potentially thousands of candidates. The search pipeline combines keyword matching, semantic similarity, and graph traversal to surface the right knowledge.

Enriched schema text

Before indexing, each engram is expanded into a searchable text representation that includes fields beyond the statement:

# What gets indexed for search
searchable_text =
  statement
  + entities (extracted from statement)
  + temporal validity markers
  + rationale
  + tags (space-separated)
  + domain
  + knowledge anchor snippets

This enrichment means a search for "trading" will find engrams whose statement doesn't mention trading but whose domain is trading/risk or whose anchor snippet references a trading journal entry.

Hybrid retrieval: BM25 + embedding + RRF

The search pipeline uses two retrieval strategies and fuses their results:

BM25 (keyword)

Full BM25 with IDF weighting, term frequency saturation (k1=1.2), and document length normalization (b=0.75). Runs in-process over enriched engram text. Fast, exact, and good at matching specific identifiers like server names or tool names. Zero external dependencies.

Embedding (semantic)

Dense vector search using BGE embeddings. Finds conceptually related engrams even when keywords don't overlap. "Deploy to production" matches "push to live server."

Results from both strategies are fused using Reciprocal Rank Fusion (RRF) — a parameter-free method that combines ranked lists without needing score normalization. Each result's final score is:

RRF(d) = Σ 1 / (k + ranki(d))

Where k is a constant (typically 60) and ranki is the document's position in each retrieval strategy's results. Documents that rank highly in both keyword and semantic search surface to the top.

This is a zero-cost hybrid search. BM25 runs on SQLite (already present for storage). Embeddings are generated locally using a small model. No external API calls, no cloud dependencies, no per-query costs. The entire search pipeline runs on the user's machine.

Injection scoring

After retrieval, engrams are scored for injection priority using a composite formula:

Score = keyword_match        # [0, 10] normalized relevance
      + anchor_boost        # [0, 2] keyword overlap with anchor snippets
      + schema_boost        # [0, 2] other schema members are activated

The top-scoring engrams are selected as directives (up to 10, within a token budget). Next-best become consider items (up to 5). Finally, a spreading activation pass traverses the association graph to discover related engrams not matched by search:

spread_score = (source_score / max_first_pass) × association_strength

This adds up to 3 more engrams from the association graph. Combined ceiling: 18 engrams per injection (10 directives + 5 consider + 3 spreading).

Implementation notes

The engram specification is deliberately storage-agnostic, but we document the reference implementation choices for implementors.

Storage format

Engrams are stored as YAML arrays in flat files. One file per scope or space. YAML was chosen over SQLite or JSON for three reasons: human-readability (engrams should be editable by hand), git-friendliness (meaningful diffs), and simplicity (no database driver required).

# File: .plur/engrams.yaml (or .datacore/learning/engrams.yaml)
- id: ENG-2026-0131-001
  statement: "Validate org-mode syntax before writing..."
  # ... full engram fields
- id: ENG-2026-0201-001
  statement: "Always rsync --dry-run first..."
  # ...

Search index

The YAML files are the source of truth. BM25 search runs in-process over engram text — no database required for the default search path. An optional SQLite database can serve as a read index for faster filtered queries at scale (enable with index: true in config). The SQLite index is rebuilt from YAML on demand. If the .db file is lost or corrupted, it is regenerated from the YAML files with zero data loss.

Tool interface

Implementations expose engram operations through whatever tool protocol their agent framework supports. The reference implementation uses MCP (Model Context Protocol). The core operations:

Operation Description
plur.learn Create a candidate engram from a statement, type, and scope
plur.recall Search engrams by keyword or semantic similarity
plur.inject Context-aware injection at session start (returns directives + consider)
plur.feedback Rate an injected engram: positive, negative, or neutral
plur.forget Retire an engram (sets status to retired)
plur.capture Record a timestamped episode (incident, resolution, session event)
plur.timeline Query episode history by time range, agent, or channel
plur.compact Remove retired engrams from storage
plur.session.start Begin a session — describes task, triggers injection
plur.session.end End a session — updates co-access associations, runs decay
plur.sync Sync engrams across machines via git
plur.status Memory health check — counts, scores, decay status

Safety

Implementations should scan engram statements for secrets before persisting. The reference implementation detects AWS keys, API keys (sk-/pk- prefixes), passwords in assignments, connection strings, JWTs, private key blocks, and bearer tokens. On detection, learn() throws and refuses to save. ingest() silently skips secret-containing candidates. Configurable via allow_secrets: true for environments where this is acceptable.

Minimum viable implementation

An implementation is engram-compatible if it supports:

Everything else — associations, spreading activation, co-access learning, schema emergence — is optional. Start minimal. Add complexity when the simple version stops being sufficient.