Skip to content

KLSGG/agent-memory-graph

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

27 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Agent Memory Graph

Give your AI agent a persistent, queryable memory β€” powered by a local knowledge graph.

MIT License Node.js 18+ SQLite FTS5 Zero Config Any LLM


The Problem

AI agents forget everything between sessions. Context windows overflow. MEMORY.md files become unstructured dumps. RAG retrieval misses relationships.

The Solution

agent-memory-graph builds a structured knowledge graph from your conversations β€” automatically. Every person, project, tool, and relationship is extracted, stored locally in SQLite, and queryable with natural language.

You: "I just met Viktor, the CTO of Nexus Labs. They're building SkyNet-X using Rust."

β†’ Graph auto-extracts:
  Viktor (Person) ──[CTO_OF]──→ Nexus Labs (Company)
  Nexus Labs ──[BUILDS]──→ SkyNet-X (Project)
  SkyNet-X ──[USES]──→ Rust (Language)

You: "Who works at Nexus Labs?"
β†’ "People at Nexus Labs: Viktor"

You: "How is Viktor connected to Rust?"
β†’ "Viktor β†’[CTO_OF]β†’ Nexus Labs β†’[BUILDS]β†’ SkyNet-X β†’[USES]β†’ Rust"

✨ Features

Feature Description
🧠 Auto-extraction Hybrid: local rule-based + LLM fallback for complex text
🏠 Zero-API mode Works fully offline β€” local extraction + local embeddings
πŸ—£οΈ Natural language queries Ask questions like "Who works at X?" or "What does Y use?"
πŸ”— Path finding Discover hidden connections between entities (BFS, up to 5 hops)
πŸ” Semantic search Local n-gram embeddings (256d) β€” no OpenAI key needed
πŸ“¦ Single SQLite file Zero external deps, fully portable, survives restarts
🌐 Domain-agnostic Software, crypto, research, CRM, notes β€” anything
⚑ Zero-config Works out of the box with zero API keys
πŸ”Œ OpenClaw plugin Auto-ingests every conversation, registers 11 tools
πŸ• Temporal facts Graphiti-inspired: facts have valid_from/valid_until, never deleted
πŸ“‰ Confidence decay Unused entities/relations lose confidence over time
🧹 Relation normalization Synonyms merged, vague relations rejected automatically
πŸ–₯️ MCP server Compatible with Claude Code, Cursor, Gemini CLI
πŸ“Š Export Mermaid, DOT, JSON, CSV for visualization

πŸ“‹ Requirements

  • Node.js 18–22 (recommended) β€” better-sqlite3 has prebuilt binaries
  • Node.js 24 β€” works but requires build tools (gcc, make, python3) for native compilation
  • No API key required β€” works fully offline with local extraction + local embeddings
  • Optional: Any OpenAI-compatible LLM β€” for higher-quality extraction in hybrid/llm mode

πŸš€ Quick Start

npm install agent-memory-graph

As a library

import { MemoryGraph } from 'agent-memory-graph';

const graph = new MemoryGraph();

// Ingest β€” entities and relationships are auto-extracted
await graph.ingest(
  "Alice is the CTO of TechCorp. She leads the Platform team " +
  "and uses Kubernetes, Go, and PostgreSQL."
);

// Query with natural language
await graph.ask("What does Alice use?");
// β†’ "Alice: USES β†’ Kubernetes, Go, PostgreSQL"

await graph.ask("Who works at TechCorp?");
// β†’ "People at TechCorp: Alice"

// Find hidden connections
graph.findPath("Bob", "PostgreSQL");
// β†’ Bob β†’[MEMBER_OF]β†’ Platform team β†’[LED_BY]β†’ Alice β†’[USES]β†’ PostgreSQL

graph.close();

As a CLI

# Ingest from text
memory-graph ingest "Started learning Rust for the new backend service"

