recuerdos-ai
Python client for Recuerdos AI — a self-hostable long-term memory service for AI agents, over REST and MCP.
pip install recuerdos-ai
You need a running daemon. The fastest way:
docker run -p 7070:7070 -v recuerdos-ai-data:/data \
-e RECUERDOS_AI_AUTH__MODE=none ghcr.io/cooldevguys/recuerdos-ai
The loop
from recuerdos_ai import Client
ra = Client(base_url="http://localhost:7070", api_key="ra_live_…")
# Raw text in. The service decides what is worth remembering, splits it
# into atomic memories, and supersedes anything they contradict.
ra.save("btw we moved the backend to Hetzner, fly.io got too expensive. "
"Also always write table-driven tests in Go")
# Ask the question you actually have.
for hit in ra.search("where do we deploy?"):
print(hit.content) # "The backend runs on Hetzner (migrated from Fly.io …)"
save returns a job, because extraction is a model call that takes
seconds:
job = ra.save("User is vegetarian now")
finished = ra.wait_for_job(job)
print(finished.memory_ids)
# Or, for scripts:
memories = ra.save_and_wait("User is vegetarian now")
When you already know what to remember
save_direct stores one memory as given, with what it is and who it is true
for. It is cheap and synchronous, and still checked against what is stored for
the same scope: a contradiction is refused rather than stored alongside. Prefer
save unless you have already distilled the memory yourself.
saved = ra.save_direct(
"User forbids barrel files / index.ts re-exports",
kind="preference",
topic="coding",
applies_to="me",
origin="user_said",
tags=["typescript", "imports"],
)
print(saved.message)
The fields are explained in the repository's docs/memory-model.md. A memory
rule that refuses the save raises RejectedError with its code. For a
conflict, error.conflicts names the stored memories: ask the user, then save
again with replaces= (they changed their mind) or coexists_with= (both hold),
or fix the stored one with ra.update(...). ra.update also closes a goal:
ra.update(goal_id, goal_status="achieved", origin="user_confirmed").
Projects are listed with ra.projects(), renamed with
ra.rename_project("quill", "quill-app") (memories follow, the old name still
finds it) and merged with ra.merge_project("me-quill", into="quill").
Session distillation
At the end of a working session, hand over what happened and keep only what outlives it:
result = ra.distill_session(transcript, session_id="s-42", client="my-agent")
print(f"{result.distilled} memories survived the session")
distilled == 0 is the ordinary outcome. Most sessions produce nothing
that stays true after they end.
Session start
print(ra.profile()) # markdown, ~1500 tokens
Read it before the first turn. Recall answers a question; an agent that has not asked one yet still needs to know the conventions it is expected to follow.
LangChain
pip install "recuerdos-ai[langchain]"
from recuerdos_ai import Client
from recuerdos_ai.langchain import RecuerdosRetriever
retriever = RecuerdosRetriever(
client=Client(api_key="ra_live_…"),
limit=5,
categories=["preference.coding", "decision"],
)
docs = retriever.invoke("how should imports be structured?")
See examples/ for a LangGraph agent that reads its memory
at the start of a thread and writes back at the end.
Errors
Every failure is a RecuerdosError subclass, keyed off the API's
stable error code rather than its message:
from recuerdos_ai import NotFoundError, PermissionError_, RecuerdosError
try:
ra.get(memory_id)
except NotFoundError:
... # gone, or someone else's — indistinguishable by design
except PermissionError_:
... # valid key, missing scope
except RecuerdosError as error:
print(error.request_id) # ties this to the server log line with the real cause
Notes
- Sync only. Every call is one request to a service usually on
localhost; the work that takes seconds already happens off the request
path behind a job id. Inside an async framework, use
asyncio.to_thread. - A key is a user. There is no user parameter anywhere — two users means two clients.
search_report()issearch()plus the top level of the response: the relevance floor that produced the list, the server's owntook_ms, and what an enabled rerank stage did —applied,shadow,not_needed, orskippedwith a reason. A stage that misses[rerank].timeout_msserves the pre-rerank order on purpose, and this is how a client can tell that apart from the feature being off.- Unknown response fields are ignored, so an older SDK keeps working against a newer daemon.
Full reference: docs/sdk-python.md.
Apache-2.0.
Metadata
Release files for recuerdos-ai 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| recuerdos_ai-0.5.0.tar.gz | 34.9 kB | With provenance | Details for recuerdos_ai-0.5.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| recuerdos_ai-0.5.0-py3-none-any.whl | Python 3 | none | any | Details for recuerdos_ai-0.5.0-py3-none-any.whl |
Total release size: 58.0 kB
Release files / recuerdos_ai-0.5.0.tar.gz
| Download URL | recuerdos_ai-0.5.0.tar.gz |
|---|---|
| Size | 34.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f135fa4bb33a5a5f599f8ef62d33bab814efe5e73cf8cf777efb06b53fbe3e0f
|
|
BLAKE2b-256 checksum How to use checksums |
88d2758cd984a2ede992299358eea9cfa4f28bb57df118b686c6fa90406a99c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logRelease files / recuerdos_ai-0.5.0-py3-none-any.whl
| Download URL | recuerdos_ai-0.5.0-py3-none-any.whl |
|---|---|
| Size | 23.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
391d15ecf60290f47a086401806b31da8169d01dccd1e3f2d113393f7346b12f
|
|
BLAKE2b-256 checksum How to use checksums |
4936e56f739779e99b318519ba7dbb658c3de407d2760a1c8c160302d5e81fba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logSecurity for recuerdos-ai 0.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for recuerdos_ai-0.5.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 13, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.