Graph Memory
Graph memory adds a fourth tier to Honi's memory stack — a persistent, queryable knowledge graph backed by edgraph, an edge-native property graph built on Cloudflare Durable Objects. Use it to store entities and relationships that your agent discovers, and retrieve them via traversal rather than keyword or vector search.
Why graph memory?
The other three tiers answer different questions:
| Tier | Answers |
|---|---|
| Working (DO) | "What happened in this conversation?" |
| Episodic (D1) | "What was said across all conversations?" |
| Semantic (Vectorize) | "What's conceptually similar to this?" |
| Graph (edgraph) | "How do these entities relate to each other?" |
Graph memory is the right choice when your agent needs to reason about structure — org charts, customer relationships, investment portfolios, knowledge maps — rather than just recall past text.
edgraph
edgraph is a property graph database built on Cloudflare Durable Objects. One DO instance per graph. Multi-hop BFS/DFS traversal runs inside the DO using SQLite — zero per-hop network cost. It stores an adjacency index alongside the edges table so traversal cost is proportional to the local neighbourhood, not the total graph size.
Deploy your own edgraph instance:
Setup
Add edgraph as a CF service binding in your wrangler.toml (preferred — zero latency, CF-internal network) or use an HTTP URL:
Set the API key as a Worker secret:
Configure
Enable graph memory in createAgent():
All options for GraphConfig:
| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | — | Enable graph memory |
graphId | string | — | Graph identifier. Maps to one edgraph DO instance. |
binding | string | — | CF service binding name. Preferred over urlEnvVar. |
urlEnvVar | string | — | Env var name whose value is the edgraph HTTP URL. |
apiKeyEnvVar | string | — | Env var name for edgraph API key (required for writes). |
contextDepth | number | 1 | Hop depth for graph context expansion during retrieval. |
maxContextEntities | number | 5 | Max entities to expand per retrieval. Guards against large context blocks. |
Writing to the graph from tools
Tool handlers receive an optional second argument — ctx — which includes the live GraphMemory instance. Use it to write entities as your tool discovers them:
ctx.graph is the live GraphMemory instance bound to the current agent. Entities written here are immediately available for future context retrieval — and they persist durably across sessions.
Hybrid retrieval (Semantic + Graph)
When both semantic and graph memory are enabled, Honi performs a two-stage retrieval on every request:
- Semantic search — embeds the user message and finds the top-K similar past episodes in Vectorize.
- Entity extraction — collects any
entityIdvalues from the semantic result metadata. - Graph expansion — calls
toContext(entityIds, depth)on those IDs, expanding each into its local neighbourhood. - Context injection — both the semantic results and the graph context are prepended to the system prompt before the LLM sees the message.
The result: instead of "here are some similar past conversations", your agent gets the full structured picture of the entities involved — including relationships they've never been directly told about.
Using GraphMemory standalone
GraphMemory can be used independently of createAgent() — as a shared knowledge base across multiple services:
GraphMemory API
| Method | Description |
|---|---|
upsertNode(id, label, props) | Create or update a node |
upsertEdge(fromId, toId, type, props?) | Create or update a directed edge |
getNode(id) | Fetch a single node by ID |
listNodes(opts) | List nodes, optionally filtered by label |
getNeighbours(id, direction?, types?) | Direct neighbours (in/out/both, filter by edge type) |
traverse(from, opts) | BFS or DFS traversal with depth, edge type, and node label filters |
shortestPath(from, to) | Shortest path between two nodes |
subgraph(root, depth, direction) | Extract a local subgraph around a root node |
toContext(entityIds, depth?) | Render entity subgraphs as an LLM-injectable text block |
deleteNode(id) | Delete a node |
deleteEdge(id) | Delete an edge |
stats() | Node and edge counts |
Performance characteristics
| Operation | Complexity |
|---|---|
| Get node / edge | O(1) — primary key lookup |
| Get neighbours | O(degree) — adjacency index |
| k-hop traversal | O(k × avg_degree) — no full-table scan |
| Shortest path (BFS) | O(V + E) over reachable subgraph |
| Subgraph extraction | O(nodes + edges in subgraph) |
All traversal runs inside the Durable Object's SQLite — a single HTTP call regardless of hop count.