npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@susu-eng/gralkor

v27.2.11

Published

OpenClaw memory plugin powered by Graphiti knowledge graphs and FalkorDB

Readme

Gralkor

The best memory plugin for OpenClaw agents

Gralkor is an OpenClaw plugin that gives your agents long-term, temporally-aware memory. It uses Graphiti (by Zep) for knowledge graph construction and FalkorDB as the graph database backend. Both run automatically as a managed subprocess - no independent server for you to manage, or SaaS company to connect to.

Gralkor automatically remembers and recalls everything your agent says, thinks, and does — no prompt engineering required by the operator, no conscious (haha) effort required by the agent.

Why Gralkor

Let's look in detail about the decisions made for Gralkor and why they make it the best memory plugin for OpenClaw.

Graphs, not Markdown or pure vector. Graphs are the right data structure for representing knowledge. Your code is a graph - the world is a deeply interrelated graph and trying to flatten it into Markdown files or pure vector embeddings is fighting reality. Gralkor doesn't use MD files (other than indexing yours), and this is not another chunking strategy or embedding experiment. Graphiti has already solved this layer and Gralkor leverages it optimally for this use case.

HippoRAG (NeurIPS 2024) found graph-based retrieval reaches 89.1% recall@5 on 2WikiMultiHopQA versus 68.2% for flat vector retrieval — a 20.9-point gap. AriGraph (IJCAI 2025) independently found KG-augmented agents markedly outperform RAG, summarization, and full-conversation-history baselines across interactive environments.

Remembering behaviour, not just dialog. Agents make mistakes, weigh options, reject approaches - they learn as they complete tasks. Gralkor distills the agent's behaviour - not just its dialog - into first-person behavioural reports weaved into episode transcripts before ingestion.

For almost all other memory plugins, your agent is inherently dishonest with you, frequently claiming to remember what it has done when it only really remembers what it already claimed to have done, or to have thought what it is only now imagining.

With Gralkor your agent actually remembers it's thoughts and actions.

Reflexion (NeurIPS 2023) showed agents storing self-reflective reasoning traces outperform GPT-4 output-only baselines by 11 points on HumanEval. ExpeL (AAAI 2024) directly ablated reasoning-trace storage versus output-only: +11–19 points across benchmarks from storing the reasoning process alone.

Maximum context at ingestion. Gralkor captures all messages in each session of work, distills behaviour, and feeds results to Graphiti as whole episodes. Extraction works way better when Graphiti has full context.

Most memory plugins save isolated question-answer pairs or summarized snippets: Some store only the first user message and the last assistant reply, others store to the last turn only.

Gralkor captures the entire series of questions, thoughts, actions, and responses that solved the problem together, with all their interrelationships. Richer semantics, better understanding, better recall.

SeCom (ICLR 2025) found coherent multi-turn episode storage scores 5.99 GPT4Score points higher than isolated turn-level storage on LOCOMO. LongMemEval (ICLR 2025) confirms: fact-level QA-pair extraction drops accuracy from 0.692 to 0.615 versus full-round episode storage.

Built for the long term. Graphiti (and therefore Gralkor) is deeply temporal. On every ingestion, it doesn't just append; it resolves new information against the existing graph, amending, expiring, and invalidating so that your agent knows what happened over time.

Graphiti does the heavy temporal lifting on ingestion. It's bad for throughput, and useless for short-lived agents, which means serving a single, long-lived user agent is the perfect use case.

LongMemEval (ICLR 2025) established that temporal reasoning is the hardest memory sub-task for commercial LLMs; time-aware indexing recovers 7–11% of that loss. MemoTime (WWW 2026) found temporal knowledge graphs enable a 4B model to match GPT-4-Turbo on temporal reasoning, with up to 24% improvement over static memory baselines.

Recursion through reflection. Point your agent back at its own memory — let it reflect on what it knows, identify contradictions, synthesize higher-order insights, and do with them whatever you believe to be good cognitive architecture. Gralkor doesn't limit you to one approach, but the research is quite clear - you should do something.

My way is to use cron and Thinker CLI together, directing the agent to use the search and add memory tools in a sequential reflective process. Share yours, and ask to see mine.

