Skip to content

Agent Memory

The identity graph is agent memory. When an AI agent resolves an entity, it can store memory entries - decisions made, investigations completed, patterns observed - linked to that entity. The next agent that resolves the same entity gets the full context from every previous agent, automatically.

No shared database to configure. No message passing between agents. Resolve the entity, get the memory.

Local memory for quick start

Want memory without cloud setup? The Python SDK includes local memory with LLM-powered fact extraction - works immediately with zero config. See Local Memory (SDK).

python
import kanoniv
mem = kanoniv.get_memory(agent_name="my-agent", api_key="sk-...")
mem.add([
    {"role": "user", "content": "I'm Bill from Acme, switch to annual billing"},
    {"role": "assistant", "content": "Done!"},
], user_id="[email protected]")

Why This Matters

AI agents are stateless by default. Agent A qualifies a lead, Agent B enriches the same contact, Agent C writes the outreach - but none of them know what the others did. Teams solve this with shared databases, vector stores, or message queues. All of these require agents to know about each other.

Kanoniv takes a different approach: memory is a property of identity. If two agents resolve the same real-world person, they share memory - even if they have never communicated.

How It Works

Memory entries are linked to entities in the identity graph. When you call POST /v1/resolve/realtime with include_memory: true, the response includes the standard resolution result plus all memory entries linked to that entity.

Because memory is attached to canonical entities (not source records), it survives merges. If two records are later resolved to the same person, their memory entries combine automatically.

Agent A resolves [email protected] -> Entity ENT_7f82
Agent A stores: "Qualified as enterprise lead"

Agent B resolves (555) 010-1234 -> Entity ENT_7f82  (same person)
Agent B receives: memory from Agent A
Agent B stores: "Enriched via LinkedIn - VP Engineering at Acme"

Agent C resolves [email protected] -> Entity ENT_7f82
Agent C receives: memory from Agent A + Agent B

Each agent adds to the cumulative memory. No agent needs to know the others exist.

Example: Four-Agent Pipeline

Consider a pipeline where four agents process the same prospect independently.

Agent 1 - Lead Qualification

bash
POST /v1/resolve/realtime
{
  "source_name": "inbound",
  "external_id": "lead_442",
  "data": { "email": "[email protected]", "company": "Acme Corp" },
  "include_memory": true
}

Response includes entity_id: "ENT_7f82" and an empty memory: [] array. Agent 1 then stores a decision:

bash
POST /v1/memory
{
  "entry_type": "decision",
  "slug": "lead-qualified",
  "title": "Qualified as enterprise lead",
  "content": "Company has 500+ employees, ARR > $10M. Matches ICP.",
  "linked_entities": ["ENT_7f82"],
  "author": "lead-qualifier-agent"
}

Agent 2 - Enrichment

Resolves the same person by phone number. Gets Agent 1's memory automatically:

bash
POST /v1/resolve/realtime
{
  "source_name": "enrichment",
  "external_id": "enrich_991",
  "data": { "phone": "5550101234", "name": "John Doe" },
  "include_memory": true
}

Response includes memory: [{ "title": "Qualified as enterprise lead", ... }]. Agent 2 adds its own findings:

bash
POST /v1/memory
{
  "entry_type": "investigation",
  "slug": "linkedin-enrichment",
  "title": "Enriched via LinkedIn",
  "content": "VP Engineering at Acme Corp. 12 years experience. Active on GitHub.",
  "linked_entities": ["ENT_7f82"],
  "author": "enrichment-agent"
}

Agent 3 - Pattern Detection

Resolves the same entity and receives all prior memory. Notices a recurring pattern:

bash
POST /v1/memory
{
  "entry_type": "pattern",
  "slug": "personal-email-pattern",
  "title": "Always uses personal email for signups",
  "content": "This contact has signed up 3 times with personal email, never corporate.",
  "linked_entities": ["ENT_7f82"],
  "author": "pattern-agent"
}

Agent 4 - Outreach

Resolves [email protected] and receives three memory entries from three different agents. It knows the lead is qualified, the contact is a VP, and they prefer personal email - without ever communicating with the other agents.

Memory Entry Types

TypePurposeExample
decisionAn action taken or conclusion reached"Qualified as sales lead", "Marked as do-not-contact"
investigationResearch findings or enrichment data"Enriched via LinkedIn", "Verified address via USPS"
patternA recurring observation about the entity"Always uses personal email", "Purchases quarterly"
knowledgeProject docs shared across agents"CLAUDE.md", "Architecture notes"
expertiseAgent's domain expertise declaration"Salesforce sync specialist"
intentShort-lived action declaration (auto-expires)"Syncing to Salesforce" (TTL: 5 min)
taskWork assigned to another agent"Sync lead to CRM" (assigned_to: crm-agent)

