English · 中文
The embedded memory engine for AI agents — memory that doesn't rot, stays
current, and proves where every fact came from — plus Areev Loop, built-in
governed self-improvement, and areev run, a governed runtime that executes
agent workflows as durable, journaled, replayable runs.
Formerly published as DejaDB — the project continues here under the
Areev name. The old dejadb packages are frozen at 1.2.0; install areev
instead.
Embed it in-process, store memories as immutable content-addressed grains, query them with CAL (the Context Assembly Language), and hand the results straight to a model — on the default embedded backend: no server, no sidecars, no network hop in the recall path. Recall in microseconds — fast enough to run inside a real-time voice agent's turn, where a network memory call can't. Your agent's memory is a file you own. And when the deployment has nowhere to put a file — stateless containers, multi-instance services — the same engine runs over a PostgreSQL schema instead, same semantics, millisecond-class recall.
git for your agent's memory: log, diff, time-travel, forks with explicit merges, and encrypted incremental sync — built into the data model, because grains are content-addressed immutable objects.
Status: 1.0.2 — the .mg format and CAL are stable and documented (conformant
with the Open Memory Spec, OMS).
Grains → context assembly → CAL → the agent loop → Areev Loop, in one animated pass.
The web console — browse memories, inspect the graph, and run CAL with a live grain inspector (click to enlarge):
Agent memory today is a vector store plus an extraction pipeline — and audited deployments keep finding the same failure: the store fills with duplicates and stale values nobody can trace. Areev is a different shape: an engine you embed, built so memory can't rot silently.
- Doesn't rot — measured, not promised: memories are immutable,
content-addressed grains, so byte-identical re-writes collapse to one
grain; updates are supersessions, so recall returns 1 current value, 0
stale with the full history kept; 100% of grains trace to when and how
they entered. All deterministic, no LLM in the loop:
cargo run -p areev-bench --bin honesty_metrics. - Safe for agents that learn: in a self-improvement loop, rot compounds — an agent that keeps stale lessons and duplicates gets worse, not better. Supersession (revisions replace, never co-rank), lessons structurally linked to the experience that taught them, replay-idempotent sync, and point-in-time rollback of the memory file make the loop auditable and reversible: build an agent that learns.
- Self-improvement with governance — Areev Loop, built in: thirteen deterministic analyzers turn the agent's own history into recommendations — "this tool failed 71% of its calls", "these two facts contradict" — each citing the grains it was computed from, gated propose → review → apply → verify, undoable, and re-measured after apply. Zero model calls required; attach an LLM and its findings are grounded against the evidence and independently verified before a human ever sees them.
- A runtime that can prove what it ran —
areev run: every agent framework executes graphs; almost none can prove an execution afterwards. Crash recovery duplicates side effects, "who approved this?" is a Slack search, and "what did the agent actually do?" is a log grep.areev runexecutes a Workflow grain as a governed run whose journal lives in the same memory file: the intent is written before every dispatch and the result supersedes it, so a crash-window effect is redelivered under the same idempotency key — journaled as a redelivery — never minted as a duplicate;areev run verifyreplays the whole run from its journal and byte-compares every checkpoint; human approval gates enforce separation of duties (the principal who triggered an ask structurally cannot approve it); budgets (tokens / USD / wall-clock) are enforced per-superstep; andareev run cancelis a kill switch whose cancel-to-drain time is measured into the oversight report, not asserted. LangGraph-grade execution — Send fan-out, subgraphs, typed reducers, streaming, time-travel forks — with an audit story the frameworks don't have (EU AI Act Art. 12/14 map). - CAL-native:
RECALL/ASSEMBLE/EXISTS/HISTORY/ADD/SUPERSEDE— a query language where destruction is shaped: it takes a hash, an identity, or an age, never a predicate.DELETEisn't a token in the grammar; the three destructive statements each require an authorization grant and a recorded reason, write an audit record, and can be capped off per process. The right-to-erasure pair (REPORT SUBJECT/FORGET SUBJECT) shares one selector, so what a data-subject request discloses is exactly what an erasure removes — seedocs/gdpr.md. - Fast where it matters (measured, Apple M4 Max): structural recall ~30µs,
entity_latest~9µs, 50ms-cadence voice loop with live write-back 79µs p50 / 152µs p99 per frame recall. - Hybrid recall: structural + BM25 + vector legs fused with RRF; multilingual
by construction (Arabic and English ride every leg; unspaced CJK rides the
vector leg). Bring any embedder: the
EmbedBackendtrait in Rust, a callback in Python (set_embedder), or a command on every surface (--embed-cmd 'my-embedder'— text on stdin, JSON vector on stdout). - Distributed the git way: op-log streaming with generations and point-in-time restore; pull subscriptions for fleet-wide knowledge distribution; concurrent edits become branches with a deterministic provisional head — surfaced, merged explicitly, never silently lost.
- Private by design: local-first, no telemetry; optional AES-256-GCM encryption at rest with an Argon2id-derived key; deletion is a tombstone or crypto-erasure (destroy the key, destroy the memory). See Security.
- Model-native: built-in MCP server, Anthropic memory-tool backend adapter, budget-aware context rendering (SML / Markdown / TOON / JSON), tool-schema rendering for 9 provider formats, Python and Node bindings.
- A format you keep, with a paved road in: the
.mgformat is fully documented and OMS-conformant (byte-exact test vectors), so your memory outlives this engine — andareev migrateimports what you have today from mem0 (keeping its full edit history as supersession chains), Zep/Graphiti, Letta, LangMem/LangGraph, Basic Memory, or any store via generic JSONL.
Areev ships on all three registries — install the surface you need:
cargo install areev # the `areev` CLI
pip install areev # Python bindings
npm install @areev/areev # Node bindings (unscoped `areev` pending npm approval)No Rust toolchain? Every release also carries prebuilt areev binaries for
Linux (x86_64 / aarch64), macOS (Intel / Apple Silicon) and Windows x86_64:
curl -fsSL https://raw.githubusercontent.com/AreevAI/areev/main/scripts/install.sh | shIt installs to ~/.local/bin (/usr/local/bin as root; override with
AREEV_INSTALL), pins with AREEV_VERSION=v1.0.2, and verifies the download
against the release's SHA256SUMS. Or grab an archive straight from the
Releases page — handy in a
notebook, where the wheel covers the memory and the loop but areev ui (the
web console, including the review queue) lives in the binary.
Embedding the store in a Rust project? Add the library crates instead of the CLI:
cargo add areev-store areev-coreOr build from source (Rust 1.90+):
git clone https://github.com/AreevAI/areev
cd areev
cargo build --release # builds the `areev` binary
./target/release/areev --help
# Python bindings (maturin): maturin develop -m crates/areev-py/Cargo.toml
# Node bindings (napi-rs): cd crates/areev-js && npm ci && npm run buildStore a fact, recall it, hand it to a model — three commands, no ceremony
(--db is optional; it falls back to $AREEV_DB, then ~/.areev/default.db):
areev add john prefers "window seat" # subject relation object
areev recall john # → the stored fact, one JSON grain per line
areev recall john --render sml # → "john prefers window seat" as a model-ready blockPoint it at a specific file with -d mem.db (or export AREEV_DB=mem.db).
Then explore: areev cal '<QUERY>' runs the query language, areev ui opens the
web console (http://127.0.0.1:7437), and areev repl is an interactive CAL shell.
claude mcp add areev -- areev serve --mcp --db ~/.areev/code.db --ns claude-codeareev serve --mcp speaks newline-delimited JSON-RPC 2.0 on stdio and works
with any MCP client — see docs/mcp-reference.md.
Bring your memories with you — including their edit history:
areev migrate --from mem0 --file export.json --history history.json --db mine.db
areev migrate --from basic-memory --file ~/basic-memory --db mine.dbmem0 history events replay as real supersession chains (ADD → add, UPDATE →
supersede, DELETE → forget) with their original timestamps, so HISTORY
shows your memory's pre-import evolution; note-shaped sources land as live
memory-tool files under /memories. Re-running an import skips what's already
there. Per-source export one-liners: docs/migrate.md.
Memory is half the story. The other half is executing agents so that what they did is provable afterwards — journaled, resumable, replayable, and gated by humans where it matters. The 10-minute proof needs no LLM key:
areev run demo --db runs.db # seeds a 2-node plan: host tool → human approval
# (prints the workflow hash — a content-addressed grain)
areev run start --db runs.db --workflow <WF_HASH> --run-id demo-1 \
--input '{"who":"world"}' --tool-cmd 'printf '\''{"greeting":"hello"}'\'''
# → the host tool runs, then the run PARKS on the approval gate:
# {"kind":"requires_action","asks":[{"node":"approve","tool_call_id":"<ASK>",…}],…}Approve it — as a different principal, because the principal who started the run structurally cannot approve their own ask:
areev run respond --db runs.db --run-id demo-1 --ask <ASK> \
--result '{"approved":true}' --as user:officer
areev run resume --db runs.db --run-id demo-1 # → {"finished":"Completed"}
areev run verify --db runs.db --run-id demo-1 # replays the journal, byte-compares every checkpointThat verify is the point: every step wrote an intent grain before
dispatch and a result grain that supersedes it, plus a checkpoint per
superstep — so the run can be re-derived from its own journal and compared
byte-for-byte against what was stored. If anyone edited history, verify names
the checkpoint and the differing fields. From there, everything is a query,
not a log grep:
areev run-trace --run-id demo-1 # the full journal, in order
areev runs-touching --hash <HASH> # which runs produced/refined this grain (the reverse join)
areev run oversight-report --run-id demo-1 # the EU AI Act Art. 14 answers: gates, budgets,
# responders, MEASURED kill-switch drain time
areev run cancel --run-id demo-1 # the kill switch (lowest-privilege verb)
areev run fork --run-id demo-1 --as-run demo-1b --at 1 # time-travel: branch from superstep 1
areev run shadow --runs demo-1 # re-execute from the journal with ZERO side effectsReal plans go further than the demo, with the same guarantees:
- LLM nodes: leave a node unbound and it becomes an abstract node — a
journaled tool-calling loop (
--model claude-sonnet,openai:gpt-5,ollama:llama3.1, or any OpenAI-compatible endpoint; keys from the environment). Every model turn and tool call lands in the journal, so verify never needs to call the model. - Budgets that actually stop the run:
--max-tokens / --max-usd / --max-wall-ms / --max-supersteps. A budget-exhausted run parks at a checkpoint;areev run forkre-opens it under raised budgets exactly where it stopped. - LangGraph-grade control flow: conditional edges, bounded cycles,
Sendfan-out, subgraphs, typed reducers (append/sum/max/…), streaming events — all validated at plan load, all replayable. - Every surface: the same six verbs ride the MCP
server (
areev_run_*— host tools execute only via$AREEV_RUN_TOOL_CMD), the Python/Node bindings (db.run_start(…)/await m.runStart(…)), and the web console's Runs tab, which is the human approval queue (shared-token and anonymous callers are refused for approvals — the approver's identity is the audit record).
Because the plan, the journal, and the memory share one file, the run/memory
join comes free: an agent's tool call cites the run that made it, and a
fact's provenance names the runs that touched it. Full guide:
docs/run.md · compliance maps:
docs/eu-ai-act.md,
docs/procurement.md.
You don't have to adopt the runtime to get the governance. Two pip adapters
(in adapters/) put Areev underneath the framework you already
run:
# LangGraph: a checkpointer where one thread = one memory file you can
# diff, sync, and erase; plus a BaseStore and a trace mirror.
from areev_langgraph import AreevCheckpointSaver
graph = builder.compile(checkpointer=AreevCheckpointSaver("./threads"))
# CrewAI: memory storage where every consolidation rewrite is a supersession
# — "what did the agent believe before the LLM rewrote it" stays a query.
from crewai.memory import Memory
from areev_crewai import AreevStorageBackend
memory = Memory(storage=AreevStorageBackend("crew.db"))What that buys you over the in-memory/SQLite defaults: checkpoints form
supersession trees (time-travel and re-put both work, history kept); a
CrewAI record's source becomes a partition-keyed subject, so one
areev forget-subject "<source>" erases that user's records, history, and
index rows with a receipt — the right-to-erasure demo; and the trace/audit
mirrors are honest about loss: best-effort mode counts every dropped event,
guaranteed mode backpressures and never drops (the only mode a compliance
story may cite).
Memory rot compounds in a self-improvement loop: an agent that re-learns duplicates and keeps stale lessons doesn't plateau, it gets worse. Areev's write path is the safety mechanism for that loop — log raw experience, distill lessons into facts, track proficiency as a supersession chain:
areev remember --observer executor --content "Attempt 2: isolated the tempdir per test - PASSED."
areev cal 'ADD fact SET subject = "fix_flaky_tests" SET relation = "lesson"
SET object = "Shared tempdirs need per-test isolation." REASON "distilled from session 41"'
areev cal 'HISTORY WHERE subject = "fix_flaky_tests" AND relation = "proficiency"' # the learning curve
areev restore --db rewound.db --from ./checkpoints --until-hlc <T> # roll back a bad learning episodeDistilling the lessons is a model call, and it is yours to own: no model runs
unless you point Areev at one (--model provider:name or --llm-cmd, key
from the environment). Point remember at one and it extracts the facts for
you — stamped verification_status="unverified" with the model named on the
grain, after the raw text is already stored, so a hallucinated extraction is
reviewable and never costs you the source
(cookbook §9).
What the write path guarantees either way: revised lessons replace instead of
co-ranking, every lesson links back to the experience that taught it
(derived_from),
synced/replayed writes can't double-store, and a bad episode rewinds with
point-in-time restore (checkpoint first — the recipe shows the flow). Even a
paraphrased re-learning is caught: areev novelty reports the nearest existing
lesson so the harness supersedes it instead of adding a near-duplicate
(advise-only — it never drops a write itself). Full loop:
cookbook §10.
The section above is the loop by hand. Areev Loop governs it: it turns your agent's history into recommendations — evidence-cited, reviewable, undoable, measured — starting with zero model calls. The fastest way to see it needs no agent and no waiting:
import areev, json
db = areev.Areev("proof.db", actor="user:me")
for _ in range(5): db.record_tool_call("stripe_refund", '{"error":"rate_limited"}', is_error=True)
for _ in range(2): db.record_tool_call("stripe_refund", '{"ok":true}', is_error=False)
db.loop_run() # deterministic; never gated when bare
for r in json.loads(db.recommendations('{"status":"pending"}')): print(r["severity"], r["summary"])
# → high Tool "stripe_refund" failed 5 times (71% of calls): rate_limited
db.apply_recommendation(<hash>, because="retries belong in the client") # audited, undoableWhat that buys you:
- Your agent stops repeating what fails. Thirteen deterministic analyzers
(eleven default-on) cluster recurring tool failures into lessons, catch
duplicate and contradictory facts, flag stale grains, and surface forks —
computed over typed grains, never raw prose. With the recall-telemetry
sidecar on, three of them see memory utility, not just hygiene: facts
never recalled (
cold_grains), questions that keep coming back empty (coverage_gap), context budgets overflowing (budget_pressure). And withareev runjournaling executions into the same file,run_outcomereads run terminals per plan — "this workflow failed 4 of 6 runs (last error: …)", "this plan has spent $4.10 across 6 runs" — as analyzer findings with the run grains cited, not dashboard archaeology. Precision is measured, not asserted: 1.00 on the labeled fixture, with a 0.90 failure floor when the fixture runner is invoked (cargo run -p areev-bench --bin loop_precision). The reusable Effective Reliability arithmetic and loop correctness tests run in ordinary CI; the fixture binary itself is an explicit evaluation command. - Nothing changes behind your back. Four gates — propose → review → apply → verify — with separation of duties, a mandatory reason on every decision, a hash-chained audit grain per transition, and a stored inverse for every apply. Auto-apply is off unless a host policy file explicitly grants it, and never for destructive or LLM-originated changes.
- It proves whether its own advice worked. A recommendation that carries
a metric is re-measured after you apply it — at 1d / 7d / 30d checkpoints,
against what actually happened (did that tool failure recur?); a late
regression proposes a revert.
areev loop outcomesis the receipt. - Add an LLM for what determinism can't see — verified, never trusted.
areev loop run --model claude-sonnet(oropenai:gpt-5,ollama:llama3.1, any OpenAI-compatible endpoint, or--llm-cmd 'CMD') lets a model discover cross-fact issues like a semantic contradiction — but every draft must ground against the cited grains and survive an independent verifier (the proposer never grades itself) before it reaches the queue, andorigin = llmcan never auto-apply. "Nothing to report" is a first-class answer, so it doesn't invent findings to look busy.
The trajectory path keeps the typed evidence needed to replay or train from a
run: record-tool-call stores JSON arguments separately from results,
capture-stop preserves every ordered chat/content block, run-manifest
binds a run to a content-addressed configuration, and sampled ASSEMBLE
manifests record the exact included/dropped hashes plus the rendered digest.
Set --run-id to join full-mode recall telemetry to the same trajectory.
areev corpus --select '<READ CAL>' [--out train.jsonl] [--recipient ID] reuses CAL as the
authorized selector and streams OpenAI chat JSONL with tool definitions,
step-level loss weights/quality labels, elision records, and trace/model/policy/
subject-fingerprint bindings. Each export writes a replicating manifest grain
whose related_to edges name every source hash; --recipient records the
downstream trainer/model owner that must act on a stale-export notice. Later identity or retention
erasure reports which exported corpora are stale and must be retired or
re-derived; this is auditable suppression/re-derivation, not a claim that a
subject has been removed from model weights.
- It runs where you already run things — no daemon. A cheap, idempotent
command with watermark gates (
--min-new,--if-stale): a Claude CodeSessionEndhook, cron, CI (areev loop list --fail-on highexits 2 — a build gate), or theareev_loopMCP tool. And the loop closes into the agent:areev recall-hook --with-looprides the pending queue into the context Claude Code injects, so the agent sees its own recommendations without polling. The console (areev ui) shows the queue, recall sessions, and measured outcomes.
From a fresh install: areev init --db demo.db --template demo seeds a demo
corpus, areev loop run proposes across analyzers (areev loop reflect
sweeps the whole memory), and the Areev Loop tab in areev ui is the governed
review queue. Full guide: docs/loop.md · why the LLM layer
is verified, never trusted: docs/loop-reflection.md.
Embed the store in-process. Add it to your Cargo.toml:
[dependencies]
areev-store = "1"
areev-core = "1"Most agent hosts are async (Tokio, axum). Use AsyncAreev there — it runs each
operation on the blocking pool and tears the store down off the async worker, so
neither a call nor a drop can panic inside a runtime:
use areev_store::AsyncAreev;
use areev_core::types::Fact;
let db = AsyncAreev::open("agent.db").await?;
db.add(Fact::new("john", "prefers", "dark mode")).await?;
let latest = db.latest("caller", "john", "prefers").await?;In synchronous code (a CLI, a script, a test) use Areev directly:
use areev_store::Areev;
use areev_core::types::Fact;
let mut db = Areev::open("agent.db")?;
db.add(&Fact::new("john", "prefers", "dark mode"))?;
Areevis blocking and drives its own runtime, so it must not be called — or dropped — from inside an async runtime. Reach forAsyncAreevin async code.
import areev, json
m = areev.Areev("john.db", ns="caller")
m.add_fact("john", "prefers", "tea", confidence=0.95)
m.recall("john") # JSON string, newest-first — needs a subject
m.search("tea", k=5) # free text, when you don't have a subject.
# BM25-only out of the box, so it matches
# words that are present; install an
# embedder (below) for semantic hits like
# "hot drinks".
m.cal('RECALL facts WHERE subject = "john"')
m.memory_tool(json.dumps({"command": "view", "path": "/memories"})) # Anthropic memory-tool backendAreev(..., index_text=False) turns the BM25 index off for this file (a
deliberate re-stamp, reported by open_warnings()). That trades search()'s
text leg — keep it working by installing an embedder — for write latency that
stays flat as the file grows. add_batch(...) writes many grains in one
transaction; to load another system's export, prefer migrate().
const { Areev } = require('areev')
const mem = new Areev('john.db', 'caller') // 3rd arg: passphrase for AES-256 at rest
await mem.addFact('john', 'prefers', 'tea', 0.95)
await mem.recall('john') // JSON string, newest-first
await mem.cal('RECALL facts WHERE subject = "john"')
await mem.memoryTool('{"command": "view", "path": "/memories"}') // Anthropic memory-tool backendEvery method returns a promise — store calls run on libuv's thread pool rather than blocking the event loop. The constructor is the exception, so opening a file still fails at the line that opened it. Await your writes: promises settle in completion order, not call order.
One memory = one file is the edge story. In stateless deployments (Cloud Run,
autoscaled containers) there is no durable disk — so the same store runs over
one PostgreSQL schema per memory instead, behind the non-default
postgres cargo feature:
cargo install areev --features postgres
areev add luis prefers window_seat --db 'postgres://user:pass@host/db?schema=memory_luis'
areev recall --db 'postgres://user:pass@host/db?schema=memory_luis' --subject luisThe bindings ship with the backend built in — the same class takes a DSN where it takes a path:
m = areev.Areev("postgres://user:pass@host/db?schema=memory_luis")
areev.drop_postgres_schema(url, "memory_luis") # memory-level erasureconst m = new Areev('postgres://user:pass@host/db?schema=memory_luis')
dropPostgresSchema(url, 'memory_luis') // memory-level erasurelet mut m = Areev::open_postgres("postgres://user:pass@host/db", "memory_luis")?;Identical semantics by construction — the same store logic (fork election, supersession, op-log, BM25, hybrid recall) runs over either backend, pinned by a conformance suite that executes the same case list against both. The differences are deliberate and explicit:
- Latency class: point reads are microseconds embedded, milliseconds over a network. The voice frame path stays on the embedded backend by design.
- Multiple concurrent writers per memory: any number of app instances can
hold handles on the same schema. Write transactions claim their id blocks
from an in-schema counters row, which serializes them briefly — so the
op-log stays gapless and ordered for followers, racing supersedes of one
head produce one winner and one clean
SupersessionConflict, and readers never block (MVCC). One instance can likewise hold handles to many memories (the schema-per-tenant shape). - Vectors use pgvector; the
vector(dim)column is created when the first embedder is installed, and a dimension mismatch is a hard refusal rather than a degraded leg. - Erasure and portability map to schema operations:
pg_dump -n <schema>exports a memory,DROP SCHEMA … CASCADEerases one (exposed asdrop_postgres_schema). Recall telemetry rides the memory's schema too. Page-level crypto-erasure remains a file-backend capability; encrypt at the deployment layer (TDE/pgcrypto) instead. - Right to erasure and retention (both backends):
forget_subjecterases every structured reference to one identity — full history, object references, thread events, the dictionary entry itself — with replicating tombstones;forget_older_thanis the age-based retention sweep. Both are host-level operations, deliberately not reachable from CAL; see docs/erasure.md for the scope contract and the documented OMS deviation. - HA is inherited: run it on a regionally-replicated Postgres and the memory inherits the failover, PITR, and backup story your ops team already drilled.
export AREEV_KEY="correct horse battery staple"
areev add --db secret.db --ns caller --subject john --relation prefers \
--object "window seat" --passphrase-env AREEV_KEY # AES-256-GCM, Argon2id keyareev stream --db john.db --to s3-mounted/john/ # continuous op-log shipping (~Litestream, grain-level)
areev restore --db new.db --from s3-mounted/john/ [--until-hlc T] # incl. point-in-time
areev follow --db org-replica.db --from org-pub/ # subscribe: org knowledge → every edge
areev verify --db john.db # integrity + full content-address recheckOne memory = one file: the unit of erasure (crypto-erase = key destruction), sync, portability, and write parallelism. Partition by user, org, category, or conversation — your call.
Reproducible harnesses in crates/areev-bench (accuracy, honesty, transport)
and crates/areev-store/examples (bench, voice_loop — the in-process
latency gates) — full methodology and raw data in
RESULTS.md; committed transcripts in
results/.
Memory quality — LoCoMo (10 conversations, 5,882 turns, 1,982 QAs), a plain retrieve-then-read pipeline with no task-specific tuning:
| retrieval leg | Areev |
|---|---|
hit@10 / hit@20 — OpenAI text-embedding-3-small |
74.5% / 81.6% |
End-to-end answer accuracy is 54.2% across all 1,982 QAs (gpt-4o-mini reader,
gpt-4o judge, k=20) — a cheap, untuned reader over that retrieval, where the
reader (not recall) is the ceiling; a stronger reader lifts it. Bring your own
models ($AREEV_LLM_CMD / $AREEV_JUDGE_CMD) and embedder (the EmbedBackend
trait; the no-API TF-IDF floor still scores 40.7% hit@10). Every answer and judge
verdict is committed for audit — the category has a history of unreproducible
claims, so we publish the receipts:
transcripts
(summary).
Memory integrity — honesty metrics (structural, deterministic, no LLM):
byte-identical writes settle to one grain (idempotent import, sync replay,
and retries — paraphrase dedup is host-side); after 20 updates recall returns
1 current value, 0 stale with full history kept; writes cost ~136µs and
0 LLM calls (text index off or deferred; a live FTS index adds ~140ms/write
— RESULTS.md finding #1); 100% of grains trace to when/how they entered.
cargo run -p areev-bench --bin honesty_metrics.
Latency (Apple M4 Max) — the microseconds that make an embedded engine a different shape from a memory service:
| recall operation | p50 | p99 |
|---|---|---|
entity_latest (in-process) |
~9 µs | — |
| structural recall (in-process) | ~30 µs | — |
| inside a 50 ms voice frame, live write-back | 79 µs | 152 µs |
| same recall via localhost HTTP sidecar | 158 µs | 264 µs |
| same recall via MCP stdio (agent host) | 129 µs | 205 µs |
Every surface above fits inside 0.6% of a 50 ms audio frame; the two transport rows show the cost is the network hop, not the store — the whole argument for embedding it.
On edge hardware — benchmarked on the devices themselves, not extrapolated.
A $35 Raspberry Pi 3 B from 2016 (1 GB RAM, 1.2 GHz Cortex-A53, consumer
microSD) serves recall at ~361 µs, flat from 500 to 8,000 grains; an
Intel NUC8i3BEH from 2018 (i3-8109U, NVMe) does the same in ~30 µs —
matching the M4 Max figure above, through the Python binding's FFI. Both install
with pip install areev in 16 seconds, no compiler. 16× the corpus, same
latency: a device can accumulate memory for months and answer as fast on day 200
as on day 1. The write path is the one thing to design for (bulk-load at
0.4–4 ms/grain vs 24–201 ms with a live FTS index). Clock-certified per phase,
with a projection for current Pi hardware:
RESULTS.md §6.
| Doc | For |
|---|---|
ARCHITECTURE.md |
How Areev works: grains, .mg format, CAL, recall, sync |
docs/loop.md |
Areev Loop — governed self-improvement (analyzers, four gates, policy, CLI/bindings/MCP/API) |
docs/loop-reflection.md |
The reflection engine — how LLM proposals are grounded, verified, and measured |
docs/run.md |
areev run — the governed runtime guide: authoring plans, the journal, verify, HITL, budgets, forks, every surface |
docs/eu-ai-act.md · docs/procurement.md |
EU AI Act article→capability→command map, and the procurement/security questionnaire answers |
docs/deployment-profile.md |
Deploying the runtime + adapters: modes, auth, SSO, what each mode may claim |
docs/cal-reference.md |
The CAL query language reference |
docs/mcp-reference.md |
The MCP server + its 23 tools |
docs/migrate.md |
Importing from mem0, Zep, Letta, LangMem, Basic Memory, JSONL |
docs/memory-tool.md |
The Anthropic memory-tool backend (Python / Node / CLI) |
docs/cookbook.md |
Task-oriented recipes |
FAQ.md |
Questions & answers (also LLM-friendly) |
SECURITY.md · docs/security-model.md |
Security policy & threat model |
docs/gdpr.md · docs/erasure.md |
GDPR obligations → capabilities (for a DPIA), and the erasure requirement record |
AGENTS.md · llms.txt |
For AI agents working in / with this repo |
CONTRIBUTING.md |
How to contribute (DCO sign-off) |
Areev is local-first and collects no telemetry. Optional AES-256-GCM encryption at rest protects the database and its CAS attachment sidecar (key derived from a passphrase via Argon2id); deleting a memory is a tombstone or crypto-erasure. The web console binds loopback with no auth by design and refuses to expose itself to the network without an explicit opt-in.
Read the honest threat model before deploying beyond a local machine, and report vulnerabilities per our security policy — please don't open public issues for them.
Software can't be GDPR-compliant — a deployment is. What Areev gives you is the mechanism, and the evidence:
areev subject-report "pat" --db memory.db --ns caller --out pat.jsonl --bundle pat.mgb
areev forget-subject "pat" --db memory.db --ns caller --yes --because "Art. 17 request #42"
areev audit export --db memory.db --out evidence.jsonlThe report and the erasure run one selector, so what an access request
discloses is exactly what an erasure removes — including partition keys
(pat#visit1) and the full supersession history, and optionally prose
mentions. The .mgb bundle is the Art. 20 portability artifact. The audit
record names a fingerprint of the identity, not the identity: verifiable by
recomputation, unusable for enumeration — because an immutable, replicating
audit grain that named the subject would undo the erasure it records.
docs/gdpr.md is the article→capability map to lift into a
DPIA, including the deployment requirements (one hub per trust domain, TLS
proxy off-loopback, a documented archive-retention window) and the limits
stated honestly.
| Crate | What |
|---|---|
areev-core |
.mg format, canonical serialization, content addressing, 12 grain types, tool-schema rendering |
areev-store |
Turso-backed store: dictionary-encoded triples, hybrid recall, heads/forks, blobs (CAS), bundles/streaming, memory-tool adapter |
areev-cal |
CAL lexer/parser/executor, multi-source ASSEMBLE, saved queries, AreevFacade (+ read-only mounts) |
areev-context |
Budget-aware provider-optimal rendering (SML/TOON/Markdown/JSON) |
areev-loop |
The self-improvement engine — substrate-agnostic: analyzers, four gates, recommendation lifecycle, LLM verifier (no Areev deps) |
areev-loop-adapter |
Areev substrate adapter for Areev Loop + the recall-telemetry sidecar |
areev-llm |
Out-of-box LLM backends: Areev Loop reflection, remember extraction, and the runtime's tool-calling seam (OpenAI-compatible / Anthropic / Ollama) |
areev-run-core |
The pure areev run scheduler — sans-IO BSP step function, plan validation, frozen condition grammar; no clock/rand/IO in its dependency tree (CI-enforced) |
areev-run |
The areev run driver — journal, checkpoints, crash-resume, HITL respond, budgets, cancel, journal-consistent verify, shadow eval, OTel export |
areev-mcp |
Stdio MCP server — 23 tools: memory (areev_recall/add/…), the loop pair, DSAR/provenance reads, and the runtime six (areev_run_*) |
areev-server |
Local web console (memories / graph / query / Areev Loop queue / Runs approval queue / sessions) + areevd hub mode; per-principal auth, optional TLS (tls feature) and SSO trusted-header |
areev |
The areev binary |
areev-py |
Python bindings (import areev) |
areev-js |
Node bindings (napi-rs native addon, require('areev')) |
adapters/ |
pip packages areev-langgraph (checkpointer, store, trace mirror) and areev-crewai (memory backend, audit listener) |
Built on Turso Database (MIT) — see
THIRD-PARTY-NOTICES.md.
Contributions are welcome under the DCO — see CONTRIBUTING.md and our Code of Conduct. Questions and ideas: GitHub Discussions.
Licensed under either of Apache License 2.0 or MIT license at your option. Unless you explicitly state otherwise, any contribution you intentionally submit for inclusion is dual-licensed as above, with no additional terms. The OMS specification itself is CC0.