Reflexion (NeurIPS 2023) demonstrated that agents storing verbal reflections in an episodic buffer gain 11 points with no weight updates. Generative Agents (UIST 2023) showed empirically that a reflection layer synthesizing raw memories into higher-order insights is essential for coherent long-term behavior.

Custom ontology: model your agent's world your way. Gralkor lets you define your own entity types, attributes, and relationships so that information is parsed into entities and relationships you define. Your graph doesn't have to be a black box - you can keep track of what matters to you.

You can use a domain model codified by experts in your field, or encode your model of the world so that your agent shares it.

Apple's ODKE+ (2025) showed ontology-guided extraction hits 98.8% precision vs 91% raw LLM; GoLLIE (ICLR 2024) directly ablated schema-constrained versus unconstrained generation on the same model, finding +13 F1 points average across NER, relation, and event extraction in zero-shot settings.

Interpretation Gralkor interprets information in memory for relevance to the task at hand. This step radically improves output with minimal impact on cost and latency.

On cost. Gralkor costs more to run than a Markdown file in the short term. In the longer term, Gralkor provides more efficient context management, reducing token burn. Instead of paying to pollute your context window with junk every read, you pay more on ingestion in exchange for cheap, high-relevance reads forever.

An agent that remembers behaviour, decisions, your preferences, and reasoning across sessions changes the character of your work. You stop spending turns re-establishing context and focus more on what you care about. A single recalled behavioural fact — "we rejected mysql because it lacked jsonb column support needed for X" — prevents re-litigating that decision in a new session - it might save 10 subagents repeating a parallel investigation of database options.

Gralkor is good memory, not cheap memory. You can push the llm choice and perhaps get better extraction, but otherwise I've just made it as good as possible while being reasonable about latency.

Tools

  • memory_search — searches the knowledge graph and returns relevant facts and entity summaries
  • memory_add — stores information in the knowledge graph; Graphiti extracts entities and relationships
  • memory_build_indices — rebuilds search indices and constraints (maintenance)
  • memory_build_communities — detects and builds entity communities/clusters to improve search quality (maintenance)
  • Hooks: auto-capture (stores full multi-turn conversations after each agent run), auto-recall (injects relevant facts before the agent responds)
  • Set up: plugins.slots.memory = "gralkor" in openclaw.json

Quick Start

1. Prerequisites

  • OpenClaw 2026.4.2
  • Python 3.12+ on the system PATH
  • uv on PATH (install)
  • An API key for a supported LLM provider (see below)

2. Configure before installing

Config must be set before plugins.allow, because OpenClaw validates all listed plugins' config on every write.

# Required: data directory for persistent state (venv, FalkorDB database).
# Choose a path YOU control — Gralkor has no default.
# This directory survives plugin reinstalls; the plugin dir does not.
openclaw config set plugins.entries.gralkor.config.dataDir /path/to/gralkor-data

# Required: LLM API key for knowledge extraction.
# Gemini is the default provider (LLM + embeddings + reranking, one key).
openclaw config set plugins.entries.gralkor.config.googleApiKey 'your-key-here'

# Optional
openclaw config set plugins.entries.gralkor.config.test true

3. Install the plugin

openclaw plugins install @susu-eng/gralkor --dangerously-force-unsafe-install

From a tarball (e.g. for air-gapped deploys):

openclaw plugins install ./susu-eng-gralkor-memory-26.0.14.tgz --dangerously-force-unsafe-install

Why --dangerously-force-unsafe-install? OpenClaw's install-time security scanner flags Gralkor as critical because dist/server-manager.js imports node:child_process and calls spawn() to launch the embedded Python server. This is intrinsic to how Gralkor works (managed FalkorDB + Graphiti subprocess) and cannot be removed. The flag is required on every install and update until OpenClaw provides a manifest-level allowlist mechanism. Inspect the source on npm/ClawHub before installing if you'd like to verify there's nothing else going on.

4. Enable and assign the memory slot

OpenClaw has a single memory slot that determines which plugin provides memory to your agents. You must explicitly assign Gralkor to the memory slot, otherwise installing the plugin does nothing — auto-capture and auto-recall hooks will never fire.