# Ask questions
memory-graph ask "What am I learning?"
# β†’ "Found: Rust (Language)"

# Search entities
memory-graph search "Rust"

# Find paths
memory-graph path "Alice" "PostgreSQL"

# Visualize
memory-graph visualize --format mermaid

# Stats
memory-graph stats
# β†’ Entities: 42 | Relationships: 67 | Types: Person, Tool, Project...

πŸ”Œ OpenClaw Plugin (Recommended)

The killer feature: install as an OpenClaw plugin and your agent automatically remembers everything.

Install

openclaw plugins install agent-memory-graph --dangerously-force-unsafe-install
openclaw gateway restart

⚠️ The --dangerously-force-unsafe-install flag is required because the plugin reads environment variables (API keys) and makes network calls (to your LLM provider). This is expected behavior for LLM-powered extraction.

What happens next

  1. Every message (>20 chars) is auto-ingested into the knowledge graph
  2. 11 tools are registered for the agent to call:
    • memory_graph_ingest β€” manually add knowledge
    • memory_graph_query β€” natural language questions
    • memory_graph_search β€” keyword search
    • memory_graph_path β€” find connections between entities
    • memory_graph_stats β€” graph statistics
    • memory_graph_temporal β€” query facts at a point in time
    • memory_graph_supersede β€” update facts (old β†’ new)
    • memory_graph_decay β€” apply confidence decay
    • memory_graph_embed β€” generate embeddings for semantic search
    • memory_graph_semantic_search β€” find similar entities by meaning
    • memory_graph_dedup_relations β€” clean up duplicate/vague relations
  3. Data persists in ~/.openclaw/data/memory-graph.db β€” survives /new, /reset, and restarts

Demo: Auto-detect in action

[19:02] You: Hey, I just met Viktor who's the CTO of Nexus Labs.
             They're building SkyNet-X using Rust and ROS2.

        β”Œβ”€ memory-graph hook ─────────────────────────────┐
        β”‚ βœ“ Auto-ingested: 4 entities, 5 relationships    β”‚
        β”‚   Viktor (Person), Nexus Labs (Company),         β”‚
        β”‚   SkyNet-X (Project), Rust (Language)            β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

[19:05] You: Who works at Nexus Labs?

        Agent calls: memory_graph_query("Who works at Nexus Labs?")
        β†’ "People at Nexus Labs: Viktor"

[19:06] You: How is Viktor connected to Rust?

        Agent calls: memory_graph_path("Viktor", "Rust")
        β†’ "Viktor β†’[CTO_OF]β†’ Nexus Labs β†’[BUILDS]β†’ SkyNet-X β†’[USES]β†’ Rust"

Plugin config

{
  "plugins": {
    "entries": {
      "memory-graph": {
        "enabled": true,
        "config": {
          "autoIngest": true,
          "extractionModel": "gpt-4o-mini",
          "extractionMode": "hybrid",
          "dbPath": "~/.openclaw/data/memory-graph.db",
          "maxHops": 5,
          "minConfidence": 0.7
        }
      }
    }
  }
}

Extraction modes:

Mode API Cost Quality When to use
"local" Zero Good for simple text No API key, offline, cost-sensitive
"hybrid" (default) ~70-80% less Best balance Most users β€” local first, LLM for complex text
"llm" Full Highest When accuracy is critical and you have API budget

Set autoIngest: false to disable auto-ingestion and only use manual tool calls.


πŸ§ͺ Query Examples

The NL query engine understands 12+ question patterns:

Question What it does
"What is Alice working on?" Find outgoing relationships
"Who works at TechCorp?" Find people connected to entity
"Where did Bob work before?" Find PREVIOUSLY_WORKED_AT relations
"What does the team use?" Find USES relationships
"What is Alice's role?" Look up role property/relation
"List all people" Filter by type (normalizes "people" β†’ "Person")
"List all companies" Type normalization works for all types
"How is A connected to B?" BFS path finding
"Who suggested X?" Verb-to-relation matching
"What tools are mentioned?" Type-based listing

