@neuralsea/neo4j-agent-memory
v0.6.1
Published
A Neo4j-backed memory system for AI agents: - semantic / procedural / episodic memories - case-based reasoning (symptoms -> similar cases -> fixes) - negative memories ("do not do") - environment fingerprints for precision - hybrid retrieval returning a C
Readme
@neuralsea/neo4j-agent-memory
A Neo4j-backed memory system for AI agents:
- semantic / procedural / episodic memories
- case-based reasoning (symptoms -> similar cases -> fixes)
- negative memories ("do not do")
- environment fingerprints for precision
- hybrid retrieval returning a ContextBundle with separate Fix / Do-not-do blocks
- feedback API to reinforce / degrade association weights (agent affinity)
Install (npm)
npm install @neuralsea/neo4j-agent-memoryRequirements
Hard requirements:
- Node.js 18+
- Neo4j 5+
- Windows, macOS, or Linux
Minimal requirements (tested):
- Neo4j Desktop 2.1.1 (macOS) with a Neo4j 5.x database
- Neo4j Browser + Bolt enabled
- Download: https://neo4j.com/download-thanks-desktop/?edition=desktop&flavour=osx&release=2.1.1&offline=false
Core API
import { createMemoryService } from "@neuralsea/neo4j-agent-memory";
const mem = await createMemoryService({
neo4j: { uri, username, password },
vectorIndex: "memoryEmbedding",
fulltextIndex: "memoryText",
halfLifeSeconds: 30 * 24 * 3600,
autoRelate: {
enabled: true,
minSharedTags: 2,
minWeight: 0.2,
maxCandidates: 12,
sameKind: true,
samePolarity: true,
allowedKinds: ["semantic", "procedural"]
}
});
const bundle = await mem.retrieveContextBundle({
agentId: "auggie",
prompt: "EACCES cannot create node_modules",
symptoms: ["eacces", "permission denied", "node_modules"],
tags: ["npm", "node_modules"],
env: { os: "macos", packageManager: "npm", container: false },
fallback: {
enabled: true,
useFulltext: true,
useTags: true,
useVector: false,
},
});
const feedback = await mem.feedback({
agentId: "auggie",
sessionId: bundle.sessionId,
usedIds: bundle.sections.fix.map((m) => m.id),
usefulIds: bundle.sections.fix.slice(0, 2).map((m) => m.id),
notUsefulIds: []
});
await mem.close();Notes:
createMemoryServiceruns schema setup on init.- Cypher assets are bundled at
dist/cypherin the published package. feedback()returns updated RECALLS edge posteriors for the provided memory ids.- Neutral usage: pass
neutralIdsorupdateUnratedUsed: falseto avoid penalizing retrieved-but-unrated memories. - Fallback retrieval uses fulltext/tag (and optional vector) search; provide
fallback.embeddingwhen using vector indexes. - Agent ids are case-sensitive; using PascalCase ids (e.g.
Auggie,Gemini) is recommended for consistency.
Design docs
packages/neo4j-agent-memory/docs/memory-design.md
Auto-relate config (defaults):
enabled: trueminSharedTags: 2minWeight: 0.2maxCandidates: 12sameKind: truesamePolarity: trueallowedKinds: ["semantic", "procedural"]
Auto-relate behavior:
- Uses tag overlap with Jaccard weight (
shared / (a + b - shared)). - Runs only for newly inserted memories (skips deduped).
- Applies filters for
sameKind,samePolarity, andallowedKinds. - Requires
minSharedTagsandminWeightto pass before linking. - Limits to
maxCandidateshighest-weight neighbors.
Performance note:
- Auto-relate scans candidate memories with tag filtering; for large graphs, keep tags selective and consider tightening
maxCandidatesandminSharedTags.
Neo4j Browser params (auto-relate by tags):
:param nowIso => "2026-01-04T22:07:53.086Z";
:param id => "mem_8cd773c2-208c-45ad-97ea-1b2337dca751";
:param minSharedTags => 2;
:param minWeight => 0.3;
:param maxCandidates => 10;
:param sameKind => false;
:param samePolarity => false;
:param allowedKinds => [];Note: :param lines are only supported in Neo4j Browser; other runners should pass parameters via the driver.
Tool adapter (createMemoryTools)
Use the tool factory to preserve the existing tool surface used by the demo:
import { createMemoryService, createMemoryTools } from "@neuralsea/neo4j-agent-memory";
const mem = await createMemoryService({ neo4j: { uri, username, password } });
const tools = createMemoryTools(mem);
await tools.store_skill.execute({
agentId: "auggie",
title: "Fix npm EACCES on macOS",
content: "If npm fails with EACCES, chown the cache directory and retry.",
tags: ["npm", "macos", "permissions"],
});Tool names:
store_skillstore_patternstore_conceptrelate_conceptsrecall_skillsrecall_conceptsrecall_patterns
Stored UI APIs
List summaries for the UI without legacy Cypher:
const all = await mem.listMemories({ limit: 50 });
const episodes = await mem.listEpisodes({ agentId: "auggie" });
const skills = await mem.listSkills({ agentId: "auggie" });
const concepts = await mem.listConcepts({ agentId: "auggie" });Graph APIs
Fetch full memory records by id:
const records = await mem.getMemoriesById({ ids: ["mem-1", "mem-2"] });Retrieve a weighted subgraph for UI maps:
const graph = await mem.getMemoryGraph({
agentId: "auggie",
memoryIds: ["mem-1", "mem-2"],
includeNodes: true,
includeRelatedTo: true,
});List edges for analytics/audit:
const edges = await mem.listMemoryEdges({ limit: 500, minStrength: 0.2 });Search stored memories (fulltext + filters):
const hits = await mem.search({
query: "EACCES node_modules",
tags: ["npm", "macos"],
kind: "procedural",
topK: 10,
});Upsert a structured memory card (good for agent tool adapters):
const { id } = await mem.upsert({
kind: "procedural",
title: "Fix npm EACCES creating node_modules on macOS",
summary: "Repair ownership/permissions and avoid sudo installs.",
whenToUse: ["EACCES", "permission denied", "node_modules"],
howToApply: ["Use nvm", "chown project and cache", "retry install"],
gotchas: ["Don't run `sudo npm install`"],
evidence: ["EACCES: permission denied"],
scope: { runtime: "node", versions: ["npm@10"] },
tags: ["npm", "macos", "permissions"],
outcome: "success",
confidence: 0.85,
utility: 0.7,
agentId: "Auggie",
taskId: "run_123",
});Link nodes by id (restricted allowlist of relationship types):
await mem.link("mem_1", "TOUCHED", "file:apps/demo-api/src/seed.ts", { reason: "edited" });Node id conventions (for mem.link() and manual Cypher):
Memory:mem_...File:file:<path>Tool:tool:<name>Tag:tag:<lowercase>Concept:concept:<lowercase>Symptom:symptom:<normalised>ErrorSignature:err:<sha256(text)>(generated by the service when you passerrorSignatures)
Retrieve a tag-based knowledge graph (edges weighted by query tag overlap):
const kg = await mem.getKnowledgeGraphByTags({
tags: ["npm", "permissions"],
limit: 50,
minStrength: 0.25,
});Retrieve a bundle with graph edges in one call:
const bundleWithGraph = await mem.retrieveContextBundleWithGraph({
agentId: "auggie",
prompt: "EACCES cannot create node_modules",
tags: ["npm", "node_modules"],
includeRelatedTo: true,
});Episodic capture helpers
await mem.captureEpisode({
agentId: "auggie",
runId: "run-123",
workflowName: "triage",
prompt: "Why is npm failing?",
response: "We found a permissions issue.",
outcome: "success",
tags: ["npm", "triage"],
});
await mem.captureStepEpisode({
agentId: "auggie",
runId: "run-123",
workflowName: "triage",
stepName: "fix",
prompt: "Apply the fix",
response: "Ran chown and reinstalled.",
outcome: "success",
});Useful learning capture
await mem.captureUsefulLearning({
agentId: "auggie",
sessionId: "run-123",
useful: true,
learning: {
kind: "semantic",
title: "Avoid chmod 777 on node_modules",
content: "Use npm cache ownership fixes instead of chmod 777.",
tags: ["npm", "permissions"],
confidence: 0.8,
utility: 0.3,
},
});Case helpers
await mem.createCase({
title: "npm EACCES",
summary: "Permission denied on cache directory.",
outcome: "resolved",
symptoms: ["eacces", "permission denied"],
env: { os: "macos", packageManager: "npm" },
resolvedByMemoryIds: ["mem-1"],
negativeMemoryIds: [],
});Event hooks
Provide an onMemoryEvent callback to observe reads/writes:
const mem = await createMemoryService({
neo4j: { uri, username, password },
onMemoryEvent: (event) => {
console.log(`[memory:${event.type}] ${event.action}`, event.meta);
},
});Schema + cypher exports
Schema helpers and cypher assets are exported for integrations:
import { ensureSchema, schemaVersion, migrate, cypher } from "@neuralsea/neo4j-agent-memory";Intended usage (demo + API)
This package is used by the demo API in this repository to:
- retrieve a ContextBundle mid-run (
/memory/retrieve) - send feedback (
/memory/feedback) - save distilled learnings (
/memory/save)
See the repo for the demo API and UI: https://github.com/emmett08/neo4j-agent-memory-demo
Reinforcement model
Edges RECALLS and CO_USED_WITH are updated using a decayed Beta posterior
(a, b pseudo-counts with exponential forgetting). strength is cached as
a/(a+b) and evidence as a+b.
