Long-term memory for AI agents — every recall returns a conflict and confidence verdict. Open-source Python SDK with MCP server, local SQLite, BM25.
Project description
atlaso
Long-term memory for AI agents — every recall() returns a confidence verdict (is_confident, has_disagreement, agreement_score, conflict_peers) so your agent stops confidently retrieving stale or contradictory facts. Open-source Python SDK with MCP server. Local SQLite + BM25. Zero telemetry.
from atlaso import Memory
m = Memory()
m.add("Alice prefers dark mode", user_id="alice")
for hit in m.recall("dark mode", user_id="alice"):
if hit.has_disagreement:
print(f"⚠ conflicts with {hit.conflict_peers}")
elif hit.is_confident:
print(f"✓ {hit.content}")
else:
print(f"? lead, not settled: {hit.content}")
What makes atlaso different
Memory stores return hits. atlaso returns hits plus a verdict on whether the hits are settled. Built around Field 3.0 — polarity-aware deposits and dispersion-aware recall — so when two memories disagree, your agent finds out before the LLM does.
| atlaso | typical memory store | |
|---|---|---|
| Recall returns | hits + confidence + conflict verdict | hits |
| When sources disagree | flagged via has_disagreement |
silent |
| Retrieval backend | BM25 over SQLite FTS5 (local) | vector DB + embedding API |
| Schema | append-only with explicit contradicts edges |
mutable rows |
| LLM dependency | none required | usually required for embedding |
| MCP server | built-in (pip install atlaso[mcp] — 9 tools) |
typically a separate package |
| Cross-tenant isolation | per-user SQLite files | shared collection with filter |
| Telemetry | none | varies |
If you've used mem0, Letta, Zep, or Cognee — atlaso is the version that comes with a confidence signal on every recall, runs fully local with no API key, and ships an MCP server in the same pip install. Apache 2.0. 135 tests on the public surface. Python 3.10+.
Built around Field 3.0
Field 3.0 is the data model under the hood. Every deposit carries:
- Polarity —
positive/negative/cautionary/open— the stance of the claim. - Evidence grade —
anecdotal/observed/replicated/verified— gated by claim breadth. - Scope — six experimental facets (
note,model,dataset,env,version,n,seed) telling you under what conditions the claim holds. - Contradictions — first-class edges, not metadata. Revising a fact deposits a new one with
contradicts=[old_id]; the audit chain is preserved forever.
When an agent calls m.recall(...), results are grouped by scope, and every hit is annotated with whether it agrees with its neighbors, whether its scope-bag has internal disagreement, and whether the SDK considers it safe to act on. Your agent gets data back; it also gets a verdict on whether the data is settled.
Full docs: rendered at https://www.atlaso.ai/docs · plain Markdown in
./docs/for offline / on-GitHub reading · listed in the official MCP Registry.
Install
pip install atlaso # core library
pip install atlaso[mcp] # + MCP server (Claude Code, Cursor, Codex, Windsurf)
Python 3.10+. No phone-home, no analytics, no signup. The library runs entirely in your process against on-disk SQLite.
Quickstart — single user
from atlaso import Memory
m = Memory()
m.add("I prefer oat milk in lattes", user_id="me")
hits = m.recall("oat milk", user_id="me")
print(hits[0].content)
SaaS — multi-tenant
from atlaso import AsyncMemory
from fastapi import FastAPI, Depends
memory = AsyncMemory()
app = FastAPI()
@app.post("/remember")
async def remember(text: str, user = Depends(current_user)):
handle = memory.for_user(user.id) # bind to authenticated identity
return await handle.add(text)
The for_user(user.id) pattern is the recommended path. The lower-level memory.add(text, user_id="alice") exists for admin tooling but is the wrong shape for request handlers — see Authorization.
Recall with conflict awareness
results = m.recall("what does Alice eat?", user_id="alice")
print(results.explain())
# → "5 matching memories disagree. Read both groups before using as fact."
for r in results:
if r.has_disagreement:
print(f"⚠ {r.content} conflicts with {r.conflict_peers}")
elif r.is_confident:
print(f"✓ {r.content}")
else:
print(f"? unconfirmed: {r.content}")
results.explain() is action language, not internals. Empty / confident / disagreement / thin-evidence each get their own one-sentence verdict.
Memory health
print(m.health(user_id="alice").explain())
# → "Memory is healthy (FMI 82/100). Searches are returning confident answers."
The Field Maturity Index is a 0–100 geometric mean of Coverage × Precision × Resolution × Density — a single readable number for "how settled is what I know about this user?"
Retract, don't delete
m.retract(deposit_id, user_id="alice", reason="this fact was wrong")
Soft tombstone by default — the row stays citable in contradicts=. hard_delete=True is the GDPR/PII escape. reason= is required because Atlaso keeps a retraction trail.
What we deliberately don't ship
- No
update(). Atlaso deposits are immutable evidence. To revise an earlier finding, deposit a new one withcontradicts=[old_id]. The audit trail is the point. - No telemetry. Atlaso never phones home.
- No required LLM.
add()andrecall()work with pure SQL + lexical retrieval. Bring your own embedder/extractor only if you want them. - No cross-tenant footguns on autocomplete. Cross-tenant operations live in
from atlaso.admin import ...behind aconfirm="I_UNDERSTAND_THIS_CROSSES_TENANTS"literal. They never appear onm.<TAB>.
Framework integrations
atlaso[mcp] covers Claude Code, Cursor, Codex, Windsurf, Cline via MCP — zero per-framework code.
For Python agents, see the recipes in docs/recipes/:
pip install atlaso[langchain] and the four other framework extras are reserved namespaces — they install only atlaso core today and emit a one-line FrameworkExtraReservedWarning when the SDK detects the framework is installed alongside it. Real adapters land in v0.1.x.
Inspect what you have
m.peek("alice")
# PeekView(user_id='alice', showing 4 of 4, FMI 0/100):
# · [open ] Alice prefers dark mode in the UI
# · [open ] Alice's preferred coffee is oat-milk lattes
# · [open ] Alice's birthday is March 15
# · [open ] Alice usually wakes up around 7am
(The default polarity is open — undecided / observed-but-not-stance-claimed. Stronger polarities like positive or negative require corresponding evidence. See the Glossary below.)
m.peek(user_id) is the "show me what's stored without writing a query" primitive. It returns a PeekView that iterates like a list but renders as a compact table in your REPL or notebook.
Debug a recall
hits = m.recall("dark mode", user_id="alice")
print(hits[0].explain())
# Returned because the text matched (BM25 score 1.842).
# Polarity: open. Evidence: anecdotal.
# This bag has only one deposit on the context (no scope facets set).
# Treat as a lead, not a settled finding.
hit.explain() answers "why did I get this result and should I act on it?" in plain language — no Field 3.0 jargon leaks. Useful for production-debugging unexpected retrievals.
Use it from bash — atlaso CLI
Once pip install atlaso lands, the atlaso command is on PATH and every Memory verb has a CLI mirror. Same vocabulary as the Python API, same vocabulary as the MCP tools — one mental model:
atlaso add "Alice prefers oat milk" --user alice
atlaso recall "coffee" --user alice
atlaso peek alice
atlaso health alice
atlaso list-recent --user alice --limit 5
atlaso get <deposit_id> --user alice
atlaso contradict "Alice moved to Brooklyn" <old_id> --user alice --reason "user moved"
atlaso retract <deposit_id> --user alice --reason "wrong fact" # soft tombstone
atlaso retract <deposit_id> --user alice --reason "GDPR" --hard # purges FTS index too
Add --json to add / recall / get / list-recent / peek / health / contradict / retract to get machine-parseable output for piping into jq or shell scripts:
atlaso list-recent --user alice --limit 100 --json | jq '.[] | select(.polarity == "negative")'
atlaso recall "milk preferences" --user alice --json | jq '.is_confident'
atlaso --help lists every subcommand. Each subcommand has -h for its own usage. Errors print as atlaso <cmd>: <ErrorType>: <message> (no stack traces) so they're shell-friendly.
Health-check the install
$ atlaso doctor
atlaso doctor
──────────────────────────────────────────────────
✓ atlaso 0.1.0a3 importable
✓ Field 3.0 engine vendored
✓ storage path: /Users/me/work/.atlaso (auto-resolved)
✓ engine round-trip (add → recall → retract)
✓ atlaso[mcp] installed (run: python -m atlaso mcp)
──────────────────────────────────────────────────
OK — atlaso is healthy.
End-to-end install + path + engine sanity check in five seconds. Returns 0 on healthy, 1 if anything's broken.
Glossary
If the words below feel unfamiliar, read this once. Five sentences each.
- Deposit — a single saved fact. Immutable; revise by depositing a new one with
contradicts=[old_id]. - Polarity — the stance of the deposit:
positive(supported),negative(refuted),cautionary(works under conditions),open(undecided / question / hypothesis — this is the default). - Evidence grade — how strong the support is:
anecdotal(one source, no measurement),observed(one careful measurement),replicated(multiple independent measurements agree),verified(independently checked against ground truth). - Scope — the experimental facets describing under what conditions the claim holds:
note,model,dataset,env,version,n,seed. All optional. - Bag — deposits that share the same scope facets are in one "scope-bag." The dispersion signals (
is_confident,has_disagreement,agreement_score) are computed per-bag. - Contradicts — a list of deposit ids this finding supersedes. The new deposit + the contradiction edges are committed atomically.
- FMI — Field Maturity Index, a 0–100 health score. Geometric mean of Coverage × Precision × Resolution × Density. Returned by
m.health(); the four components are interpretable separately.
License
Apache 2.0.
Status
v0.1.0a6 — research preview, ships from PyPI on every release. The public API is design-locked for v0.1+; new methods may land, existing signatures and return types follow semver inside the alpha track. Read the release notes before upgrading.
Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file atlaso-0.1.0a6.tar.gz.
File metadata
- Download URL: atlaso-0.1.0a6.tar.gz
- Upload date:
- Size: 105.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70ab30f8d861aab0c1eacd611262531cf9bf4a7e4a47add885cdc0f94cea2934
|
|
| MD5 |
3f1f83f89e89da1ea3c0ed90369889db
|
|
| BLAKE2b-256 |
75959f388662157a73d893acb66ec6ce1db1d8f42ef569a9a24182654918d925
|
File details
Details for the file atlaso-0.1.0a6-py3-none-any.whl.
File metadata
- Download URL: atlaso-0.1.0a6-py3-none-any.whl
- Upload date:
- Size: 56.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d93a80e81d2f5035d708f15f75dfa1b2e3cbd30ecf3a31cbd85e0ae8aea4560f
|
|
| MD5 |
41b14bbe293b0c4cd2f5a071134f7bcd
|
|
| BLAKE2b-256 |
a7b6305bee2650c5cc491288f4d35e6fb52f674886a19a86924817a4248488d9
|