New entry types

knowledge, expertise, intent, and task enable cross-agent coordination. See Intent & Expertise and Cross-Agent Tasks for details.

Memory Statuses

StatusMeaning
activeCurrent and relevant
supersededReplaced by a newer entry
resolvedThe issue or investigation is complete
archivedNo longer relevant, retained for audit

API Reference

Resolve with Memory

Include include_memory: true in any resolve call to receive linked memory entries in the response.

bash
POST /v1/resolve/realtime
Content-Type: application/json
Authorization: Bearer <api_key>

{
  "source_name": "crm",
  "external_id": "contact_123",
  "data": { "email": "[email protected]" },
  "include_memory": true
}

The response includes the standard resolve fields (entity_id, decision, confidence, is_new) plus a memory array.

Create Memory Entry

bash
POST /v1/memory
Content-Type: application/json
Authorization: Bearer <api_key>

{
  "entry_type": "decision",
  "slug": "lead-qualified",
  "title": "Qualified as enterprise lead",
  "content": "Matches ICP. 500+ employees, ARR > $10M.",
  "linked_entities": ["ENT_7f82"],
  "linked_sources": ["crm"],
  "author": "qualifier-agent"
}
FieldTypeRequiredDescription
entry_typestringYesOne of: decision, investigation, pattern
slugstringYesURL-safe identifier for the entry
titlestringYesShort summary
contentstringYesFull details
linked_entitiesstring[]YesEntity IDs this memory is linked to
linked_sourcesstring[]NoSource names for context
authorstringNoAgent or user that created the entry

Get Memory by Entity

bash
GET /v1/memory/by-entity/:entity_id
Authorization: Bearer <api_key>

Returns all memory entries linked to the given entity, ordered by creation time.

Append to Memory

Add a timestamped note to an existing memory entry without replacing it.

bash
POST /v1/memory/:id/append
Content-Type: application/json
Authorization: Bearer <api_key>

{
  "note": "Follow-up call scheduled for March 10."
}

Search Memory

Full-text search across all memory entries in the tenant.

bash
GET /v1/memory/search?q=enterprise+lead
Authorization: Bearer <api_key>

Update Memory

bash
PUT /v1/memory/:id
Content-Type: application/json
Authorization: Bearer <api_key>

{
  "title": "Updated title",
  "content": "Updated content",
  "status": "superseded"
}

Archive Memory

bash
DELETE /v1/memory/:id
Authorization: Bearer <api_key>

Sets the entry status to archived. Memory entries are never hard-deleted.

MCP Tools

Agents using Kanoniv via MCP (npx @kanoniv/mcp) have eight memory tools available:

ToolDescription
resolve_with_memoryResolve an entity and return linked memory entries
memorizeStore a decision, investigation, pattern, knowledge, or expertise entry
recallGet all memory linked to an entity
search_memoryFull-text search across all memory (filter by entry_type)
declare_intentTell other agents what you're about to do (auto-expires via TTL)
query_expertiseFind which agents have experience with an entity or domain
sync_knowledgeBulk-import project docs so all agents can access them

See Sync & Pull for knowledge sharing, Intent & Expertise for coordination, and Cross-Agent Tasks for task assignment.

MCP Example

json
{
  "tool": "resolve_with_memory",
  "arguments": {
    "source_name": "crm",
    "external_id": "contact_123",
    "data": { "email": "[email protected]" }
  }
}

Returns the resolved entity plus all linked memory. The agent can then call memorize to store new findings:

json
{
  "tool": "memorize",
  "arguments": {
    "entity_id": "ENT_7f82",
    "entry_type": "decision",
    "slug": "outreach-approved",
    "title": "Approved for outreach sequence",
    "content": "Enterprise ICP match. VP-level contact. Green light for personalized sequence."
  }
}

Memory and Merges

When two entities merge, their memory entries combine. If Entity A has 3 memory entries and Entity B has 2, the merged entity has all 5. No memory is lost during merges.

This means memory accumulates naturally as the identity graph evolves. Early-stage agents that resolve partial data contribute context that later agents benefit from - even after the graph restructures through merges.

Memory is tenant-scoped

All memory entries are isolated by tenant, enforced by row-level security. Agents using different API keys within the same tenant share memory. Agents in different tenants never see each other's memory.

The identity and delegation layer for AI agents.