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)