# If you use an allowlist, add gralkor to it
openclaw config set --json plugins.allow '["gralkor"]'

# Enable the plugin entry
openclaw config set plugins.entries.gralkor.enabled true

# Assign Gralkor to the memory slot (replaces the built-in memory-core)
openclaw config set plugins.slots.memory gralkor

# Expose Gralkor's tools to the agent. Auto-capture and auto-recall work without
# this, but the agent won't see memory_add / memory_build_indices / memory_build_communities
# unless you add them to the active tool profile's allowlist.
openclaw config set --json tools.alsoAllow '["gralkor"]'

5. Restart and go

Restart OpenClaw. On first start, Gralkor automatically:

  • Creates a Python virtual environment in dataDir/venv/
  • Installs Graphiti and its dependencies (~1-2 min first time)
  • Starts the Graphiti server with embedded FalkorDB
  • Subsequent restarts are fast (venv reused)

Verify the plugin loaded:

openclaw plugins list
openclaw gralkor status

Start chatting with your agent. Gralkor works in the background:

  • Auto-capture: Full multi-turn conversations are stored in the knowledge graph after each agent run
  • Auto-recall: Before the agent responds, relevant facts and entities are retrieved and injected as context

Upgrading

openclaw plugins update gralkor --dangerously-force-unsafe-install

LLM providers

Graphiti needs an LLM to extract entities and relationships from conversations.

| Provider | Config field | Notes | |---|---|---| | Google Gemini (default) | googleApiKey | Fully self-contained (LLM + embeddings + reranking) | | OpenAI | openaiApiKey | Handles LLM + embeddings out of the box | | Anthropic | anthropicApiKey | LLM only — still needs openaiApiKey for embeddings | | Groq | groqApiKey | LLM only — still needs openaiApiKey for embeddings |

To switch away from Gemini, set llm and embedder. For example, with OpenAI:

openclaw config set plugins.entries.gralkor.config.openaiApiKey "$OPENAI_API_KEY"
openclaw config set --json plugins.entries.gralkor.config.llm '{"provider":"openai","model":"gpt-4.1-mini"}'
openclaw config set --json plugins.entries.gralkor.config.embedder '{"provider":"openai","model":"text-embedding-3-small"}'

CLI

openclaw gralkor status              # Server state, config, graph stats, data dir, venv
openclaw gralkor search <group_id> <query>  # Search the knowledge graph

See Graph partitioning for what <group_id> should be.

Configuration

Configure with openclaw config set. For example:

openclaw config set --json plugins.entries.gralkor.config.autoRecall.maxResults 20
openclaw config set --json plugins.entries.gralkor.config.idleTimeoutMs 600000

| Setting | Default | Description | |---|---|---| | autoCapture.enabled | true | Automatically store conversations in the graph | | autoRecall.enabled | true | Automatically recall relevant context before each turn | | autoRecall.maxResults | 10 | Maximum number of facts injected as context by auto-recall | | search.maxResults | 20 | Maximum number of facts returned by the memory_search tool | | search.maxEntityResults | 10 | Maximum number of entity summaries returned by the memory_search tool | | idleTimeoutMs | 300000 | How long (ms) after the last agent response to wait before flushing buffered messages to the graph. Prevents data loss when sessions aren't explicitly ended (e.g. user walks away, gateway restarts). Set to 0 to disable idle flushing. | | dataDir | (required) | Directory for persistent backend data (Python venv, FalkorDB database). No default — operator must set. | | test | false | Test mode — logs full episode bodies and search results at plugin boundaries for debugging |

Complete config reference

The full plugin config shape (as it appears under plugins.entries.gralkor.config in ~/.openclaw/openclaw.json):

{
  "dataDir": "/path/to/gralkor-data",
  "workspaceDir": "~/.openclaw/workspace",
  "googleApiKey": "your-gemini-key",
  "llm": { "provider": "gemini", "model": "gemini-3.1-flash-lite-preview" },
  "embedder": { "provider": "gemini", "model": "gemini-embedding-2-preview" },
  "autoCapture": { "enabled": true },
  "autoRecall": { "enabled": true, "maxResults": 10 },
  "search": { "maxResults": 20, "maxEntityResults": 10 },
  "idleTimeoutMs": 300000,
  "ontology": {
    "entities": {},
    "edges": {},
    "edgeMap": {}
  },
  "test": false
}

