Skip to content
GitHub
Agents

Agent Memory Primitives

Spectral runs three agents — the Spectral Agent, the World Agent, and the Operations Agent — each with its own memory system. The agents differ in audience, scope, and behavior, but their memory systems all answer the same set of underlying questions. This page names those questions as primitives: the axes each agent’s memory parameterizes.

The primitives doctrine is: every agent’s memory chooses an explicit value for each foundational primitive, and either accepts the typology-implied default for each behavioral primitive or documents a deviation. New agent memories follow the same template. Existing agent memory pages (Memory System, World Agent, Operations Agent) read as parameterizations of this page.


These five primitives are structural. Every agent’s memory makes an explicit choice on each.

The scope tuple that keys an agent’s memory. Every other decision cascades from this choice — tier boundaries, retention semantics, visibility, conflict resolution, and promotion criteria all resolve differently depending on what anchors the persistent tier.

The anchor entity is the agent’s tenancy model expressed as a key tuple. Mature systems make this a required primitive (LangGraph’s BaseStore requires a namespace argument; Mem0 exposes user_id / agent_id / run_id as first-class scoping keys).

What an agent’s memory specifies: the full scope tuple, which keys are required at write time, and which are nullable for cross-scope queries. The persistent tier’s anchor is the most consequential — it determines what survives across sessions and what gets garbage-collected at session-end.

Example anchors across Spectral’s three agents:

AgentPersistent-tier anchor
Spectral Agent(workspace_id)
World Agent(world_id)world_version is contextual provenance per ADR-058 D5, not a version pin
Operations Agent(operator_id)

The distribution of episodic / semantic / procedural memory across an agent’s tiers. This typology is the field-converged framing (CoALA paper; Mem0; Zep facts-vs-episodes; CrewAI entity memory) and most behavioral primitives’ values follow from it.

  • Episodic — what happened, tied to time and interaction context. “During this scan attempt, lowering temperature to 0.2 eliminated fabrication on this case pattern.”
  • Semantic — facts about the domain or world the agent operates in, time-invariant within their validity window. “The conformity gate requires N independent corroborations for promotion.”
  • Procedural — how to do things; behavioral preferences and patterns. “This operator prefers concise distillation outputs over exhaustive ones.”

What an agent’s memory specifies: the typology mix at each tier. Most agents’ transient tiers (cycle, run, conversation) are episodic by nature — that part is the floor. The persistent tier is where typology diverges and where cross-agent differences live.

Example typology distributions:

AgentTransient tiersPersistent tier
Spectral AgentEpisodicBifurcated: semantic (domain observations, route candidates) + procedural (workspace-specific optimization patterns)
World AgentEpisodicSemantic + procedural about the world’s domain
Operations AgentEpisodic at conversation tier; mixed at session tierProcedural-dominant (operator preferences, in-flight task state)

The number of tiers, what defines a tier boundary, and what each tier holds. Field convergence is two to four tiers; some are time-scoped (cycle / run), some scope-anchored (workspace / operator / world).

What an agent’s memory specifies: tier count; per-tier name; the lifecycle event or scope change that defines each boundary; which tier is the persistent (top) tier.

A tier boundary is one of:

  • Lifecycle event — interaction-end, session-end, run-end. The boundary is temporal.
  • Scope change — entering a different workspace, operator, or world. The boundary is the anchor change.
  • Anchor escalation — moving from a more-scoped anchor to a broader one (e.g., session-scoped to operator-scoped at promotion).

The physical home of memory state. Convention follows LangGraph’s two-axis split:

  • Checkpointer / short-term — interaction state, framework-managed, append-mostly. Spectral uses the LangGraph AsyncPostgresSaver in a dedicated langgraph schema. All three agents share this backend for their conversation/session checkpointer.
  • Store / long-term — application-managed memory, queryable, embedding-indexed, lives in the agent’s owning context (platform.* for Spectral Agent memory tiers; worlds.* for World Agent memory; platform.* operations namespace for Operations Agent memory).

What an agent’s memory specifies: the schema(s) each tier lands in; whether tiers share a backend or split across checkpointer + store; cross-context read access patterns where applicable.

