Skip to main content
By default a memory records only which agent formed it. That’s fine for a single-user assistant — but in B2B, one agent acts on behalf of many subjects (customers, leads, patients, guests). Engram’s scope model lets a single agent keep thousands of subjects cleanly isolated, compose the right context on recall, and share authoritative org knowledge — without spinning up an agent per subject or pooling everyone together. Every memory carries a binding that records what it’s about:
BindingWhat it’s bound toExample
privatethe forming agent only (the default — unchanged behavior)“Front desk WiFi rotates weekly”
anchoreda specific anchor (a subject: customer/guest/patient/case)“Guest 42 is vegetarian”
sessionone conversation (short-term, decays after the session)“On this call, asked for a Goa quote”
canontenant-shared, authoritative knowledge (policies, catalog)“Gold members get free late checkout”
Binding is derived server-side from the ids you pass (anchor_external_idanchored, session_idsession, neither → private). canon is the one explicit exception, written through its own admin endpoint. A caller that passes only agent_id gets exactly today’s behavior — nothing changes until you reach for a subject.

Anchors — who a memory is about

An anchor is a subject your agent acts on behalf of. You don’t pre-register them — pass your own id as anchor_external_id and Engram creates the anchor on first use, tenant-scoped so it’s shared across all of your agents.
from engram import Engram
client = Engram(base_url="http://localhost:8080", api_key="mk_...")

# Store a durable fact ABOUT guest-42 (anchor auto-created)
client.memories.store(
    agent_id=agent.id,
    content="Guest prefers a top-floor sea-view room",
    anchor_external_id="guest-42",
)
curl -X POST http://localhost:8080/v1/memories \
  -H "Authorization: Bearer mk_..." \
  -d '{"agent_id":"AGENT","content":"Guest is vegetarian","anchor_external_id":"guest-42"}'
# → { "binding": "anchored", "anchor_id": "...", ... }

Recall is isolated per subject

Pass the anchor on recall and you get only that subject’s memory (plus the agent’s private notes and tenant canon) — never another subject’s:
# Everything about guest-42 — guest-99's data never leaks in
client.memories.recall(
    agent_id=agent.id,
    query="dietary preferences",
    anchor_external_id="guest-42",
)
This isolation holds even when two subjects have semantically identical facts: guest-42 changing “lives in New York → Boston” never touches guest-99’s “lives in London”. Belief dynamics (reinforcement, contradiction, decay) are partitioned per anchor.

Sessions — one conversation

A session is a single conversation/run. Session memory is short-term: it decays after the session ends (a fast 0.20 decay rate), so “what happened on the last call” stays available for days, then fades — without polluting the subject’s durable profile.
# Start a session for a returning guest's call
session = client.sessions.create(agent_id=agent.id, anchor_external_id="guest-42")

client.memories.store(
    agent_id=agent.id,
    content="On this call, asked for a 3-night Goa quote, callback Friday",
    session_id=session.id,
)

# later
client.sessions.end(session.id)   # schedules session-memory expiry

Composed recall

Pass anchor_external_id and session_id and Engram composes multiple scopes into one ranked result — the subject’s durable profile + this conversation’s recent context + tenant canon — in a single call:
client.memories.recall(
    agent_id=agent.id,
    query="what does this returning guest want",
    anchor_external_id="guest-42",
    session_id=session.id,
)
# → anchored facts (sea-view, vegetarian) + session (Goa quote) + canon (policies),
#   session and anchored recency-boosted, canon capped so it can't crowd out subject context
If a session fact keeps recurring (reinforced ≥3× for the same anchor), it’s promoted from session to anchored — short-term trivia graduating into the durable profile.

Canon — shared org knowledge

Canon is tenant-wide authoritative knowledge every agent and subject inherits: policies, catalog, rules. It’s curated, so it bypasses belief logic (no reinforcement/contradiction — your policy won’t get demoted by some agent’s private note) and gets a sticky 0.01 decay rate. Writes are admin-scoped; reads are open to any authenticated caller and idempotent on identical content.
# admin key required
curl -X POST http://localhost:8080/v1/canon \
  -H "Authorization: Bearer mk_..." \
  -d '{"agent_id":"AGENT","content":"Gold loyalty members receive free late checkout until 4pm"}'

curl http://localhost:8080/v1/canon -H "Authorization: Bearer mk_..."   # list tenant canon
Canon composes into every recall in the tenant, regardless of which anchor you ask about.

Endpoints

MethodPathPurpose
POST/v1/memoriesstore — accepts anchor_external_id / anchor_id / session_id
GET/v1/memories/recallrecall — same params; composes scopes
POST/v1/agents/{id}/conversations/ingestingest — accepts anchor_external_id / session_id
POST GET/v1/anchors · /v1/anchors/{id}create / list / get a subject
GET/v1/anchors/{id}/memoriesa subject’s full durable profile
DELETE/v1/anchors/{id}?purge=trueGDPR hard-erase — deletes the subject and all its traces
POST GET/v1/sessions · /v1/sessions/{id} · /v1/sessions/{id}/endsession lifecycle
POST GET DELETE/v1/canon · /v1/canon/{id}canon (writes admin-scoped)

Compliance: per-subject erasure

Subject-scoped recall plus the existing mutation audit trail give per-subject data boundaries — the HIPAA/GDPR story. A purge hard-deletes the subject and every trace bound to it, scoped to just that subject:
curl -X DELETE "http://localhost:8080/v1/anchors/ANCHOR_ID?purge=true" \
  -H "Authorization: Bearer mk_..."
# guest-42: all anchored memories + the anchor entity deleted. Other subjects untouched.

The architecture behind this

Anchors reuse Engram’s entity graph; bindings layer onto the existing confidence, decay, and contradiction engine — applied per scope.