Graph partitioning

Each agent gets its own graph partition automatically — different agents won't see each other's knowledge, and no configuration is needed.

The partition key (group_id) is the agent's ID with hyphens replaced by underscores (FalkorDB's RediSearch syntax doesn't accept hyphens). So an agent named my-coding-agent stores its memory under group my_coding_agent. Agents running without an explicit ID use the partition default. You'll need this group_id whenever you query the graph directly — e.g. openclaw gralkor search <group_id> <query>.

Custom entity and relationship types

By default, Graphiti extracts generic entities and connects them with generic RELATES_TO relationships. This works well out of the box — you don't need to configure anything for Gralkor to be useful.

If you want more structured extraction, you can define custom entity and relationship types. Graphiti will classify entities into your types, extract structured attributes, and create typed relationships between them.

Entities

The simplest useful ontology defines just entity types. Relationships will still be created, using Graphiti's default RELATES_TO type. Set the whole ontology in one go:

openclaw config set --json plugins.entries.gralkor.config.ontology '{
  "entities": {
    "Project": {
      "description": "A software project or initiative being actively developed. Look for mentions of repositories, codebases, applications, services, or named systems that are built and maintained by a team.",
      "attributes": {
        "status": ["active", "completed", "paused"],
        "language": "Primary programming language used in the project"
      }
    },
    "Technology": {
      "description": "A programming language, framework, library, database, or infrastructure tool. Identify by mentions of specific named technologies used in or considered for projects.",
      "attributes": {
        "category": ["language", "framework", "database", "infrastructure", "tool"]
      }
    }
  }
}'

Relationships

To control how entities are connected, add edges (relationship types) and edgeMap (which entity pairs they apply to):

{
  "entities": {
    "Project": {
      "description": "A software project or initiative being actively developed. Look for mentions of repositories, codebases, applications, services, or named systems that are built and maintained by a team.",
      "attributes": {
        "status": ["active", "completed", "paused"],
        "language": "Primary programming language used in the project"
      }
    },
    "Technology": {
      "description": "A programming language, framework, library, database, or infrastructure tool. Identify by mentions of specific named technologies used in or considered for projects.",
      "attributes": {
        "category": ["language", "framework", "database", "infrastructure", "tool"]
      }
    }
  },
  "edges": {
    "Uses": {
      "description": "A project actively using a technology in its stack. Look for statements about tech choices, dependencies, or implementation details that indicate a project relies on a specific technology.",
      "attributes": {
        "version": "Version of the technology in use, if mentioned"
      }
    }
  },
  "edgeMap": {
    "Project,Technology": ["Uses"]
  }
}

Apply with openclaw config set --json plugins.entries.gralkor.config.ontology '<above>'.

Without edgeMap, all edge types can connect any entity pair. With edgeMap, relationships are constrained to specific pairs — entity pairs not listed fall back to RELATES_TO.

Attributes

Attributes control what Graphiti extracts for each entity or relationship. They are required fields — if the LLM can't populate them from the text, it won't extract that entity type at all. This makes attributes the primary mechanism for gating extraction quality.

| Format | Example | Generated type | Gating strength | |---|---|---|---| | String | "language": "Primary programming language" | Required str field | Weak — any text satisfies it | | Enum (array) | "status": ["active", "completed", "paused"] | Required Literal enum | Strong — must pick a valid value | | Typed object | "budget": { "type": "float", "description": "Budget in USD" } | Required typed field | Medium — must be valid type | | Enum with description | "priority": { "enum": ["low", "high"], "description": "Priority level" } | Required Literal enum | Strong |

Supported types for the object form: string, int, float, bool, datetime.

Descriptions

Descriptions are the most important part of your ontology — they tell the LLM what to look for. Write them like extraction instructions, not dictionary definitions.

Weak (dictionary definition):