How memory enters the agent’s reasoning. Hybrid is the field default — vector + structured tag + recency, fused via Reciprocal Rank Fusion (RRF) or weighted score. Embedding choice is part of this primitive and is pinned globally to BGE-small-en-v1.5 with the retrievable-table convention.

What an agent’s memory specifies: the signal mix (which retrieval signals contribute); the scoring method (RRF k=60 is the default); per-tier retrieval scope (one tier? all tiers? weighted by tier?); whether a reranking layer sits on top.

The Spectral Agent’s memory uses a three-signal RRF retrieval over its tiers (structured envelope match + semantic search + time decay). World Agent and Operations Agent retrieval defaults inherit the same signal mix; per-agent specifications may deviate where typology requires (e.g., procedural-dominant memory may weight recency higher than semantic similarity).


Behavioral primitives (typology-driven defaults)

Section titled “Behavioral primitives (typology-driven defaults)”

These primitives have typology-implied defaults. Each agent picks a typology mix at each tier, and these primitives’ values follow. Documented deviations require justification on the per-agent memory page.

What dies, what archives, what stays.

TypologyDefault lifecycle
Episodic (transient)Drop at scope-end unless promoted at the tier boundary.
Episodic (persistent)Forcing-function decay toward disposition: promote, mark exempt, or archive (see Time decay).
SemanticPersist with corroboration tracking. Archive when invalidated by canonical-source change or by N consecutive failed corroborations.
ProceduralPersist indefinitely. Decay-exempt by default. Archive on explicit invalidation only.

The persistent tier registers a RetentionPolicy directly per the four-state model in data retention (ACTIVE / REFERENCED / ORPHANED / TOMBSTONED). Transient tiers (interaction, session) inherit lifecycle from their enclosing scope — interaction → chat thread; session → operator session — rather than registering a literal TTL. The persistent-vs-transient axis is about the durability of the memory itself, not “ephemeral by construction.”

What pressure decay creates on stored memory.

TypologyDefault decay model
Episodic (persistent)Forcing-function — entries must dispose toward an outcome (promote / mark exempt / archive). Decay weight in retrieval scoring increases as time passes, creating pressure toward continued evaluation rather than fade-into-irrelevance.
SemanticValidity-window decay — entries carry validity-as-of timestamps; decay reflects diminishing confidence in still-current state. Re-corroboration extends validity.
ProceduralDecay-exempt by default — preferences and workflow patterns are durably true unless invalidated by a contradicting write.

The Spectral Agent’s “forcing-function” decay (per Memory System) is the episodic-persistent default. The Operations Agent’s “decay-exempt by default” (per Operations Agent) is the procedural-dominant default. Both are typology-consistent.

When and how memory rows are written.

TypologyDefault write policy
EpisodicAuto-write at observation events (scan completion, interaction turn). Volume controlled by sampling and promotion gates. For the Spectral Agent, the interaction-tier (cycle) write at scan completion is performed by the on_scan_completed handler via the spectral_agent_memory gateway — a direct gateway invocation, not an event-mediated dispatch.
SemanticExplicit-write through a promotion engine; never directly written by the agent. The promotion gate enforces corroboration.
ProceduralMixed — explicit-write for operator-stated preferences; auto-extract from interaction patterns with high-confidence threshold.

What triggers an entry’s move up a tier.

Source → TargetDefault promotion criteria
Episodic (transient) → Episodic (persistent)Compounding pass at tier boundary; embedding-similarity dedup against existing persistent entries
Episodic (persistent) → SemanticCorroboration across ≥ N independent observations; sanitization-gate pass; cross-context validity
Semantic → meta-semantic (cross-version / cross-anchor)≥ 2-version persistence; non-empty surviving canonical-reference set; recurrence threshold
ProceduralNo promotion — procedural memory is the durable form

Spectral’s compounding engine (per Memory System) implements the episodic→semantic gate, including the sanitization step that strips workspace-specific context before promoting domain observations to world-signal events.

What happens when a new memory contradicts an existing one. Convention follows Mem0’s ADD / UPDATE / DELETE / NOOP decisions and Zep’s temporal-validity invalidation.

