# Alaya

> Local memory engine for AI agents with knowledge graphs, forgetting, and semantic recall

- **Type:** MCP server
- **Install:** `agentstack add mcp-securityronin-alaya`
- **Verified:** Pending review
- **Seller:** [SecurityRonin](https://agentstack.voostack.com/s/securityronin)
- **Installs:** 0
- **Latest version:** 0.2.6
- **License:** MIT
- **Upstream author:** [SecurityRonin](https://github.com/SecurityRonin)
- **Source:** https://github.com/SecurityRonin/alaya

## Install

```sh
agentstack add mcp-securityronin-alaya
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Alaya

[](https://zenodo.org/badge/latestdoi/1167077192)
[](https://opensource.org/licenses/MIT)
[](https://www.rust-lang.org/)
[](https://crates.io/crates/alaya)
[](https://docs.rs/alaya)
[](https://www.npmjs.com/package/alaya-mcp)
[](https://pypi.org/project/alaya-memory/)
[](https://modelcontextprotocol.io/)
[](https://glama.ai/mcp/servers/SecurityRonin/alaya)
[](https://github.com/SecurityRonin/alaya)
[](https://github.com/sponsors/h4x0r)
[](https://github.com/SecurityRonin/alaya/actions)

The only memory engine with neuroscience-grounded memory dynamics — Bjork dual-strength forgetting, retrieval-induced suppression, and Hebbian co-activation — in a zero-dependency embeddable Rust library.

**Alaya** (Sanskrit: *alaya-vijnana*, "storehouse consciousness") is an
embeddable Rust library. One SQLite file. No external services. Your agent
stores conversations, retrieves what matters, and lets the rest fade. The
graph reshapes through use, like biological memory.

```rust
let alaya = Alaya::open("memory.db")?;
alaya.episodes().store(&episode)?;           // store
let results = alaya.knowledge().query(&query)?; // retrieve
alaya.lifecycle().consolidate(&provider)?;   // distill knowledge
alaya.lifecycle().transform()?;              // dedup, LTD, discover categories
alaya.lifecycle().forget()?;                 // decay what's stale
let cats = alaya.admin().categories(None)?;  // emergent ontology
alaya.admin().purge(PurgeFilter::Session("s1"))?; // cascade delete + tombstones
```

## The Problem

Most AI agents treat memory as flat files. OpenClaw writes to `MEMORY.md`.
Claudesidian writes to Obsidian. Hand-rolled systems write to JSON or
Markdown. It works at first.

Then the files grow. Context windows fill. The agent dumps everything into
the prompt and hopes the LLM finds what matters.

**The cost is measurable.** OpenClaw injects ~35,600 tokens of workspace
files into every message, 93.5% of which is irrelevant
([#9157](https://github.com/openclaw/openclaw/issues/9157)). Heavy users
report [$3,600/month](https://milvus.io/blog/why-ai-agents-like-openclaw-burn-through-tokens-and-how-to-cut-costs.md)
in token costs. Community tools like
[QMD](https://github.com/tobi/qmd) and
[memsearch](https://github.com/zilliztech/memsearch) cut 70-96% of that
waste by replacing full-context injection with ranked retrieval
([Levine, 2026](https://x.com/andrarchy/status/2015783856087929254)).

**The structure problem compounds the cost.** MEMORY.md conflates decisions,
preferences, and knowledge into one unstructured blob. Users independently
invent [`decision.md`](https://www.chatprd.ai/how-i-ai/jesse-genets-5-openclaw-agents-for-homeschooling-app-building-and-physical-inventories)
files, `working-context.md` snapshots, and
[12-layer memory architectures](https://github.com/coolmanns/openclaw-memory-architecture)
to compensate. Monday you mention "Alice manages the auth team." Wednesday
you ask "who handles auth permissions?" The agent retrieves both memories
by text similarity but cannot connect them
([Chawla, 2026](https://blog.dailydoseofds.com/p/openclaws-memory-is-broken-heres)).

## How Alaya Solves It

| Problem | File-based memory | Alaya |
|---|---|---|
| **Token waste** | Full-context injection (~35K tokens/message) | Ranked retrieval returns only top-k relevant memories |
| **No structure** | Everything in one file (users invent `decision.md` workarounds) | Three typed stores: episodes, knowledge, preferences |
| **No forgetting** | Files grow until you manually curate | Bjork dual-strength decay separates storage strength from retrieval strength; retrieval-induced forgetting (RIF) actively suppresses competing memories |
| **No associations** | Flat files, no links between memories | Hebbian co-retrieval strengthening (LTP/LTD): memories retrieved together strengthen connections; spreading activation finds indirect associations |
| **Brittle preferences** | Agent-authored summary, easily drifts | Implicit preferences emerge from accumulated impressions via vasana (perfuming), no LLM required; crystallize at threshold |
| **LLM required** | Can't function without one | Graceful degradation at every level. No embeddings? BM25-only. No LLM? Episodes accumulate. Each capability independently optional |

## Getting Started

### MCP Server (recommended for agents)

The fastest way to add Alaya memory to any MCP-compatible agent (Claude Desktop,
Claude Code, Cursor, Cline, etc.):

#### Via npm (no Rust toolchain needed)

Add to your Claude Code config (`~/.claude/claude_code_config.json`):

```json
{
  "mcpServers": {
    "alaya": {
      "command": "npx",
      "args": ["-y", "alaya-mcp"]
    }
  }
}
```

Or for Claude Desktop / other MCP clients (with optional LLM auto-consolidation):

```json
{
  "mcpServers": {
    "alaya": {
      "command": "npx",
      "args": ["-y", "alaya-mcp"],
      "env": {
        "ALAYA_LLM_API_KEY": "sk-...",
        "ALAYA_LLM_API_URL": "https://api.openai.com/v1/chat/completions",
        "ALAYA_LLM_MODEL": "gpt-4o-mini"
      }
    }
  }
}
```

#### From source (requires Rust 1.75+)

```bash
git clone https://github.com/SecurityRonin/alaya.git
cd alaya
cargo build --release --features "mcp llm"
```

Then add to your MCP config:

```json
{
  "mcpServers": {
    "alaya": {
      "command": "/path/to/alaya/target/release/alaya-mcp"
    }
  }
}
```

The `ALAYA_LLM_*` env vars are optional — without them, the server works in
prompt mode (reminds the agent to call `learn` after 10 episodes). With an API
key and the `llm` feature, it auto-consolidates instead.

That's it. Your agent now has 13 memory tools:

| Tool | What it does |
|------|-------------|
| `remember` | Store a conversation message (auto-prompts consolidation after 10 episodes) |
| `recall` | Search memory with hybrid retrieval (+ category boost) |
| `learn` | Teach extracted knowledge directly — agent extracts facts and calls this |
| `status` | Rich memory statistics: episodes, knowledge breakdown, categories, graph, embeddings |
| `preferences` | Get learned user preferences |
| `knowledge` | Get distilled semantic facts (+ category filter) |
| `maintain` | Run memory cleanup (dedup, decay) |
| `purge` | Delete memories by session, age, or all |
| `categories` | List emergent categories with stability filter |
| `neighbors` | Graph neighbors via spreading activation |
| `node_category` | Which category a node belongs to |
| `import_claude_mem` | Import observations from a claude-mem database |
| `import_claude_code` | Import conversation history from Claude Code JSONL files |

See [docs/mcp-quickstart.md](docs/mcp-quickstart.md) for a full walkthrough
with sample interactions and recommended system prompt.

Data is stored in `~/.alaya/memory.db` (override with `ALAYA_DB` env var).
Single SQLite file, no external services.

**Example interaction** — what your agent sees when using Alaya:

```
Agent: [calls remember(content="User prefers dark mode", role="user", session_id="s1")]
Alaya: Stored episode 1 in session 's1'

Agent: [calls recall(query="user preferences")]
Alaya: Found 1 memories:
  1. [user] (score: 0.847) User prefers dark mode

Agent: [calls status()]
Alaya: Memory Status:
  Episodes: 1 (1 this session, 1 unconsolidated)
  Knowledge: none
  Categories: 0
  Preferences: 0 crystallized, 0 impressions accumulating
  Graph: 0 links
  Embedding coverage: 0/1 nodes (0%)
```

**Environment variables:**

| Variable | Default | Description |
|----------|---------|-------------|
| `ALAYA_DB` | `~/.alaya/memory.db` | Path to SQLite database |
| `ALAYA_LLM_API_KEY` | *(none)* | API key for auto-consolidation (enables `ExtractionProvider`). Requires `llm` feature. |
| `ALAYA_LLM_API_URL` | `https://api.openai.com/v1/chat/completions` | OpenAI-compatible chat completions endpoint |
| `ALAYA_LLM_MODEL` | `gpt-4o-mini` | Model name. Any small/fast model works (GPT-4o-mini, Haiku, Gemini Flash, etc.) |

### Python Bindings

```bash
pip install alaya-memory
```

See [alaya-py/README.md](alaya-py/README.md) for the full Python API.

### Rust Library

For embedding Alaya directly into a Rust application:

```toml
[dependencies]
alaya = "0.2.2"
```

### Quick Start (Rust)

```rust
use alaya::{Alaya, NewEpisode, Role, EpisodeContext, Query, NoOpProvider};

// Open a persistent database (or use open_in_memory() for tests)
let alaya = Alaya::open("memory.db")?;

// Store a conversation episode
alaya.episodes().store(&NewEpisode {
    content: "I've been learning Rust for about six months now".into(),
    role: Role::User,
    session_id: "session-1".into(),
    timestamp: 1740000000,
    context: EpisodeContext::default(),
    embedding: None, // pass Some(vec![...]) if you have embeddings
})?;

// Query with hybrid retrieval (BM25 + vector + graph + RRF)
let results = alaya.knowledge().query(&Query::simple("Rust experience"))?;
for mem in &results {
    println!("[{:.2}] {}", mem.score, mem.content);
}

// Get crystallized preferences
let prefs = alaya.admin().preferences(Some("communication_style"))?;

// Run lifecycle (NoOpProvider works without an LLM)
alaya.lifecycle().consolidate(&NoOpProvider)?;
alaya.lifecycle().transform()?;
alaya.lifecycle().forget()?;
```

### Run the Demo

The demo walks through all eleven capabilities with annotated output and no
external dependencies:

```bash
git clone https://github.com/SecurityRonin/alaya.git
cd alaya
cargo run --example demo
```

## Architecture

Alaya is a library, not a framework. Your agent owns the conversation loop,
the LLM, and the embedding model. Alaya owns memory.

```
Your Agent                          Alaya
─────────                           ─────

Via MCP (stdio):                    alaya-mcp binary
  remember(content, role, session)    ──▶ episodic store + graph links
  recall(query, boost_category?)      ──▶ BM25 + vector + graph → RRF → rerank
  learn(facts, session_id?)           ──▶ agent-driven knowledge extraction
  status()                            ──▶ rich stats (episodes, knowledge, graph, embeddings)
  preferences(domain?)                ──▶ crystallized behavioral patterns
  knowledge(type?, category?)         ──▶ consolidated semantic nodes
  maintain()                          ──▶ dedup + decay
  purge(scope)                        ──▶ selective or full deletion
  categories(min_stability?)          ──▶ emergent ontology with hierarchy
  neighbors(node, depth?)             ──▶ graph spreading activation
  node_category(node_id)              ──▶ category assignment lookup
  import_claude_mem(path?)            ──▶ import from claude-mem.db
  import_claude_code(path)            ──▶ import from Claude Code JSONL

Via Rust library:                   Alaya coordinator
  alaya.episodes().store(ep)           ──▶ episodic store + graph links
  alaya.knowledge().query(q)           ──▶ BM25 + vector + graph → RRF → rerank
  alaya.admin().preferences(domain?)   ──▶ crystallized behavioral patterns
  alaya.knowledge().filter(f?)         ──▶ consolidated semantic nodes
  alaya.admin().categories(min?)       ──▶ emergent ontology with hierarchy
  alaya.admin().subcategories(id)      ──▶ children of a parent category
  alaya.graph().neighbors(node, d)     ──▶ graph spreading activation
  alaya.admin().node_category(id)      ──▶ category assignment lookup
  alaya.set_embedding_provider(p)      ──▶ auto-embed in store + query
  alaya.set_extraction_provider(p)     ──▶ enable auto-consolidation
  alaya.lifecycle().consolidate(p)     ──▶ episodes → semantic knowledge
  alaya.knowledge().learn(nodes)       ──▶ provider-less knowledge injection
  alaya.lifecycle().auto_consolidate() ──▶ extract + learn (needs ExtractionProvider)
  alaya.lifecycle().perfume(i, p)      ──▶ impressions → preferences
  alaya.lifecycle().transform()        ──▶ dedup, LTD, prune, split categories
  alaya.lifecycle().forget()           ──▶ Bjork strength decay + archival
  alaya.admin().purge(scope)           ──▶ cascade deletion + tombstones
```

### Three Stores

| Store | Analog | Purpose |
|-------|--------|---------|
| **Episodic** | Hippocampus | Raw conversation events with full context |
| **Semantic** | Neocortex | Distilled knowledge extracted through consolidation |
| **Implicit** | Alaya-vijnana | Preferences and habits that emerge through perfuming |

### Retrieval Pipeline

```mermaid
flowchart LR
    Q[Query] --> BM25[BM25 / FTS5]
    Q --> VEC[Vector / Cosine]
    Q --> GR[Graph Neighbors]

    BM25 --> RRF[Reciprocal Rank Fusion]
    VEC --> RRF
    GR --> RRF

    RRF --> RR[Context-Weighted Reranking]
    RR --> SA[Spreading Activation + Enrichment]
    SA --> RIF[Retrieval-Induced Forgetting]
    RIF --> OUT[Top 3-5 ResultsEpisodes + Semantic + Preferences]
```

### Lifecycle Processes

| Process | Inspiration | What it does |
|---------|-------------|--------------|
| **Consolidation** | CLS theory (McClelland et al.) | Distills episodes into semantic knowledge |
| **Perfuming** | Vasana (Yogacara Buddhist psychology) | Accumulates impressions, crystallizes preferences |
| **Transformation** | Asraya-paravrtti | Deduplicates, LTD link decay, prunes, discovers categories |
| **Forgetting** | Bjork & Bjork (1992) | Decays retrieval strength, archives weak nodes |
| **RIF** | Anderson et al. (1994) | Retrieval-induced forgetting suppresses competing memories |
| **Emergent Ontology** | Vikalpa (conceptual construction) | Hierarchical categories emerge from clustering; auto-split when too broad |

## Integration Guide

### Implementing ConsolidationProvider

The `ConsolidationProvider` trait connects Alaya to your LLM for knowledge
extraction:

```rust
use alaya::*;

struct MyProvider { /* your LLM client */ }

impl ConsolidationProvider for MyProvider {
    fn extract_knowledge(&self, episodes: &[Episode]) -> Result> {
        // Ask your LLM: "What facts/relationships can you extract?"
        todo!()
    }

    fn extract_impressions(&self, interaction: &Interaction) -> Result> {
        // Ask your LLM: "What behavioral signals does this contain?"
        todo!()
    }

    fn detect_contradiction(&self, a: &SemanticNode, b: &SemanticNode) -> Result {
        // Ask your LLM: "Do these two facts contradict each other?"
        todo!()
    }
}
```

Use `NoOpProvider` without an LLM. Episodes accumulate and BM25 retrieval
works without consolidation.

### Implementing ExtractionProvider (auto-consolidation)

The `ExtractionProvider` trait enables automatic knowledge extraction without
manual `consolidate()` calls. When configured, the MCP server auto-consolidates
after 10 unconsolidated episodes:

```rust
use alaya::*;

struct MyExtractor { /* your LLM client */ }

impl ExtractionProvider for MyExtractor {
    fn extract(&self, episodes: &[Episode]) -> Result> {
        // Ask your LLM: "Extract facts from these conversations"
        todo!()
    }
}

let mut alaya = Alaya::open("memory.db")?;
alaya.set_extraction_provider(Box::new(MyExtractor { /* ... */ }));

// Now auto_consolidate() works without a ConsolidationProvider
let report = alaya.lifecycle().auto_consolidate()?;
```

The `llm` feature flag provides a ready-to-use `LlmExtractionProvider` that
calls any OpenAI-compatible API:

```rust
use alaya::LlmExtractionProvider;

let provider = LlmExtractionProvider::builder()
    .api_key("sk-...")
    .model("gpt-4o-mini")      // default; any small model works
    .build()?;
```

### Lifecycle Scheduling

| Method | When to call | What it does |
|--------|-------------|--------------|
| `consolidate()` | After accumulating 10+ episodes | Extracts semantic knowledge from episodes |
| `perfume()` | On every user interaction | Extracts behavioral impressions, crystallizes preferences |
| `transform()` | Daily or weekly | Deduplicates, LTD link decay, prunes weak links, discovers categories |
| `forget()` | Daily or weekly | Decays retrieval strength, archives truly forgotten nodes |
| `purge()` | On user request | Cascade deletes by session/age/all with tombs

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [SecurityRonin](https://github.com/SecurityRonin)
- **Source:** [SecurityRonin/alaya](https://github.com/SecurityRonin/alaya)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Versions

- **0.2.6** — security scan: pending review — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-securityronin-alaya
- Seller: https://agentstack.voostack.com/s/securityronin
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
