Skip to content

Recall Strategies

HEBBS supports four recall strategies. Each targets a different access pattern. Choose the strategy (or combine them) based on what the agent needs: semantic match, recency, cause-and-effect, or structural analogy.

What it does: Returns memories whose content is semantically similar to the query. Uses vector embeddings and approximate nearest-neighbor search.

When to use it: When the agent needs context that sounds like or means something close to the current situation. “What did we discuss about pricing?” “Find memories related to this customer complaint.”

How it works internally: The query is embedded with the same model used at write time. HNSW (Hierarchical Navigable Small World) index performs approximate k-NN search. Results are ranked by cosine similarity. Time complexity is O(log n) with bounded ef_search for predictable latency.

Example use case: A sales agent receives a new lead. Similarity recall fetches past conversations with similar companies or topics to prime context before the call.

ParameterDefaultWhen to change
ef_search50Increase (up to ~500) for large datasets where you need higher recall accuracy and can tolerate slightly higher latency. Decrease for real-time applications with tight latency budgets.

What it does: Returns memories for a specific entity in time order, optionally within a time range.

When to use it: When the agent needs “what happened with entity X” or “how has X changed over time.” Chronology matters more than semantic match.

How it works internally: A B-tree index on (entity_id, created_at) supports efficient range scans. The query specifies an entity_id and optional start_time/end_time. Results are streamed in time order. Time complexity is O(log n + k) where k is the number of memories in the range.

Requires entity_id: Temporal recall needs an entity to scope the timeline. During indexing, entity_ids are automatically assigned to propositions from LLM-extracted entities (e.g., “cloudvault”, “meridian analytics”). For manually stored memories, use hebbs remember --entity-id <entity>.

Example use case: A legal agent asks “what happened with Meridian?” Temporal recall with --entity-id meridian returns the chronological timeline: DPA signing, subprocessor change, violation, risk escalation.

Alternative for indexed content: If you don’t know the entity_id, use similarity recall with recency-weighted scoring (--weights 0.3:0.5:0.2:0) to get time-ordered results across all entities.

ParameterDefaultWhen to change
time_rangeNone (unbounded)Set explicit start/end timestamps to focus on a specific period (e.g. “last 24 hours”, “Q1 2025”). When omitted, all memories are eligible, returned newest-first up to top_k.

What it does: Returns memories connected by causal edges (CausedBy, FollowedBy). Traverses the graph from a seed memory to find causes, effects, or chains.

When to use it: When the agent needs to reason about why something happened or what followed from an event. “What led to this decision?” “What happened after the user said X?”

How it works internally: Starts from one or more seed memory IDs. Performs bounded graph traversal (max depth configurable) following edges of the specified types. Results are ranked by graph distance and recency. Time complexity is O(branching_factor ^ max_depth), bounded by configuration.

Works with indexed content: During indexing, the LLM extracts entity relationships which become EntityRelation graph edges. These edges connect propositions across documents, enabling causal traversal on indexed content without manual edge setup. For richer causal chains, store memories with explicit edges via hebbs remember --edge TARGET:caused_by:0.9.

Example use case: A research assistant traces how a conclusion was reached. Causal recall walks backward from the conclusion to the supporting evidence and reasoning steps.

ParameterDefaultWhen to change
seed_memory_idNone (auto-detect)Set explicitly when you know the starting point for the graph walk. When omitted, the engine embeds the cue and uses the closest memory as the seed.
max_depth5 (bounded at 10)Increase for deep causal chains. The hard cap of 10 prevents runaway traversals. Decrease for shallow “immediate cause” queries.
edge_typesNone (all types)Filter to ["CausedBy"] for pure cause-tracing, or ["FollowedBy"] for sequential narratives. When omitted, all edge types are followed.

What it does: Finds memories that share structural patterns across domains. “This situation is like X in a different context.”

When to use it: When the agent needs cross-domain transfer: lessons from one project applied to another, or patterns that repeat across customers.

How it works internally: Structural pattern matching over memory graphs. Extracts relational structure (entities, actions, outcomes) and finds isomorphic or similar patterns in other memories. More expensive than similarity; typically used with smaller candidate sets or as a secondary pass.

