Skip to main content
Glama
Xanther-Ai

Xanther memory Engine

Official

PyPI License Python 3.10+ MCP Server Local-first

Xanther Memory Engine โ€” session memory dashboard

pip install xanther-xme
xme hook install .      # 30 seconds โ€” auto-captures every session
xme start my-project    # memory starts now

Want code intelligence too? Install XME bundled with the Xanther Context Engine (XCE) in one command:

pip install "xanther-xce[all]"        # XCE + XME together
# or run instantly, no install:
uvx --from "xanther-xce[all]" xanther --help

๐Ÿš€ Why XME

Most LLM sessions are ephemeral. The agent solves a problem, then forgets it. The usual workarounds fall short:

  • Chat history captures conversations but isn't structured or searchable knowledge.

  • Bigger context windows still reset every session and cost tokens to refill.

  • Built-in agent memory is small, vendor-owned, and usually invisible โ€” gone if you switch tools.

  • RAG / vector DBs need infra and usually live in someone else's cloud.

XME takes a simpler path: three memory layers you own, on your machine, queryable over MCP.

  • Verbatim episodes so you can audit exactly what happened.

  • An extracted fact graph (decisions, attempts, preferences) with vector dedup.

  • Live working context that's always current, injected at the start of each session.

  • Facts link to the code they affect when XCE is installed alongside.


Related MCP server: evermemos-mcp

๐Ÿ”ง How it works

You are mid-refactor and the agent tried a Redis distributed lock last week that timed out under load. Without memory, it suggests the same thing again. With XME:

1. Capture (automatic). As you work, an IDE hook buffers every turn to .xanther/turns/ in under 5ms. Nothing blocks.

2. Persist on stop. When the agent stops, XME drains the buffer, extracts facts, and updates working context:

[ATTEMPT ยท FAILED] Redis distributed lock โ€” timeout under high load
[DECISION ยท VALIDATED] Use FastAPI โ€” async support required
Current task: Refactor auth module

3. Prime the next session. On xme_session_start, the agent gets a context block injected into its prompt:

Current task: Refactor auth module
Known failed approaches:
  - Redis distributed lock โ€” timeout under high load
Recent decisions:
  - [VALIDATED] Use FastAPI โ€” async support required

4. No repeated mistakes. The agent sees the failed Redis attempt and proposes something else โ€” building on history instead of relearning it.

The files stay yours (.xanther/xme.db, plus optional Neo4j/OpenSearch), inspectable and local.


Architecture

graph TB
    subgraph "AI Agent (Claude Code / Kiro / Cursor)"
        AGENT[Agent]
        HOOKS[IDE Hooks<br/>agentStop ยท promptSubmit]
    end

    subgraph "XME Memory Engine"
        ENGINE[MemoryEngine<br/>xme/engine.py]

        subgraph "Layer 1 โ€” Episodic"
            EP[EpisodicStore<br/>Verbatim session transcripts]
        end

        subgraph "Layer 2 โ€” Facts"
            FG[FactGraphStore<br/>Decisions ยท Attempts<br/>Preferences ยท Conventions]
            EXT[FactExtractor<br/>LLM or regex]
            EMB[LocalEmbedder<br/>all-MiniLM-L6-v2]
            EXT --> FG
            EMB --> FG
        end

        subgraph "Layer 3 โ€” Context"
            CTX[ContextStore<br/>Working state per project+user<br/>UPSERT semantics]
        end

        ENGINE --> EP & FG & CTX
    end

    subgraph "Storage"
        OS[(OpenSearch<br/>port 9200<br/>Full-text + k-NN)]
        NEO4J[(Neo4j<br/>port 7687<br/>Fact graph + vectors)]
        SQLITE[(SQLite<br/>.xanther/xme.db<br/>Context + fallback)]
    end

    subgraph "Outputs"
        MCP[MCP Server<br/>11 tools]
        DASH[Dashboard<br/>port 8001]
        EXP[Exports<br/>Obsidian ยท Wiki ยท Graphify]
    end

    HOOKS -- buffer files --> ENGINE
    AGENT -- MCP tool calls --> MCP
    EP --> OS & SQLITE
    FG --> NEO4J & SQLITE
    CTX --> SQLITE
    ENGINE --> DASH & EXP
    ENGINE --> MCP