πŸ“Š Graph Visualization

graph LR
    classDef person fill:#3b82f6,stroke:#1d4ed8,color:#fff
    classDef company fill:#f97316,stroke:#c2410c,color:#fff
    classDef project fill:#8b5cf6,stroke:#6d28d9,color:#fff
    classDef tool fill:#10b981,stroke:#047857,color:#fff

    Alice[Alice - CTO]:::person
    Bob[Bob - Engineer]:::person
    TechCorp[TechCorp]:::company
    Platform[Platform Team]:::project
    K8s[Kubernetes]:::tool
    Go[Go]:::tool
    PG[PostgreSQL]:::tool

    Alice -->|CTO_OF| TechCorp
    Alice -->|LEADS| Platform
    Alice -->|USES| K8s
    Alice -->|USES| Go
    Alice -->|USES| PG
    Bob -->|MEMBER_OF| Platform
    Bob -->|WORKS_AT| TechCorp
Loading

🏠 Zero-API Mode (Fully Offline)

No API key? No problem. The plugin works completely offline:

# No environment variables needed!
openclaw plugins install agent-memory-graph --dangerously-force-unsafe-install
openclaw gateway restart
# That's it. Everything works.

What works offline:

  • βœ… Entity extraction (rule-based pattern matching)
  • βœ… Relationship detection (grammar patterns: "X works at Y", "X built Y", etc.)
  • βœ… Semantic search (local n-gram embeddings, 256 dimensions)
  • βœ… All graph operations (search, path, temporal, supersede, decay, dedup)
  • βœ… Auto-ingestion from conversations

What needs an API (optional):

  • LLM extraction for complex/ambiguous text (hybrid mode fallback)
  • Higher-dimensional embeddings (text-embedding-3-small via OpenAI)

How local extraction works

The rule-based extractor uses:

  1. Named Entity Recognition β€” capitalized words, type indicator patterns ("CEO of X", "built Y")
  2. Relationship patterns β€” 11 grammar templates (WORKS_AT, BUILDS, USES, LOCATED_IN, SUPPORTS, etc.)
  3. Relation normalization β€” synonyms merged (CREATED/DEVELOPED/AUTHORED β†’ BUILDS)
  4. Vague relation rejection β€” RELATED_TO, ASSOCIATED_WITH, etc. are filtered out
  5. Confidence scoring β€” local results get 0.5-0.7 confidence (vs 0.8-1.0 for LLM)

How local embeddings work

Instead of calling OpenAI's embedding API, we generate 256-dimensional vectors locally:

  1. Character trigrams β€” "hello" β†’ ["hel", "ell", "llo"]
  2. Word unigrams + bigrams β€” "hello world" β†’ ["hello", "world", "hello world"]
  3. FNV-1a hashing β€” each n-gram hashed to a vector position
  4. TF normalization β€” frequency-weighted, L2-normalized output
  5. Cosine similarity β€” compare vectors in JS (no pgvector needed)

Quality benchmarks:

  • Bitcoin ↔ Ethereum: 0.80 similarity (related concepts)
  • Bitcoin ↔ Apple fruit: 0.13 similarity (unrelated)
  • "AI agent memory" β†’ finds "agent memory" entity at 67.5% match

βš™οΈ Configuration

LLM Provider

Works with any OpenAI-compatible API β€” OpenAI, Anthropic (via proxy), Ollama, LiteLLM, vLLM, 9router, etc.

Variable Description Default
OPENAI_API_KEY API key sk-local
OPENAI_BASE_URL API base URL http://127.0.0.1:20128/v1
MEMORY_GRAPH_API_KEY Override API key β€”
MEMORY_GRAPH_BASE_URL Override base URL β€”
MEMORY_GRAPH_MODEL Override model gpt-4o-mini