"A software project."

Strong (extraction instructions):

"A software project or initiative being actively developed. Look for mentions of repositories, codebases, applications, services, or named systems that are built and maintained by a team."

The more specific your description, the better Graphiti will distinguish between entity types and avoid false positives.

Reserved names

The following entity names are used internally by Graphiti and cannot be used: Entity, Episodic, Community, Saga.

Data storage

dataDir is a required config field — the operator chooses where persistent data lives:

  • venv/ — Python virtual environment (Graphiti, FalkorDBLite, etc.)
  • falkordb/ — embedded FalkorDB database files

By keeping dataDir outside the plugin install directory, openclaw plugins uninstall and reinstall won't destroy the graph database. The operator controls the lifecycle of this directory.

openclaw config set plugins.entries.gralkor.config.dataDir /data/gralkor

How it works

User sends message
        │
        ▼
 ┌──────────────┐    search    ┌──────────────┐    query     ┌──────────────┐
 │ auto-recall  │ ───────────▶ │   Graphiti   │ ───────────▶ │   FalkorDB   │
 │    hook      │ ◀─────────── │     API      │ ◀─────────── │              │
 └──────────────┘    facts     └──────────────┘   subgraph   └──────────────┘
        │
        ▼
 Agent runs (with recalled facts as context)
        │
        ▼
 ┌──────────────┐    ingest    ┌──────────────┐   extract    ┌──────────────┐
 │ auto-capture │ ───────────▶ │   Graphiti   │ ───────────▶ │   FalkorDB   │
 │    hook      │              │     API      │  entities    │              │
 └──────────────┘              └──────────────┘   & facts    └──────────────┘

Graphiti handles the heavy lifting: entity extraction, relationship mapping, temporal tracking, and embedding-based search. Gralkor wires it into the OpenClaw plugin lifecycle. The Graphiti server and embedded FalkorDB run as a managed subprocess — started and stopped automatically by the plugin.

Troubleshooting

openclaw gralkor status says "Server process: stopped" Many things can cause this. Use the available diagnostics to narrow it down:

  • openclaw gralkor status — shows process state, config summary, dataDir, venv state, and (if unreachable) the connection error
  • Gateway logs — grep for [gralkor] boot: markers. You should see boot: plugin loaded, boot: starting, then boot: ready. A boot: ... failed: line tells you which stage broke
  • openclaw gralkor search <group_id> <query> — quick end-to-end check that the server is reachable and the graph has data (group ID is required; it's the agent ID with hyphens replaced by underscores)

Common causes:

  • uv not on PATH (Python itself is managed by uv — it fetches 3.12+ on demand and produces its own errors)
  • uv sync failed (network/registry issue, or on first boot ~1–2 min is normal — wait it out)
  • Missing or invalid LLM API key — the server starts but every operation fails
  • Stale server.pid in dataDir holding port 8001 (the manager tries to clean this up, but a SIGKILL'd predecessor can leave the port wedged)
  • On linux/arm64: bundled falkordblite wheel couldn't be resolved (not in server/wheels/, not cached in dataDir/wheels/, and the GitHub Release download failed)

First startup takes a long time Normal — Gralkor is creating a Python virtual environment and installing dependencies via pip. This takes ~1-2 minutes. Subsequent starts reuse the venv and skip pip.

Plugin loads but all graph operations fail Most likely: missing or invalid LLM API key. Check your provider API key configuration.

No memories being recalled

  • Check that autoRecall.enabled is true (it is by default)
  • Verify the graph has data: run openclaw gralkor search <group_id> <term> (group ID = agent ID with hyphens replaced by underscores)
  • Auto-recall extracts keywords from the user's message — very short messages may not match

Agent doesn't store conversations

  • Check that autoCapture.enabled is true (it is by default)
  • Conversations are flushed to the graph when the session ends or after 5 minutes of inactivity (configurable via idleTimeoutMs). On SIGTERM, all pending buffers are flushed before shutdown. If the process receives SIGKILL without prior SIGTERM, buffered messages may be lost.
  • Conversations where the first user message starts with / are skipped by design
  • Empty conversations (no extractable text) are skipped