Memory

The memory component is a scoped, vector-searchable store. Memories have typed scopes, support fact superseding with audit trails, and can be linked with relationship edges.

Scopes

Memories are organized in a 4-level visibility hierarchy:

task < session < user < agent
Scope Visibility Carries sessionId
task Only the current sub-agent yes
session Current session yes
user All sessions for this user no
agent All users of this agent no

A search at user scope also sees agent-scoped memories. A search at session scope sees session + user + agent.

Writing memories

await harness.memory().write({
  content: "User prefers Rust over TypeScript",
  scope: "user",
  embedding,                          // number[]
  tags: ["preference", "language"],   // optional
  metadata: { source: "chat" },       // optional
  supersedes: oldMemoryId,            // optional
  summary: "language preference",     // optional
  sourceType: "conversation",         // optional
  extractionMethod: "rules",          // optional
  confidence: 0.9,                    // optional (0-1)
  expectedVersion: 1,                 // optional — optimistic concurrency
})

Superseding

When supersedes is set, the old memory is preserved in the audit trail but excluded from future searches. A supersedes edge is created automatically. The old memory's status changes to superseded.

// original fact
const m1 = await harness.memory().write({
  content: "User prefers TypeScript",
  scope: "user", embedding,
})

// later, the fact changes
await harness.memory().write({
  content: "User prefers Rust over TypeScript",
  scope: "user", embedding: newEmb,
  supersedes: m1.id,
})
// m1 still exists but won't appear in search results

Searching

const results = await harness.memory().search({
  embedding: queryVec,
  scope: ["user", "agent"],          // scope filter (array = union)
  tags: ["preference"],              // optional tag filter
  metadata: { source: "chat" },      // optional metadata filter
  queryText: "language",             // optional FTS query
  scoring: "hybrid",                 // "similarity" | "hybrid" | "rrf"
  hybridWeights: {                   // optional weight tuning
    similarity: 0.6,
    recency: 0.25,
    popularity: 0.15,
  },
  decayHalfLifeDays: 14,            // optional recency decay
  graphExpand: { maxExpand: 3 },     // optional edge traversal
  rerankFn,                          // optional custom reranker
  minScore: 0.4,                     // optional threshold
  limit: 10,                         // optional max results
})

Each result includes breakdown scores:

Field Description
score Combined final score
similarityScore Cosine similarity to query vector
recencyScore Time-based decay score
popularityScore Access-count-based score
ftsScore Full-text search score (when queryText is used)

Scoring modes

Mode Description
similarity Pure cosine similarity — no time or popularity factors
hybrid Weighted blend of similarity + recency + popularity
rrf Reciprocal rank fusion across all signals

Edges

Typed relationships between memories. Useful for building knowledge graphs and enabling graph-expanded search.

// add a relationship
await harness.memory().addEdge({
  sourceId: memA.id,
  targetId: memB.id,
  edgeType: "related",
  metadata: { reason: "same topic" },
})

// get edges for a memory
const edges = await harness.memory().getEdges(memA.id)

// delete an edge
await harness.memory().deleteEdge(edgeId)

Edge types

Type Meaning
related General relationship
derived Target was derived from source
contradicts Facts conflict
supports Target supports source
supersedes Target replaces source (auto-created on supersede)

Other methods

// list memories with filters
const mems = await harness.memory().list({ scope: "user", limit: 50 })

// get a specific memory by ID
const mem = await harness.memory().get(memoryId)

// delete a memory
await harness.memory().delete(memoryId)