Atomic memory infrastructure for agents — atomic facts on write, atomic sub-question decomposition on read.
Project description
atomir
Atomic memory for LLM agents — atomic on both ends: facts are extracted and reconciled on write; questions are decomposed into sub-questions on read.
Why
Most memory systems store text blobs and retrieve with one fuzzy search. atomir doesn't:
- Write — split a message into atomic facts, then reconcile each (ADD / UPDATE-with-history / DELETE / NOOP). A similarity gate stops distinct facts over-merging.
- Read — decompose a question into sub-questions (only when useful), retrieve each, union the results. Surfaces facts a single-blob search misses.
Vendor-neutral: LLM, embedder, and store are interfaces chosen by config.
Defaults are fake, so it runs with no keys.
Install
pip install atomir # core, offline-capable
pip install "atomir[qdrant,api]" # Qdrant backend + HTTP API
pip install "atomir[langchain,langgraph]" # framework integrations
Quickstart
from atomir.assembly import build_memory_service
mem = build_memory_service() # backends from .env; defaults to fake (no keys)
mem.add("user123", "I'm vegetarian and my manager is Dana.")
hits = mem.search("user123", "who should I email about my project?")
print(hits["subquestions"], [r["text"] for r in hits["results"]])
mem.answer("user123", "who is my manager?") # composed answer + the facts used
mem.get_all("user123"); mem.delete("user123", fact_id); mem.reset("user123")
Real providers: copy .env.example → .env, then set backends + keys.
Providers
| Slot | Options | Config |
|---|---|---|
| LLM | fake groq openai anthropic ollama |
LLM_BACKEND, LLM_API_KEY, MODEL |
| Embedder | fake jina voyage openai ollama |
EMBED_BACKEND, EMBED_API_KEY, EMBED_DIM |
| Store | json qdrant |
STORE_BACKEND, STORE_URL / STORE_PATH |
Adding a provider is one class + one registry line. LLM_BASE_URL /
EMBED_BASE_URL target self-hosted or proxy endpoints.
Agent frameworks
atomir is the memory, not the model: recall before, remember after. Scope
memory by user_id — "user:1" (shared), "user:1#agent:x" (agent-private),
"acme|user:1" (multi-tenant).
LangChain — AtomirRetriever is a real BaseRetriever:
from atomir.integrations.langchain import AtomirMemory
mem = AtomirMemory(build_memory_service(), user_id="user:1")
retriever = mem.as_retriever()
LangGraph — drop-in nodes for multi-agent graphs:
from atomir.integrations.langgraph import recall_node, remember_node
g.add_node("recall", recall_node(mem)) # -> state["memories"]
g.add_node("remember", remember_node(mem)) # stores state["input"]
Agents coordinate through shared memory (persists across runs). Store durable
findings only. Runnable examples: examples/.
HTTP API
Run uvicorn atomir.api:app (or docker compose up). MemoryClient(url) wraps
these with identical shapes.
| Method | Path | Returns |
|---|---|---|
| POST | /memories {user_id, text} |
{operations, facts} |
| POST | /search {user_id, query, k?, decompose?} |
{subquestions, results} |
| POST | /answer {user_id, query, ...} |
{answer, subquestions, results} |
| GET | /memories?user_id= |
facts |
| DELETE | /memories/{id}?user_id= |
{deleted, id} |
| DELETE | /memories?user_id= |
{reset} |
| GET | /health |
{status, store, llm, embedder} |
Limitations
RECONCILE_MIN_SIM(default0.5) is embedder-dependent — re-tune witheval/tune.pywhen you switch embedders.- JSON store: atomic writes, but single-process and rewrites the whole file — dev / small scale only; use Qdrant otherwise.
- No multi-fact transactions; a partial
addself-heals on retry (writes are per-user serialized).
License
MIT
Project details
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 atomir-0.4.1.tar.gz.
File metadata
- Download URL: atomir-0.4.1.tar.gz
- Upload date:
- Size: 32.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc3710c4d17dc9c290fee26d0ce85e635695077f4393757fd5d9037d513d75d8
|
|
| MD5 |
7970d4eaf2a85e7483afa72c9b1bf2b3
|
|
| BLAKE2b-256 |
5e0564fd991be5a4a8e4284c00b4769c669a214d7bf8cad13fc82a4970774d78
|
File details
Details for the file atomir-0.4.1-py3-none-any.whl.
File metadata
- Download URL: atomir-0.4.1-py3-none-any.whl
- Upload date:
- Size: 44.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3917c8b03bb53c255d68647a04ab1f22a393b8dbf4756c0e89b6daf3e453e95d
|
|
| MD5 |
7a4e1c741b3327b519666b0f3629a7e3
|
|
| BLAKE2b-256 |
2c73227c5248249e345fa5d6261eab1dafbbe613e66f01be5367386d158ba64c
|