tiramemsu
Your agent's brain loves Tiramemsu.
Layered, never-forget memory for agents, for Python.
Website · Time travel explained · Layered graphs explained · GitHub
Tiramemsu is an embedded graph database on SQLite. Every fact has its own id, so a fact can carry a confidence, a source or a belief about it, layer on layer. Every change is kept, with when the database learned it and when it was true in the world. This package is the Python binding: a native module (PyO3, stable ABI) and a typed, synchronous API.
Status: new. Tiramemsu was designed and implemented in September 2026. This package has not been published to PyPI yet, so the install line below works after the first release. Until then, build it from source.
Install
pip install tiramemsu
Python 3.9 or later. Each platform gets one prebuilt wheel (Linux x86_64 and aarch64, musllinux x86_64, macOS x86_64 and arm64, Windows x64), and SQLite is compiled in, so nothing else is needed. The package is typed (py.typed) and checked with mypy --strict.
Build from source instead
You need Python 3.9 or later and the Rust toolchain pinned by the repository (1.91.1).
git clone https://github.com/Volland/tiramemsu
cd tiramemsu/bindings/python
python3 -m venv .venv && source .venv/bin/activate
pip install maturin pytest mypy
maturin develop # or: maturin develop --release
pytest
If another rustc is first on your PATH (for example Homebrew's), put rustup's first: export PATH="$HOME/.cargo/bin:$PATH".
Quick start
Alice joins Acme in 2020, with a confidence of 0.8. We later learn she left at the end of 2023, and then that she joined Globex in March 2024.
from tiramemsu import Database, Iri
V = "urn:tiramemsu:v:" # written `v:` in queries
alice, works_at, acme, globex, confidence = (
Iri(V + name) for name in ("alice", "worksAt", "acme", "globex", "confidence")
)
db = Database("memory.db")
# 1. A fact is a statement with its own id, so it can carry a layer.
with db.transact() as tx:
job = tx.assert_(alice, works_at, acme, valid_from="2020-01-01")
tx.assert_(job, confidence, 0.8) # `job` is a Ref: the statement, before it has an id
first = tx.report.asserted[0] # its eid, known once the transaction has committed
# 2. Correct it. The layer moves to the new statement; nothing is deleted.
with db.transact() as tx:
tx.supersede(first, valid_to="2024-01-01")
# 3. A new fact.
with db.transact() as tx:
tx.assert_(alice, works_at, globex, valid_from="2024-03-01")
# 4. Ask the same question at different times.
q = "SELECT ?org WHERE { v:alice v:worksAt ?org }"
def orgs(view):
return [row["org"].value.rsplit(":", 1)[-1] for row in view.sparql(q)]
orgs(db.now()) # ['acme', 'globex'] both episodes are live
orgs(db.as_of(tx=1)) # ['acme'] what we believed after tx 1
orgs(db.as_of(tx=1).valid_at("2026-01-01")) # ['acme'] we thought she was still there
orgs(db.now().valid_at("2026-01-01")) # ['globex'] what is true today
orgs(db.now().valid_at("2024-02-01")) # [] between the two jobs
The same store speaks Cypher, and a layer is a relationship property:
db.now().cypher("MATCH (a)-[r:worksAt]->(c) RETURN c, r.confidence AS conf")
# columns ['c', 'conf'], rows [[acme, 0.8], [globex, None]] (Globex has no confidence layer)
Two clocks
A view chooses when you look and when the fact was true. Every read takes a view, and views are immutable.
| You want | Code |
|---|---|
| What we believe now | db.now() |
What we believed after transaction n |
db.as_of(tx=n) |
| What we believed at a wall-clock time | db.as_of(instant="2026-09-01T12:00:00Z") |
| What was true on a date | view.valid_at("2026-01-01") |
| Every statement ever, with retracted ones | db.history() |
valid_at combines with any of them. Valid time is off unless you ask for it. Time travel and bitemporality, explained has the full story.
Writing
db.transact() is a context manager. It records the operations of the block and commits them as one transaction when the block exits cleanly, and the report is on tx.report. If the block raises, nothing is committed. db.transact(ops) takes a list of operation dicts instead. assert_, create and supersede return a Ref that later calls in the same block accept as a statement id, a subject or an object.
| Method | What it does |
|---|---|
assert_(s, p, o, valid_from=, valid_to=, on_existing=) |
Adds a statement; idempotent when a live one with an overlapping valid time exists |
create(s, p, o, ...) |
Always adds one, for parallel edges |
retract(eid) |
Ends belief in a statement and every layer about it |
retract_matching(s=, p=, o=) |
Retracts every live match |
supersede(eid, o=, valid_from=, valid_to=) |
Corrects a statement and replays its layers on the new one. A bound you leave out is kept; None clears it |
confirm(eid) |
Records that another source agrees |
meta(p, o), upsert(p, o), new_node() |
Transaction metadata, unique upsert, an anonymous node |
add_to_graph(eid, g), remove_from_graph, clear_graph, create_graph, drop_graph |
Named graphs as tags on statements |
cypher(text, params=None) |
A Cypher query that may write, inside the same transaction |
Times accept a datetime, a date, epoch milliseconds or an RFC 3339 string. db.transact(dry_run=True) reports what would happen and commits nothing. db.speculate(ops, queries) applies changes hypothetically, runs queries on the result, and keeps nothing.
Reading
| Method | Returns |
|---|---|
view.sparql(text) |
A select result (iterate it for rows of variable to term; .vars lists the variables), an ask, a graph, or an update result |
view.cypher(text, params=None) |
A result with columns and rows |
view.triples(s=, p=, o=) |
Statement values with eid, s, p, o, t_add, t_ret, valid_from, valid_to, ret_kind |
view.path(start, expr, mode="reach", max_hops=None) |
Endpoints with hop counts. mode is "reach", "trail", "anyShortest" or "allShortest" |
view.events(since=0) |
The change log after a transaction |
view.graphs(), view.graph_members(g), view.values(s, key) |
Named graphs and values |
expr is SPARQL property-path syntax with the predeclared prefixes v:, sys:, tm:, rdf: and xsd:, for example v:knows+. SPARQL supports RDF 1.2 annotations: {| v:confidence ?c |} reads a layer.
Terms
| Python | Stored as |
|---|---|
str, bool |
plain string, boolean |
int |
xsd:integer, exact at any size |
float |
xsd:double |
datetime, date |
xsd:dateTime, xsd:date; they come back as the same Python types. A naive datetime is taken as UTC |
Iri(s) |
IRI |
Literal(lex, datatype=), Literal(lex, lang=) |
typed or language-tagged literal |
Node(n), BNode(n), Stmt(eid), TxId(n) |
anonymous node, blank node, statement id, transaction |
Errors
Every failure raises TiramemsuError with a .code:
| Code | Meaning |
|---|---|
Parse |
SPARQL, Cypher or path text is invalid |
InvalidArgument |
The call itself is malformed: an unknown operation, a missing field, a term of the wrong shape |
NotLive |
The statement does not exist or was already retracted |
Unsupported |
Valid but outside the supported subset, such as a Cypher write through a read view |
UniqueViolation |
A sys:unique predicate already has a live holder of that value |
ValueTypeMismatch |
The object does not match the predicate's sys:valueType |
CascadeLimitExceeded |
A retraction would touch more than max_cascade statements |
PathLimitExceeded |
A path search exceeded its state limit |
InvalidPatch |
A supersede patch tried to change the subject or predicate |
Sqlite |
A SQLite failure, such as a locked or unreadable file |
Options
Database(path, readers=, busy_timeout_ms=, term_cache_capacity=, optimize_every=, path_max_hops=, path_max_states=). It works as a context manager, and Python threads can query one Database in parallel, because the GIL is released during each call.
Good to know
- The API is synchronous, like the Rust core. Reads run in parallel on a small connection pool, and writes serialize on one writer.
- Nothing is ever deleted: the SQLite file rejects
DELETE. Forgetting means retracting, and the past stays exact. - Results cross the native boundary as JSON, which is fine for agent memory and not meant for million-row result sets.
- There is no MCP server, WASM build or network server yet.
License
MIT OR Apache-2.0, at your option. See LICENSE-MIT and LICENSE-APACHE.
Release files for tiramemsu 0.1.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 | |
|---|---|---|---|
| tiramemsu-0.1.0.tar.gz | 578.7 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| tiramemsu-0.1.0-cp39-abi3-win_amd64.whl | CPython 3.9 | abi3 | Windows x86-64 | Details |
| tiramemsu-0.1.0-cp39-abi3-musllinux_1_2_x86_64.whl | CPython 3.9 | abi3 | Linux musl 1.2+ x86-64 | Details |
| tiramemsu-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| tiramemsu-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| tiramemsu-0.1.0-cp39-abi3-macosx_11_0_arm64.whl | CPython 3.9 | abi3 | macOS 11.0+ ARM64 | Details |
| tiramemsu-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl | CPython 3.9 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 30.6 MB
Release files / tiramemsu-0.1.0.tar.gz
| Download URL | tiramemsu-0.1.0.tar.gz |
|---|---|
| Size | 578.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d1cfe949adf04dc80dafa3828d989b5f31fa3caf8fd4c70b82a0bcd5d16f6884
|
|
BLAKE2b-256 checksum How to use checksums |
339ee4d0948f686e8c4545e69d261390617f7a3b9f466e3388fd18da44af58f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 30, 2026.
Transparency logRelease files / tiramemsu-0.1.0-cp39-abi3-win_amd64.whl
| Download URL | tiramemsu-0.1.0-cp39-abi3-win_amd64.whl |
|---|---|
| Size | 4.7 MB |
| Tags | CPython 3.9 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
ebd2dc0125358f6a11fca5a790354410c721cb24abbc904a1a245f7954a24a98
|
|
BLAKE2b-256 checksum How to use checksums |
792e93fc732af6abd3d8a47af12e8377ae58afc203882768f0ea935f7577c877
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 30, 2026.
Transparency logRelease files / tiramemsu-0.1.0-cp39-abi3-musllinux_1_2_x86_64.whl
| Download URL | tiramemsu-0.1.0-cp39-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 5.5 MB |
| Tags | CPython 3.9 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
bd688f37db4ce32581a86f8c8ab9345eb31867f3f71eaa11087c81b0dc528970
|
|
BLAKE2b-256 checksum How to use checksums |
37a28dd4af3298c354c81981e2196184ab31f77c4ab30e21c620aa9ac5c33b1e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 30, 2026.
Transparency logRelease files / tiramemsu-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | tiramemsu-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 5.2 MB |
| Tags | CPython 3.9 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
a4c0e7626686d3e6461a800df4c947aa420c30ce642289c4ae065bc96d64d4a3
|
|
BLAKE2b-256 checksum How to use checksums |
9dc204bf10d964ca32f01ea0e01a3e4f9a1734e48b4d086e3fd29f1a97e6bc69
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 30, 2026.
Transparency logRelease files / tiramemsu-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | tiramemsu-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 5.0 MB |
| Tags | CPython 3.9 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
33d3f5287f4a1cdf4890a534d554cea2f4f5fd3e71d04571a7da5f48716adeda
|
|
BLAKE2b-256 checksum How to use checksums |
c26e15ea4787343e3a7753508f5e2d95b496f57a25cb6bb232963805a2280d88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 30, 2026.
Transparency logRelease files / tiramemsu-0.1.0-cp39-abi3-macosx_11_0_arm64.whl
| Download URL | tiramemsu-0.1.0-cp39-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 4.7 MB |
| Tags | CPython 3.9 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
120038cfdceea5923818c4bd97e93ff79c40a02e9f432086c938a6783d644600
|
|
BLAKE2b-256 checksum How to use checksums |
a896be4ffc5648a5455cc97791d874134145c2264a47ab566c1fa156330d04fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 30, 2026.
Transparency logRelease files / tiramemsu-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl
| Download URL | tiramemsu-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 4.9 MB |
| Tags | CPython 3.9 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
411fd0506f60b258b216c9000ec5849f3206c4d47f74d06b1333613b0c5a3cc3
|
|
BLAKE2b-256 checksum How to use checksums |
3743dc2591248a0f394779147446d95d85c022e9fdc02e621d5cbca103fef8a4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 30, 2026.
Transparency log