Local Infrastructure

graph LR
    subgraph "Your Machine"
        subgraph "Docker Compose"
            NEO4J[(Neo4j:7687<br/>Fact knowledge graph)]
            OS[(OpenSearch:9200<br/>Episodic search)]
        end

        subgraph "XME Process"
            CLI[xme CLI]
            DASH[xme dashboard<br/>:8001]
            MCP_SRV[MCP Server]
        end

        subgraph "Hook Files"
            BUF[.xanther/turns/<br/>Buffer files<br/>written per turn]
            DB[.xanther/xme.db<br/>SQLite warm store]
        end

        subgraph "IDE"
            KIRO[Kiro / Claude Code]
            MCP_CFG[mcp.json]
        end
    end

    subgraph "External APIs (optional)"
        OR[OpenRouter API<br/>LLM fact extraction]
    end

    KIRO -- agentStop hook --> BUF
    KIRO -- promptSubmit hook --> BUF
    CLI -- drain buffer --> DB
    CLI -- index to --> NEO4J & OS
    MCP_CFG -- spawn --> MCP_SRV
    MCP_SRV -- read --> NEO4J & OS & DB
    KIRO -- MCP tool calls --> MCP_SRV
    CLI -. LLM extraction .-> OR
    DASH -- read --> NEO4J & OS & DB

Session lifecycle

sequenceDiagram
    participant IDE as Kiro / Claude Code
    participant HOOK as Hook Handler<br/>.xanther/hook.py
    participant BUF as Buffer<br/>.xanther/turns/
    participant XME as XME Engine
    participant DB as Neo4j + SQLite

    IDE->>HOOK: promptSubmit (user message)
    HOOK->>BUF: write turn JSON (< 5ms)

    IDE->>HOOK: promptSubmit (next message)
    HOOK->>BUF: write turn JSON

    Note over IDE,DB: ... more turns ...

    IDE->>HOOK: agentStop (response finished)
    HOOK->>BUF: write session_end marker

    Note over BUF,DB: On next xme start or xme_session_end MCP call

    XME->>BUF: drain all buffer files
    XME->>XME: extract facts (LLM or regex)
    XME->>DB: upsert facts with vector dedup
    XME->>DB: save episode to OpenSearch
    XME->>DB: update working context (UPSERT)

    Note over IDE,DB: Next session

    IDE->>XME: xme_session_start
    XME->>DB: load working context
    XME->>DB: load recent facts
    XME->>DB: load last episode summary
    XME-->>IDE: primed context block (inject into prompt)

Three memory layers

flowchart LR
    subgraph "Layer 1 โ€” Episodic"
        direction TB
        E1[Full session transcripts<br/>verbatim]
        E2[Searchable by:<br/>full-text ยท semantic ยท date ยท user]
        E3[Backend: OpenSearch<br/>Fallback: SQLite FTS5]
        E1 --> E2 --> E3
    end

    subgraph "Layer 2 โ€” Facts"
        direction TB
        F1[Extracted knowledge nodes]
        F2[Types:<br/>Decision ยท Attempt<br/>Preference ยท Convention ยท Entity]
        F3[UPSERT dedup<br/>cosine similarity > 0.85]
        F4[Backend: Neo4j graph<br/>+ vector index]
        F1 --> F2 --> F3 --> F4
    end

    subgraph "Layer 3 โ€” Context"
        direction TB
        C1[Live working state<br/>per project + user]
        C2[Fields:<br/>current_task ยท next_steps<br/>recent_decisions ยท blockers]
        C3[UPSERT only โ€” always current<br/>Backend: SQLite]
        C1 --> C2 --> C3
    end

    EP[Episodic\nStore] --> L1(Layer 1)
    FG[Fact\nGraph] --> L2(Layer 2)
    CTX[Context\nStore] --> L3(Layer 3)

    style L1 fill:#dbeafe
    style L2 fill:#dcfce7
    style L3 fill:#fef9c3