TypologyDefault conflict resolution
EpisodicNOOP — episodes accumulate; contradictions are themselves observations
SemanticUPDATE with temporal validity — old fact gets invalid_at = now(); new fact gets valid_at = now(). Both retained for audit
ProceduralUPDATE with supersession — the latest preference wins; the prior is archived for audit, never hard-deleted

How multiple observations merge into fewer, richer entries.

TypologyDefault consolidation
EpisodicPeriodic compounding at tier boundaries; embedding-similarity dedup at promotion
SemanticLLM-based merge on contradicting or overlapping facts (ADD/UPDATE per Mem0 pattern)
ProceduralAppend-with-supersession; the latest valid preference replaces the prior in the active set

How memory enters the agent’s prompt + per-block token accounting. Field convergence: per-memory-block token budgets with priority-based eviction (LlamaIndex MemoryBlock.token_limit) and retrieval-on-demand for lower-priority tiers (MemGPT paged-in core memory for highest priority).

What an agent’s memory specifies: per-tier token budget; eviction priority within budget; whether each tier is retrieved-on-demand or always-present-in-prompt; reranking layer if any.

Static budgets and priorities are the default; tune when measured retrieval quality or context-window pressure justifies it. Persistent-tier retrieval is on-demand via the retrieval model (primitive 5); transient tiers are always-present within their lifecycle.


Discipline primitives (cross-cutting invariants)

Section titled “Discipline primitives (cross-cutting invariants)”

These primitives are not typology-driven. Each agent’s memory answers each independently.

What canonical state the agent’s memory must not duplicate. Each agent declares a non-mirror list — concrete categories of state that live elsewhere as a single source of truth and may only be referenced (never copied).

AgentNon-mirror list
Spectral AgentWorld-model rule content; canonical scan results
World AgentWorld-model rule content; Spectral memory at any tier
Operations AgentWorld-model rule content; scan trace data; customer PII

Schema-level enforcement preferences:

  • No wide text columns on memory tables. Memory rows hold structured envelopes, FK references, and bounded-length reasoning notes — never canonical-source bodies.
  • Junction tables for canonical references. When a memory row references rules or other canonical entities, use a junction table with real foreign keys (with version pinning where the canonical entity is versioned), not arrays of UUIDs.
  • Views for reference resolution. Where the agent needs to present canonical content alongside memory, use a database view that joins to the canonical source at query time rather than materializing the content.

Where content is transformed when it crosses a tenant, context, or trust-scope boundary. Sanitization is distinct from access control: access control gates who can read; sanitization changes what they read.

Boundary crossingGate
Spectral T3 domain observation → world-signal eventStrip workspace-specific identifiers; preserve domain-behavioral pattern
Operations Agent → summaries crossing into worldsAlready aggregate; no further transform needed
World Agent memory → operator chat surfaceHedge-mapping to provenance tier; “I don’t know” as first-class output where the world model has unknown coverage

The Spectral T3-to-world-signal gate is the canonical example: an observation expressed without workspace-specific detail routes; an observation that requires workspace specificity to be meaningful stays at T3.

Who can read what. Access enforcement uses the layering per ADR-033: app-layer tenancy primary, RLS as backstop. Reads across contexts do not use SQL grants — per ADR-063, call flow between contexts goes through DI-injected protocols composed at the framework-layer entrypoint (see Contract Surfaces).

AgentRead access pattern
Spectral Agent memoryWorkspace-scoped via session-var RLS; consumption by worlds is event-driven (subscribes to platform.t3_memory.written; projects into a worlds-local replica) per ADR-064 D3 (broadened) + ADR-056 — no Reader Protocol
World Agent memoryInternal to worlds; operator read via the Operations Agent chat surface (ask_world_agent tool); no direct DB read from another context
Operations Agent memoryOperator-keyed RLS; no cross-operator sharing; no read from another context

Audit and immutability (universal default)

Section titled “Audit and immutability (universal default)”

