# Kronroe
[](https://github.com/kronroe/kronroe/actions/workflows/ci.yml)
[](https://crates.io/crates/kronroe)
[](https://docs.rs/kronroe)
[](https://pypi.org/project/kronroe/)
[](./LICENSE)
[](https://kronroe.dev)
**AI memory that never leaves the device.**
No server. No cloud. No data risk.
Kronroe is built for three audiences:
- **Privacy-regulated industries** — healthcare, education, legal, care homes.
Patient notes, student records, and case files never leave the device.
Bi-temporal storage means every fact has a full audit trail built in:
"what did we know, and when did we know it?" is a first-class query.
- **Mobile and offline-first apps** — iOS and Android developers who need AI
memory that works on a plane, in a hospital, in a care home with no wifi.
Ships as a Swift Package and a Kotlin/JNI library. The same engine runs in
WASM in-browser with zero network calls.
- **AI agent builders** — developers building agents that need to remember how
their understanding of the world has changed over time. Drop-in replacement
for Graphiti, mem0, and mcp-memory-service — without the Neo4j server,
without the cloud API, without data leaving your infrastructure.
---
## What
Every existing embedded graph database treats time as your problem. You add `created_at` to your properties. You write `WHERE valid_at BETWEEN ...` queries. The database does not know that "Alice works at Acme" was true in 2023 and false in 2024.
Kronroe treats bi-temporal facts as a **type-level design primitive enforced by the storage engine**:
```rust
// Assert a temporal fact — valid time is part of the engine, not your schema
db.assert_fact("alice", "works_at", "Acme", Utc::now())?;
// Point-in-time query — first-class operation, not a WHERE clause trick
let employer = db.facts_at("alice", "works_at", past_date)?;
// Invalidation — old fact gets valid_to set; history is preserved, never deleted
db.invalidate_fact(&fact_id, Utc::now())?;
// Full-text search across all current facts
let results = db.search("where does Alice work", 10)?;
// Semantic vector search — pass pre-computed embeddings, temporal filtering included
db.assert_fact_with_embedding("alice", "bio", "Software engineer", Utc::now(), embedding)?;
let nearest = db.search_by_vector(query_vec, 5, None)?;
```
This is the DuckDB move. DuckDB did not "do SQLite better" — it said analytical queries deserve their own engine design. Kronroe says temporal knowledge evolution deserves its own graph engine design.
## Why now
Three use cases are completely unserved:
- **Privacy-regulated industries** — healthcare providers, schools, care
homes, and legal tools want AI capabilities but cannot send sensitive
data to the cloud. GDPR, HIPAA, and sector-specific regulations make
cloud AI a compliance blocker. Kronroe runs entirely on-device —
zero data egress, full audit trail by design.
- **AI agent memory** — agents that need to remember, update, and query
facts about the world over time, without running a server. Kronroe
replaces Graphiti + Neo4j, mem0, and mcp-memory-service with a single
embedded library.
- **Mobile/edge** — iOS and Android apps that need AI memory without
network latency, server infrastructure, or per-call API costs.
The XCFramework and Kotlin/JNI library are under 6 MB and work offline.
The solutions developers reach for today (Graphiti + Neo4j, mcp-memory-service) require a running server, have no temporal model at the engine level, and do not run on mobile.
## Architecture
Pure Rust. No C dependencies. No network calls. Runs on every platform
where data privacy is non-negotiable.
| Storage engine | `crates/core/src/storage_append_log.rs` | Kronroe append-log backend |
| Full-text search | Kronroe lexical engine | BM25 + fuzzy matching (`feature: fulltext`) |
| Vector search | `crates/core/src/vector.rs` | Flat cosine similarity + temporal filtering (`feature: vector`) |
| Python bindings | `crates/python` | `PyO3` bindings for core + agent memory |
| MCP server | `crates/mcp-server` | stdio transport, 11 tools |
| iOS bindings | `crates/ios` | C FFI + XCFramework + Swift Package |
| Android bindings | `crates/android` | Hand-written JNI + Kotlin wrapper |
| WASM bindings | `crates/wasm` | In-memory backend only |
## Workspace
```
kronroe/
├── crates/
│ ├── core/ # kronroe — TemporalGraph engine, bi-temporal storage
│ ├── agent-memory/ # kronroe-agent-memory — high-level AgentMemory API
│ ├── mcp-server/ # kronroe-mcp — stdio MCP server binary
│ ├── python/ # kronroe-py — PyO3 bindings
│ ├── wasm/ # kronroe-wasm — WebAssembly bindings (in-memory)
│ ├── ios/ # kronroe-ios — C FFI staticlib + Swift Package
│ └── android/ # kronroe-android — JNI cdylib + Kotlin wrapper
├── python/
│ └── kronroe-mcp/ # pip shim — kronroe-mcp CLI entry point
└── docs/
```
## Quickstarts
### MCP server (Claude Desktop / any MCP client)
```bash
cargo install --path crates/mcp-server
```
Add to your MCP client config:
```json
{
"mcpServers": {
"kronroe": {
"command": "kronroe-mcp",
"env": { "KRONROE_MCP_DB_PATH": "~/.kronroe/memory.kronroe" }
}
}
}
```
The native `kronroe-mcp` binary is the supported MCP runtime. The server exposes
11 tools: `remember`, `recall`, `recall_scored`, `assemble_context`,
`facts_about`, `assert_fact`, `correct_fact`, `invalidate_fact`,
`what_changed`, `memory_health`, `recall_for_task`.
### Python
```python
from kronroe import KronroeDb, AgentMemory
db = KronroeDb.open("./memory.kronroe")
db.assert_fact("alice", "works_at", "Acme")
results = db.search("where does Alice work", 10)
memory = AgentMemory.open("./memory.kronroe")
facts = memory.facts_about("alice")
```
### Rust
```rust
use kronroe::{KronroeTimestamp, TemporalGraph, Value};
let db = TemporalGraph::open("./memory.kronroe")?;
let id = db.assert_fact("alice", "works_at", Value::Text("Acme".into()), KronroeTimestamp::now_utc())?;
let current = db.current_facts("alice", "works_at")?;
let historical = db.facts_at("alice", "works_at", past_date)?;
db.invalidate_fact(&id, KronroeTimestamp::now_utc())?;
```
## Capability Matrix
For stability guarantees and compatibility expectations across features/surfaces, see
[`docs/API-STABILITY-MATRIX.md`](./docs/API-STABILITY-MATRIX.md).
### Available (shipping in repo)
| Bi-temporal fact model + core CRUD (`assert_fact`, `facts_at`, `invalidate_fact`, etc.) | `crates/core/src/temporal_graph.rs` | `cargo test -p kronroe` |
| Full-text search (BM25 + fuzzy) | `crates/core/src/temporal_graph.rs` (`feature: fulltext`, default on core) | `cargo test -p kronroe search_ --all-features` |
| Vector search with temporal filtering | `crates/core/src/temporal_graph.rs`, `crates/core/src/vector.rs` (`feature: vector`) | `cargo test -p kronroe vector_ --all-features` |
| Atomic fact + embedding write transaction | `assert_fact_with_embedding` in core | see vector durability/error tests in core suite |
| Idempotent writes (`assert_fact_idempotent`) | core + agent-memory wrappers | `cargo test -p kronroe idempotent --all-features` |
| `AgentMemory` API surface (`remember`, `recall`, `recall_scored`, `assemble_context`, confidence + source assertions) | `crates/agent-memory/src/agent_memory.rs` | `cargo test -p kronroe-agent-memory --all-features` |
| MCP server (11 tools) + Python shim | `crates/mcp-server`, `python/kronroe-mcp` | `cargo test -p kronroe-mcp` |
| Python bindings (`KronroeDb`, `AgentMemory`) | `crates/python/src/python_bindings.rs` | `cargo build -p kronroe-py` + `./crates/python/scripts/run_runtime_smoke.sh` |
| iOS package artifacts + behavior tests | `crates/ios` | `cargo test -p kronroe-ios` and `./crates/ios/scripts/run-swift-tests.sh` |
| WASM bindings (in-memory engine, no persistent file backend) | `crates/wasm/src/wasm_bindings.rs` | `cargo build -p kronroe-wasm` |
| Android JNI bindings + Kotlin wrapper | `crates/android/src/android_bindings.rs` | `cargo test -p kronroe-android` |
| WASM playground live deploy + smoke verification | `.github/workflows/deploy-site.yml`, `site/scripts/smoke-playground.mjs` | merge to `main` triggers deploy + smoke summary |
### Experimental (feature-gated, API may change)
| Hybrid retrieval API (`search_hybrid`) with two-stage reranking + score breakdown | `kronroe` features `hybrid-experimental` + `vector` | Implemented and tested in core; intentionally marked experimental |
| Agent-memory hybrid recall path (text + vector fusion) | `kronroe-agent-memory` feature `hybrid` | Implemented via core experimental API; contract may evolve |
| Contradiction detection (singleton predicates, Allen's interval overlap, conflict severity/policy) | `kronroe` feature `contradiction` | Engine-native, no LLM required; agent-memory auto-registers common singletons |
| Uncertainty model (age decay, source authority, effective confidence at query time) | `kronroe` feature `uncertainty` | Engine-native, pure Rust math; agent-memory auto-registers default volatilities |
### Planned (not shipping yet)
| Rich NLP extraction/planning layer beyond current `AgentMemory` primitives | Planned |
## Contributing
Contributions are welcome. Before your first pull request is merged, you'll be asked to sign the [Contributor Licence Agreement](./CLA.md) — a bot will prompt you automatically. The CLA lets us maintain the dual-licence model while keeping the project open.
Naming standards for crate entrypoints and path references are documented in [`docs/NAMING-CONVENTIONS.md`](./docs/NAMING-CONVENTIONS.md).
## Licence
Kronroe is dual-licensed:
- **Open source** — [GNU Affero General Public Licence v3.0](./LICENSE) (AGPL-3.0) for open-source projects, personal use, and research
- **Commercial** — [Commercial Licence](./LICENCE-COMMERCIAL.md) for proprietary products and SaaS applications
If embedding Kronroe in a closed-source product, a commercial licence is required. See [LICENCE-COMMERCIAL.md](./LICENCE-COMMERCIAL.md) for details and how to get in touch.
Copyright © 2026 Kindly Roe Ltd