Skip to main content

topodb

Embedded, temporal, graph-native memory for AI agents — Python bindings for the TopoDB engine.

TopoDB is a single-file property graph (redb-backed) with scoped recall, text + vector search, and bi-temporal edges. These bindings embed the engine in your process: no server, no daemon, one .redb file on disk.

Install

pip install topodb

Prebuilt wheels (abi3, Python ≥ 3.9):

Platform Architecture
Linux (manylinux) x86_64
Linux (manylinux) aarch64
macOS universal2 (x86_64 + arm64)
Windows x64

Other platforms build from the sdist (requires a Rust toolchain via maturin).

Quickstart

import topodb
from topodb import ops

# Indexing is opt-in per (label, prop): declare equality lookups and what
# full-text search should cover. Plain TopoDB.open() indexes nothing (fine
# for pure graph workloads); TopoDB.open_stored() reopens a file with the
# spec it was created with.
spec = {
    "equality": [{"label": "Entity", "prop": "name"}],
    "text": [{"label": "Memory", "prop": "content"}],
}

with topodb.TopoDB.open_with("memory.redb", spec) as db:
    r = db.submit([
        ops.create_entity("ada"),
        ops.create_memory("ada wrote the first program"),
        ops.link("#1", "#0", "ABOUT"),   # "#n" back-references the n-th op's new id
    ])
    ada_id, memory_id, edge_id = r["ids"]

    scopes = ["shared"]                  # reads always name the scopes they may see
    hits = db.search_text(scopes, "first program", 5)
    print(hits[0]["node"]["props"]["content"], hits[0]["score"])

    sg = db.traverse(scopes, seeds=[memory_id], max_hops=2)
    print([n["id"] for n in sg["nodes"]], len(sg["edges"]))

TopoDB.open(path) creates or opens a database with the default index spec; TopoDB.open_with(path, spec) sets an explicit index spec (equality + text indexes) on create; TopoDB.open_stored(path) reopens with whatever spec the file already carries. The handle is a context manager — leaving the with block closes it, and any later call raises ClosedError.

Writes: ops builders + submit

All mutation goes through db.submit(batch), one atomic batch of command dicts. The topodb.ops module builds those dicts (the same wire shapes the CLI and MCP server speak):

ops.create_entity(name, scope=None)
ops.create_memory(content, scope=None)
ops.create_node(label, props=None, scope=None)
ops.link(from_, to, type, props=None, scope=None, valid_from=None)
ops.set_node_props(id, props)      # a None value inside props deletes that prop
ops.remove_node(id)
ops.close_edge(id, valid_to=None)
ops.set_embedding(id, model, vector)

Within a batch, "#0", "#1", … refer to the ids created by earlier ops in the same batch. submit returns {"first_seq", "last_seq", "ids"} — one ULID string per op. Pass now_ms= to pin the write timestamp (defaults to the wall clock) and default_scope= to stamp the whole batch (see below).

The multi-scope read model

Every read takes a list of scopes as its first argument and only sees data stamped with one of them. Every write is stamped with exactly one scope — per-op via the builder's scope= parameter, or batch-wide via db.submit(batch, default_scope=...). A scope is "shared" or a ULID string.

This asymmetry is the point: an agent can read across ["shared", project_scope] while writing only into project_scope.

db.node(scopes, id)                                  # dict or None
db.nodes_by_label(scopes, label)
db.nodes_by_label_newest(scopes, label, k)
db.nodes_by_prop(scopes, label, prop, value)         # equality-indexed props only
db.nodes_by_prop_normalized(scopes, label, prop, value)
db.nodes_by_float_range(scopes, prop, lo, hi)
db.edges_from(scopes, id, type=None)
db.traverse(scopes, seeds=[...], max_hops=n,
            edge_types=None, direction="both", as_of=None)
db.search_text(scopes, query, k)
db.search_vector(scopes, model, vector, k)
db.recall(scopes, query, k, vector=(model, vec), labels=None, now_ms=None)
db.suggest_links(scopes, id, k, model=None)

Nodes come back as plain dicts: {"id", "scope", "label", "props"}. Search hits are {"node", "score"}.

Bi-temporal edges

Edges carry two independent time axes, both in the wire dict:

  • World timevalid_from / valid_to: when the fact was true in the world. Settable on write (ops.link(..., valid_from=...), ops.close_edge(id, valid_to=...)); valid_to is None while the edge is open. traverse(..., as_of=t) answers "what was true at t".
  • Belief timerecorded_at / superseded_at: when the database learned and stopped believing the fact. Stamped by the engine, never settable; superseded_at is None while the edge is current.