The audit posture is action-linkage-based, not blanket-tier-based:

  • No hard DELETE on persistent-tier memory. Persistent memory is durable by definition.
  • No hard DELETE on any-tier memory load-bearing for audit. When a memory was the basis of a downstream action — a rule promotion, a change-set acceptance, a published decision — the linkage from the action back to the memory rows that justified it stays intact. The memory cannot be removed from beneath the action, regardless of which tier it lives in.
  • Transient-tier memory without action-linkage can be removed when its scope ends. Interaction-tier memory tied only to a conversation can be discarded when the chat thread closes; session-tier memory tied only to an operator session can be discarded when the session closes.
  • Soft-supersession. When a memory is no longer surfaced by retrieval (archived, decayed, invalidated, superseded), a state column records the transition (archived_at, superseded_at, invalidated_at) but the row stays.

This posture supports Explainability and the regulatory posture on auditability of agentic actions.

Implementation note (per-agent specificity)

Section titled “Implementation note (per-agent specificity)”

The universal default scopes which tiers are transient and which carry action-linkage-bearing memory by agent. Per ADR-058 D10 and ADR-059 D10:

  • Spectral Agent. Tier 1 (interaction = cycle) and Tier 2 (session = run) are transient; Tier 3 (persistent = workspace) carries action-linkage-bearing memory. Transient-tier rows without action-linkage are dropped at scope-end (cycle-end, run-end); persistent-tier rows follow the universal “no hard DELETE” posture. Cycle-tier writes are produced by the on_scan_completed handler at scan completion via the spectral_agent_memory gateway; compounding (interaction → session → persistent) lives in the gateway and runs at cycle-end and run-end scan-event boundaries.
  • World Agent. Interaction and session tiers are transient; session-tier memory is retained within the interaction window per ADR-058 D12 and then inherits scope-close lifecycle. The persistent tier carries action-linkage-bearing memory (rule-revision signals, contradictions surfaced to operators, promoted candidates).
  • Operations Agent. The conversation tier (interaction) is transient with chat-thread lifecycle; the operator-session tier (session) is semi-durable with operator-session lifecycle per ADR-059 D12 (30-day idle defines session-close, with compounding-and-archive at close). The persistent tier carries action-linkage-bearing memory (workflow preferences, durable inferences, signal digests load-bearing for downstream decisions).

In all three cases the action-linkage rule overrides the tier-transience default: any-tier memory load-bearing for audit (rule promotion, change-set acceptance, published decision) is retained regardless of which tier it lives in.

Per-agent memory leak defense is calibrated to memory consumption pattern, not uniform across agents.

  • World Agent (semantic-leaning over rules). The trigram trigger against worlds.rules.body_text is the primary defense — the agent reasons OVER rules to produce semantic claims, so rule-shadow risk is structurally close to the write path.
  • Operations Agent (procedural-dominant). The same-shape trigram trigger is a defense-in-depth backstop. Primary defense is agent-design discipline (workshop framing — see Reference-only invariants): the operator’s semantic memory holds workflow meta-knowledge (“operator was working on conformity-gate coverage for World X”), not rule content (“the conformity gate says Y”). Rule interpretation lives with the rule corpus and its tools.

When a new agent is parameterized against these primitives, the calibration question is: does the agent reason OVER canonical content (trigger as primary defense) or WITH canonical content via tools (trigger as backstop with workshop discipline as primary)?


When introducing a new agent (or revising an existing agent’s memory spec), work the primitives in this order:

  1. Anchor entity — pick the scope tuple. Every other decision flows from it.
  2. Memory typology — distribute episodic / semantic / procedural across tiers. Most behavioral primitives’ defaults follow from this.
  3. Tier model — count, names, boundary events.
  4. Persistence backend — which schemas; checkpointer / store split.
  5. Retrieval model — signal mix and scoring.
  6. Behavioral primitives — accept typology defaults or document each deviation.
  7. Discipline primitives — declare the agent’s non-mirror list, sanitization gates, visibility/access scope. Each is an explicit, per-agent choice.
  8. Audit posture — universal default unless a specific exemption is justified (none currently exist).

The result is a per-agent memory spec that reads as a parameterization of this page rather than as a standalone design.