โšก Getting Started

1. Install

pip install xanther-xme

# Or bundled with the Xanther Context Engine (code graph + memory):
pip install "xanther-xce[all]"
# Run instantly without installing:
uvx --from "xanther-xce[all]" xanther --help

2. Choose an infrastructure mode

XME works with or without Docker. Pick one:

Zero infrastructure โ€” SQLite only, no Docker, works offline:

XME_FALLBACK_MODE=true xme start my-project

Full infrastructure โ€” Neo4j (fact graph) + OpenSearch (episodic search):

cp .env.example .env        # set NEO4J_PASSWORD (and OPENROUTER_API_KEY for LLM extraction)
docker-compose up -d        # starts Neo4j (:7687) + OpenSearch (:9200)
xme start my-project

No OpenRouter key? Fact extraction falls back to regex heuristics โ€” everything still works, just with slightly coarser facts.

3. Install the auto-capture hooks

This is the step that makes memory automatic. Hooks capture every agent turn and persist a session when the agent stops โ€” no manual recording needed.

# Install Kiro + Claude Code hooks into a repo (defaults to current dir)
xme hook install .

# Preview what would be written without changing anything
xme hook install . --dry-run

# Remove the hooks later
xme hook uninstall .

What gets installed:

Hook

IDE event

What it does

xme-record-turn

promptSubmit

Buffers each user turn to .xanther/turns/ (<5ms, non-blocking)

xme-record-tool

postToolUse

Buffers tool calls to the same journal

xme-session-end

agentStop / Stop

Drains the buffer โ†’ extracts facts โ†’ updates context โ†’ saves the session

The installer writes IDE-native config:

  • Kiro โ†’ hook files under .kiro/hooks/

  • Claude Code โ†’ hook entries in the project's Claude settings

So your agent can query and prime memory directly, add XME as an MCP server. Pick your client:

Add to ~/.kiro/settings/mcp.json (global) or .kiro/settings/mcp.json (workspace):

{
  "mcpServers": {
    "xme": {
      "command": "xme",
      "args": ["serve"],
      "env": { "NEO4J_PASSWORD": "your-password" },
      "autoApprove": ["xme_session_start", "xme_search", "xme_get_context"]
    }
  }
}
claude mcp add xme -- xme serve

Add to .cursor/mcp.json (project) or ~/.cursor/mcp.json (global):

{
  "mcpServers": {
    "xme": {
      "command": "xme",
      "args": ["serve"],
      "env": { "NEO4J_PASSWORD": "your-password" }
    }
  }
}

Add to your User Settings (JSON):

{
  "mcp": {
    "servers": {
      "xme": {
        "command": "xme",
        "args": ["serve"],
        "env": { "NEO4J_PASSWORD": "your-password" }
      }
    }
  }
}

If your client speaks MCP over stdio, point it at the xme serve command above. The tool names and behavior are identical across clients.

At the start of a session the agent calls xme_session_start to get a primed context block (current task, recent decisions, known-failed approaches) injected into its prompt.

5. Verify it's working

xme stats my-project      # memory health: fact / episode / context counts
xme dashboard             # visual timeline at http://localhost:8001

After a session or two, xme stats should show growing fact and episode counts. If they stay at zero, see Troubleshooting hooks below.

Troubleshooting hooks

  • Nothing captured? Confirm hooks installed: check .kiro/hooks/ (Kiro) or your Claude Code settings. Re-run xme hook install . --dry-run to see expected paths.

  • Buffer never drains? Facts are extracted on agentStop or on the next xme start / xme_session_end MCP call. Run xme start my-project to force a drain.

  • Neo4j errors? You can run fully local with XME_FALLBACK_MODE=true (SQLite only).

  • Buffer files live in .xanther/turns/; the warm store is .xanther/xme.db. Both are safe to inspect. Add .xanther/ to your .gitignore (memory is per-developer runtime state).


What gets captured automatically

After xme hook install .:

  • Every prompt is buffered to .xanther/turns/ (< 5ms, no blocking)

  • On agentStop: buffer drains โ†’ facts extracted โ†’ context updated

  • Next session: agent gets a primed context block injected automatically