Example use case: A product manager asks “Have we seen a similar launch failure before?” Analogical recall finds past launches with comparable failure patterns, even if the domains differ.

ParameterDefaultWhen to change
analogical_alpha0.5 (balanced)Lower (toward 0.0) to favor structural similarity — useful when you want pattern matches even if the surface content differs. Raise (toward 1.0) to favor embedding similarity — useful when content overlap is a stronger signal than structure.

You can invoke multiple strategies in a single recall request. When you do, HEBBS executes them in parallel, deduplicates results by memory ID (keeping the highest relevance), computes a composite score for each, and returns a single ranked list truncated to top_k.

When combining strategies, consider latency: similarity and temporal are fastest; causal and analogical add graph traversal cost. Use strategy-specific limits (top_k, max_depth) to stay within latency budgets.

Every recall result includes a composite score — the number shown in CLI output and returned as score in API responses. This is not raw cosine similarity. It’s a weighted blend of four signals:

composite = w_relevance × relevance
+ w_recency × recency_signal
+ w_importance × importance
+ w_reinforcement × reinforcement_signal
SignalRangeWhat it measuresHow it’s computed
Relevance0.0 — 1.0Semantic match between query and memory1.0 - hnsw_distance (cosine similarity for normalized embeddings)
Recency0.0 — 1.0How recently the memory was created1.0 - (age / max_age), where max_age defaults to 30 days. A brand-new memory scores 1.0; a 30-day-old memory scores 0.0.
Importance0.0 — 1.0Memory’s importance valueThe importance field set at remember time. Defaults to 0.5 if not specified.
Reinforcement0.0 — 1.0How often this memory has been recalledlog₂(1 + access_count) / log₂(1 + cap), where cap defaults to 100. A never-recalled memory scores 0.0.
WeightDefaultEffect
w_relevance0.5Relevance contributes half the score
w_recency0.2Recent memories rank higher
w_importance0.2High-importance memories rank higher
w_reinforcement0.1Frequently recalled memories rank higher

With these defaults, the theoretical maximum score for a brand-new, never-recalled memory with default importance (0.5) is:

0.5 × 1.0 + 0.2 × 1.0 + 0.2 × 0.5 + 0.1 × 0.0 = 0.80

So a score of 0.67 does not mean weak similarity. The raw cosine similarity is likely 0.85+, blended down by the other signals.

Pass scoring_weights to override the defaults. This works via gRPC, REST, the Python SDK, and the TypeScript SDK.

Pure relevance ranking (ignore recency, importance, reinforcement):

# Python
results = await client.recall(
"Acme meeting",
strategies=["similarity"],
scoring_weights={
"w_relevance": 1.0,
"w_recency": 0.0,
"w_importance": 0.0,
"w_reinforcement": 0.0,
},
)
// TypeScript
const results = await client.recall({
cue: 'Acme meeting',
strategies: ['similarity'],
scoringWeights: { wRelevance: 1.0, wRecency: 0.0, wImportance: 0.0, wReinforcement: 0.0 },
});

Recency-biased ranking (prefer recent memories, with relevance as tiebreaker):

# Python
results = await client.recall(
"Acme meeting",
strategies=["similarity"],
scoring_weights={
"w_relevance": 0.3,
"w_recency": 0.5,
"w_importance": 0.1,
"w_reinforcement": 0.1,
},
)
// TypeScript
const results = await client.recall({
cue: 'Acme meeting',
strategies: ['similarity'],
scoringWeights: { wRelevance: 0.3, wRecency: 0.5, wImportance: 0.1, wReinforcement: 0.1 },
});

REST equivalent:

Terminal window
curl -X POST http://localhost:6381/v1/memories/recall \
-H "Content-Type: application/json" \
-d '{
"cue": "Acme meeting",
"strategies": ["similarity"],
"scoring_weights": {
"w_relevance": 1.0,
"w_recency": 0.0,
"w_importance": 0.0,
"w_reinforcement": 0.0
}
}'

Each result also includes strategy_details with per-strategy metadata. For similarity recall, this includes the raw relevance (cosine similarity) and distance values, so you can inspect the semantic match strength independently of the composite score. These are available in gRPC responses and the REST API.