DEV Community

Anton Illarionov
Anton Illarionov

Posted on • Originally published at github.com

Building Production Agent Memory with Neo4j: The Constitutional Graph Pattern

Building Production Agent Memory with Neo4j: The Constitutional Graph Pattern

Most agent memory tutorials use vector databases. This is a guide for building with Neo4j instead — and why it matters for production autonomous agents.

Why Graph > Vector for Agent Memory

Vectors are great for "find me something similar to X." But agent memory has different requirements:

What agents actually ask:

  • "Has this action already been taken?" → Exact match, not similarity
  • "What led to this decision?" → Graph traversal
  • "Is this agent authorized for this?" → Authority lookup
  • "What is the temporal context here?" → Time-aware traversal

These are all native graph operations. They're awkward in vector space.

The 6-Layer Constitutional Ontology

After building this in production (ODEI, Jan 2026), here's the schema that works:

// Core layers
CREATE CONSTRAINT ON (n:Foundation) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT ON (n:Vision) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT ON (n:Strategy) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT ON (n:Tactics) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT ON (n:Execution) ASSERT n.id IS UNIQUE;
CREATE CONSTRAINT ON (n:Track) ASSERT n.id IS UNIQUE;

// Relationships
// PURSUES_GOAL, BLOCKS, INFORMS, PART_OF, ASSIGNED_TO, TRACKS
Enter fullscreen mode Exit fullscreen mode

Layer purposes:

  • FOUNDATION — who are we, what do we value, who do we trust
  • VISION — where are we going
  • STRATEGY — how are we getting there
  • TACTICS — what are we doing this week
  • EXECUTION — what are we doing right now
  • TRACK — how are we doing

The Constitutional Write Pattern

Before every write to the graph, run these checks:

// 1. Check immutability
MATCH (n {id: $id}) WHERE n.immutable = true RETURN n

// 2. Check referential integrity
MATCH (n {id: $ref_id}) RETURN count(n) as exists

// 3. Check deduplication
MATCH (e:Execution {hash: $action_hash}) RETURN count(e) as count

// 4. Check authority
MATCH (a:Agent {id: $agent_id})-[:HAS_SCOPE]->(s:Scope {name: $action_type})
RETURN count(s) as authorized
Enter fullscreen mode Exit fullscreen mode

If any check fails: reject. If suspicious: escalate. If all pass: write.

Production Stats (91-Node Graph, 2 Months)

Running this at https://api.odei.ai since January 2026:

  • 91 nodes across 6 layers
  • 91 relationship types
  • 0 hallucination errors (referential integrity catches them)
  • 0 duplicate writes (deduplication layer)
  • ~15% fewer harmful actions vs no-validation baseline

The Temporal Pattern

Every node gets createdAt and optional expiresAt:

CREATE (n:Task {
  id: randomUUID(),
  title: "Deploy guardrails",
  createdAt: datetime(),
  expiresAt: datetime({days: 7}),  // optional
  status: "pending"
})
Enter fullscreen mode Exit fullscreen mode

Query at a point in time:

MATCH (n)
WHERE n.createdAt <= $timestamp
AND (n.expiresAt IS NULL OR n.expiresAt > $timestamp)
RETURN n
Enter fullscreen mode Exit fullscreen mode

Making It Available to Agents

Option 1: REST API

# Get full graph state
curl https://api.odei.ai/api/v2/world-model/live

# Constitutional validation
curl -X POST https://api.odei.ai/api/v2/guardrail/check \
  -d '{"action": "...", "severity": "high"}'
Enter fullscreen mode Exit fullscreen mode

Option 2: MCP Server (Claude)

{
  "mcpServers": {
    "odei": {"command": "npx", "args": ["@odei/mcp-server"]}
  }
}
Enter fullscreen mode Exit fullscreen mode

Further Reading


Running in production at api.odei.ai — Virtuals ACP Agent #3082

Top comments (0)