The two differ whenever a fact is recorded late or corrected after the fact. Full edge shape:

{"id", "scope", "type", "from", "to", "props",
 "valid_from", "valid_to", "recorded_at", "superseded_at"}

Errors

All errors derive from topodb.TopoDBError, so one except catches everything; subclasses carry the detail:

Exception Meaning Extra attributes
StorageError I/O or storage-layer failure
EncodingError corrupt or undecodable stored data
RejectedError invalid batch, arguments, or unindexed-prop query
CompactedError requested ops feed range was compacted away oldest — first seq still available
BusyError database file held by another process; retryable
ClosedError handle used after close()
UnsupportedFormatError file format version mismatch found, supported

Change feed

db.subscribe(capacity) returns a Subscription that yields committed ops as dicts. sub.next(timeout=...) returns the next event or None on timeout (the GIL is released while waiting), and the object is also a plain iterator that ends when the database closes. db.ops_since(seq) / db.current_seq() / db.compact_ops(seq) cover catch-up and log compaction.

Embedded vs MCP

These bindings are the embedded client: in-process, zero-IPC, one Python process owning the file. If you want TopoDB behind an agent framework instead — shared across sessions, spoken over the Model Context Protocol — use the topodb-mcp server. Both speak the same wire shapes and the same batch DSL; see docs/agent-clients.md for the trade-offs.

Versioning

0.1.0 is the first published release of these bindings; it wraps the frozen 0.1 engine API. See the repository CHANGELOG.md for history from here on.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

topodb-0.1.0.tar.gz (2.3 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

topodb-0.1.0-cp39-abi3-win_amd64.whl (1.4 MB view details)

Uploaded CPython 3.9+Windows x86-64

topodb-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

topodb-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.5 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

topodb-0.1.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (2.9 MB view details)

Uploaded CPython 3.9+macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

Details for the file topodb-0.1.0.tar.gz.

File metadata

  • Download URL: topodb-0.1.0.tar.gz
  • Upload date:
  • Size: 2.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for topodb-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d034bfd1c6d73b06c34678299dd31e0a64ba3d66c69c2fdb66540898a5a12f62
MD5 f289d17c33a113dbf890d587d58963a5
BLAKE2b-256 ee03c3cc10d0658a0931fc72bfafab6643d48b7a4ddaeb30289f7b787ba2116a

See more details on using hashes here.

Provenance

The following attestation bundles were made for topodb-0.1.0.tar.gz:

Publisher: bindings.yml on TopoDB/TopoDB

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topodb-0.1.0-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: topodb-0.1.0-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 1.4 MB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for topodb-0.1.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 8c55f6e10397b99e2fb8b90ecb2fd0bd1f99e4645d7f1e15c6d0ccb74f6a698d
MD5 e7ce6d37427581f489a40ffe5c87505e
BLAKE2b-256 5bc01b5760c1d59a8fec03d8881dbfb1f47566c23032da4acaf64c54b679c45c

See more details on using hashes here.

Provenance

The following attestation bundles were made for topodb-0.1.0-cp39-abi3-win_amd64.whl:

Publisher: bindings.yml on TopoDB/TopoDB

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topodb-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for topodb-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2f5d0533d37fdda8f959803f128e0d323e1ed057b6ec0f7d4e283642c9341de0
MD5 dfc73ae23f95dd59833b1c4c5902edd6
BLAKE2b-256 cdee8ac1417ef28afbc4c9a32437e92e7113777cc64f4aadb831e6da42e99429

See more details on using hashes here.

Provenance

The following attestation bundles were made for topodb-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: bindings.yml on TopoDB/TopoDB

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topodb-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for topodb-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 6c5b5c9627d7158e29ee998ce71f4b5a37df29a8694461d3989763bc5299d7c6
MD5 26a64f688155ae76353a8b91c707876f
BLAKE2b-256 92c373ffb03d1b3d973756fbc1f7aa5c4fa02463365abe605c32e87a05ff6e4a

See more details on using hashes here.

Provenance

The following attestation bundles were made for topodb-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: bindings.yml on TopoDB/TopoDB

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topodb-0.1.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for topodb-0.1.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 1f8293ea7b8cceb12904ee5bad8165e2eb0c448ad1db1d72f721fb2d559425cc
MD5 ea140eb2f8354e05d941bbf5daa39913
BLAKE2b-256 6143fab41eadc964ce11a7ed4add70d431841b15a48fef4592efd87f05b97098

See more details on using hashes here.

Provenance

The following attestation bundles were made for topodb-0.1.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: bindings.yml on TopoDB/TopoDB

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

5 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page