**Current task**: Refactor auth module
**Last session**: Moved JWT to dedicated auth service โ€” success
**Recent decisions**:
  - [VALIDATED] Use FastAPI โ€” async support required
  - [VALIDATED] PostgreSQL โ€” ACID compliance
**Known failed approaches**:
  - Redis distributed lock โ€” timeout under high load
**Next steps**: Deploy auth service to staging

๐Ÿงฐ MCP tools (11)

Tool

Description

xme_session_start

Start session, get primed context block

xme_session_end

End session: persist episode, extract facts, update context

xme_add

Add content โ€” Mem0-style UPSERT with deduplication

xme_search

Search across all 3 layers simultaneously

xme_get_context

Get working context for prompt injection

xme_facts

Query fact graph (filter by type, user, keyword)

xme_episodes

Full-text + semantic search over past sessions

xme_remember

Explicitly store a typed fact

xme_forget

Soft-delete a memory node

xme_export

Export to Obsidian vault / wiki / Graphify JSON

xme_context_update

Partial UPSERT of working context fields

Add to MCP config:

{
  "mcpServers": {
    "xme": {
      "command": "xme",
      "args": ["serve"],
      "env": {
        "NEO4J_PASSWORD": "your-password"
      }
    }
  }
}

Deduplication

Facts are stored once, not repeated across sessions:

flowchart TD
    A[New content added] --> B[Embed with\nall-MiniLM-L6-v2]
    B --> C{Similar fact exists?\ncosine > 0.85}
    C -- Yes --> D[Merge into existing fact\nupdate content + metadata]
    C -- No --> E[Create new fact node]
    D --> F[Update Neo4j + SQLite]
    E --> F

๐Ÿ“Š How It Compares

Mem0

Zep

MemPalace

XME

Episodic memory

โœ…

โœ…

โœ…

โœ…

Fact graph

partial

โœ…

โŒ

โœ…

Working context UPSERT

โŒ

โŒ

โŒ

โœ…

Multi-user scoping

โœ…

โœ…

โŒ

โœ…

Deduplication

โœ…

โœ…

โŒ

โœ…

Local-first / open source

โŒ

โŒ

โœ…

โœ…

MCP tools

โŒ

โŒ

โŒ

โœ… (11)

Obsidian export

โŒ

โŒ

โŒ

โœ…

Dashboard UI

โŒ

โœ…

โŒ

โœ…

Code graph integration

โŒ

โŒ

โŒ

โœ… via XCE


CLI

xme start <project>              # init + show stats
xme add <project> <user> <text>  # add content to memory
xme search <project> <query>     # search all layers
xme facts <project>              # list facts
xme stats <project>              # memory health metrics
xme export <project>             # export (obsidian/wiki/graphify)
xme dashboard                    # launch web UI (port 8001)
xme hook install [path]          # install Kiro + Claude Code hooks
xme hook uninstall [path]        # remove hooks

Configuration

# LLM for better fact extraction (optional โ€” regex works without it)
OPENROUTER_API_KEY=sk-or-...
XME_LLM_MODEL=openai/gpt-4o-mini

# Neo4j โ€” fact graph (recommended, free tier at console.neo4j.io)
NEO4J_URI=bolt://localhost:7687
NEO4J_PASSWORD=your-password

# OpenSearch โ€” episodic search (optional, falls back to SQLite FTS5)
XME_OPENSEARCH_URL=http://localhost:9200

# Zero-infrastructure mode
XME_FALLBACK_MODE=false   # set true for SQLite-only, no Docker needed

See .env.example for the complete reference.


Xanther Context Engine (XCE) โ€” code graph intelligence. When installed alongside XME, decisions link directly to the code they affect.

pip install "xanther-context-engine[memory]"  # XCE + XME together

โญ Star Us on GitHub

If XME saves your agent from relearning your codebase every session, a star helps other developers find it and helps us keep building in the open.

License

Apache 2.0. See LICENSE.

Related MCP Connectors

Related MCP Servers