Examples:

# OpenAI
export OPENAI_API_KEY="sk-..."

# Anthropic via LiteLLM/9router
export OPENAI_BASE_URL="http://127.0.0.1:4000/v1"
export MEMORY_GRAPH_MODEL="claude-3-5-haiku-20241022"

# Ollama (free, local)
export OPENAI_BASE_URL="http://localhost:11434/v1"
export MEMORY_GRAPH_MODEL="llama3.1"

Domain Hints (optional)

Improve extraction accuracy for your specific domain:

{
  "domains": [{
    "name": "software",
    "entityHints": ["Person", "Repository", "Language", "Framework", "Service"],
    "relationHints": ["MAINTAINS", "USES", "DEPENDS_ON", "DEPLOYS_TO"]
  }]
}

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  MemoryGraph API                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Ingest  β”‚  Query  β”‚  Search  β”‚  Temporal  β”‚  Export  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Hybrid   β”‚ NL      β”‚ Keyword  β”‚ Supersede  β”‚ Mermaid β”‚
β”‚ Extract  β”‚ Query   β”‚ + FTS5   β”‚ + Decay    β”‚ DOT/CSV β”‚
β”‚          β”‚ Engine  β”‚ + Vector β”‚ + Temporal β”‚         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Extraction Layer                                    β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚ Local (free)    β”‚  β”‚ LLM (fallback, optional)   β”‚  β”‚  β”‚
β”‚  β”‚  β”‚ Rule-based NER  β”‚  β”‚ OpenAI / Anthropic / Ollamaβ”‚  β”‚  β”‚
β”‚  β”‚  β”‚ Pattern match   β”‚  β”‚ High-quality extraction    β”‚  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Embedding Layer                                     β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚ Local (free)    β”‚  β”‚ API (optional, higher-dim) β”‚  β”‚  β”‚
β”‚  β”‚  β”‚ N-gram 256d    β”‚  β”‚ text-embedding-3-small     β”‚  β”‚  β”‚
β”‚  β”‚  β”‚ Cosine in JS   β”‚  β”‚ 1536d, better quality      β”‚  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  GraphEngine (SQLite + WAL + FTS5)                      β”‚
β”‚  Entities β”‚ Relationships β”‚ Embeddings β”‚ FTS5 Index     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • SQLite β€” Single file, WAL mode, FTS5 full-text search, schema v4
  • Hybrid extraction β€” Local rule-based (free) + LLM fallback (optional)
  • Local embeddings β€” N-gram 256d vectors, cosine similarity in JS
  • NL Query Engine β€” 12+ regex patterns + smart entity-name fallback
  • Graph traversal β€” BFS pathfinding up to 5 hops
  • Temporal facts β€” valid_from/valid_until, supersession, never-delete
  • Confidence decay β€” Unused facts lose confidence (min 0.1)
  • Relation normalization β€” Synonyms merged, vague relations rejected
  • Deduplication β€” Levenshtein-based entity merging + relation dedup
  • MCP server β€” stdio protocol for Claude Code, Cursor, Gemini CLI
  • Persistence β€” Survives process restarts, session resets, and agent reboots

πŸ“ˆ Test Results

βœ“ Unit tests: 38/38 pass
βœ“ NL Query accuracy: 10/10 (local), 9.5/10 (plugin E2E)
βœ“ Path finding: 4/4 pass
βœ“ Edge cases: graceful handling, zero crashes
βœ“ Zero hallucination: no fabricated relationships
βœ“ Persistence: data survives /new, /reset, gateway restart

🀝 Contributing

PRs welcome! See CONTRIBUTING.md.

git clone https://github.com/KLSGG/agent-memory-graph
cd agent-memory-graph
npm install
npm test       # 38 tests
npm run dev    # Watch mode

πŸ“„ License

MIT β€” Use it however you want.


Built for OpenClaw agents that need to remember.

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors