Entity-Scoped Memory
HEBBS enforces strict entity isolation — memories stored under one entity are invisible to queries against another. This cookbook demonstrates how to use entity scoping for multi-tenant applications.
Concept
Section titled “Concept”An “entity” in HEBBS is a namespace that isolates memories. Common entity schemes:
| Pattern | Example | Use Case |
|---|---|---|
| Customer ID | customer-42 | CRM, sales agents |
| User ID | user-alice | Personal assistants |
| Session ID | session-abc123 | Conversation agents |
| Agent ID | agent-support-1 | Agent-specific knowledge |
| Composite | org-acme:user-bob | Multi-level isolation |
Zero-Config Scoping with Folders
Section titled “Zero-Config Scoping with Folders”The simplest way to scope memories is the entities/ folder convention. Place files under entities/{name}/ at the workspace root, and every memory from those files is automatically scoped:
workspace/├── entities/│ ├── acme-corp/│ │ ├── call-2026-03-15.md → entity_id: "acme-corp"│ │ └── call-2026-03-22.md → entity_id: "acme-corp"│ └── initech/│ └── discovery.md → entity_id: "initech"├── products/ → shared knowledge (no entity)└── training/ → shared knowledge (no entity)Files outside entities/ are shared knowledge, accessible during recall for all entities. Use frontmatter to override when needed:
---entity_id: initech---# How Initech Cut Data Entry by 80%This case study is shared content but also relevant to the Initech entity.Create Memories for Multiple Entities
Section titled “Create Memories for Multiple Entities”import asynciofrom hebbs import HebbsClient, MemoryKind
async def main(): async with HebbsClient.connect("localhost:50051") as client:
# Store memories for Entity A await client.remember( content="Acme Corp is expanding to Europe next quarter", entity="acme-corp", kind=MemoryKind.EPISODIC, ) await client.remember( content="Acme's budget is $500K for Q2", entity="acme-corp", kind=MemoryKind.SEMANTIC, )
# Store memories for Entity B await client.remember( content="Beta Inc is focused on North American market", entity="beta-inc", kind=MemoryKind.EPISODIC, ) await client.remember( content="Beta's budget is $200K for Q2", entity="beta-inc", kind=MemoryKind.SEMANTIC, )
print(f"Acme memories: {await client.count('acme-corp')}") print(f"Beta memories: {await client.count('beta-inc')}")
asyncio.run(main())Prove Isolation
Section titled “Prove Isolation”Querying one entity never returns memories from another:
# Query Acme — should only see Acme memoriesacme_results = await client.recall( query="What is the budget?", entity="acme-corp", strategy="similarity", top_k=10,)
print("Acme results:")for r in acme_results.memories: print(f" [{r.score:.3f}] {r.memory.content}") assert r.memory.entity == "acme-corp" # Always true
# Query Beta — should only see Beta memoriesbeta_results = await client.recall( query="What is the budget?", entity="beta-inc", strategy="similarity", top_k=10,)
print("\nBeta results:")for r in beta_results.memories: print(f" [{r.score:.3f}] {r.memory.content}") assert r.memory.entity == "beta-inc" # Always trueEntity-Wide Operations
Section titled “Entity-Wide Operations”Forget All Memories for an Entity
Section titled “Forget All Memories for an Entity”result = await client.forget("acme-corp")print(f"Deleted {result.deleted_count} memories for acme-corp")
# Verifyassert await client.count("acme-corp") == 0assert await client.count("beta-inc") > 0 # Beta unaffectedPer-Entity Reflection Policies
Section titled “Per-Entity Reflection Policies”# Enable aggressive reflection for high-value accountsawait client.set_policy( "acme-corp", reflect_enabled=True, reflect_interval=1800, # every 30 minutes reflect_min_memories=3,)
# Disable reflection for low-activity accountsawait client.set_policy( "beta-inc", reflect_enabled=False,)Composite Entity Patterns
Section titled “Composite Entity Patterns”For multi-level isolation, use composite entity keys:
# Organization-level memories (shared across users)await client.remember( content="Company-wide policy: no discounts over 15%", entity="org-acme", kind=MemoryKind.SEMANTIC,)
# User-level memories within the organizationawait client.remember( content="Bob prefers morning meetings", entity="org-acme:user-bob", kind=MemoryKind.SEMANTIC,)
# Query at the user levelresults = await client.recall( query="What do I know about Bob?", entity="org-acme:user-bob", top_k=5,)To query across levels, your application layer retrieves from both entities and merges results.
Performance Considerations
Section titled “Performance Considerations”- Entity isolation is structural — it’s enforced at the storage and index level via key prefixes, not post-query filtering.
- Each entity’s HNSW index is logically independent. 1000 entities with 1000 memories each performs the same as 1 entity with 1000 memories for query latency.
- Entity-wide
forget()is efficient — it uses prefix deletion in RocksDB.