Skip to content

Python Bindings

End-to-end Python examples. For the reference surface, see the Python API.

Everyday tree

from prollytree import ProllyTree

tree = ProllyTree()
tree.insert(b"hello", b"world")
tree.insert(b"foo", b"bar")

print(tree.find(b"hello"))           # b"world"

tree.update(b"hello", b"Hello!")
tree.delete(b"foo")

# Batch.
tree.insert_batch([(b"k1", b"v1"), (b"k2", b"v2")])

Persistent tree

tree = ProllyTree(storage_type="file", path="/tmp/prolly_data")
tree.insert(b"alpha", b"1")
# Data survives a restart.

Versioned store with branch/merge

from prollytree import VersionedKvStore, ConflictResolution

store = VersionedKvStore("./my_store")
store.insert(b"config:theme", b"light")
store.insert(b"config:lang",  b"en")
store.commit("initial config")

store.create_branch("darkmode")
store.update(b"config:theme", b"dark")
store.insert(b"config:animations", b"enabled")
store.commit("dark + animations")

store.checkout("main")
store.update(b"config:lang", b"fr")
store.commit("french")

ok, conflicts = store.try_merge("darkmode")
assert ok  # no overlapping keys

merge = store.merge("darkmode", ConflictResolution.TakeSource)
print("merge:", merge[:8])

SQL

from prollytree import ProllySQLStore

sql = ProllySQLStore("./sql_store")
sql.execute("CREATE TABLE users (id INTEGER, name TEXT, email TEXT)")
sql.execute("INSERT INTO users VALUES (1, 'Alice', 'alice@example.com'),"
            "                          (2, 'Bob',   'bob@example.com')")

for row in sql.execute("SELECT id, name FROM users ORDER BY id"):
    print(row)

See SQL example for analytics-style queries.

Document versioning

from prollytree import VersionedKvStore
import json, datetime

store = VersionedKvStore("./docs_store")

doc = {"title": "My Document",
       "content": "Initial content",
       "author": "Alice",
       "created": datetime.datetime.utcnow().isoformat()}

store.insert(b"doc:readme", json.dumps(doc).encode())
store.commit("initial")

# Update.
doc["content"] = "Updated with more details"
doc["modified"] = datetime.datetime.utcnow().isoformat()
store.update(b"doc:readme", json.dumps(doc).encode())
store.commit("expand")

for c in store.log():
    print(c["id"][:8], c["message"])

Configuration management

prod = {
    "database": {"host": "prod-db", "port": 5432, "ssl": True},
    "api":      {"rate_limit": 1000, "timeout": 30},
}

dev = json.loads(json.dumps(prod))   # copy
dev["database"]["host"] = "localhost"
dev["database"]["ssl"]  = False
dev["api"]["rate_limit"] = 10_000

store.insert(b"config:production",  json.dumps(prod).encode())
store.insert(b"config:development", json.dumps(dev).encode())
store.commit("seed configs")

Batch-insert benchmark

import time
from prollytree import ProllyTree

tree = ProllyTree()
start = time.time()
for i in range(1000):
    tree.insert(f"single:{i:04d}".encode(), f"v{i}".encode())
print("single:", time.time() - start, "s")

tree = ProllyTree()
start = time.time()
tree.insert_batch([(f"batch:{i:04d}".encode(), f"v{i}".encode()) for i in range(1000)])
print("batch:", time.time() - start, "s")

LangMem integration for AI agent memory

ProllyTree can be a drop-in backend for LangMem, giving AI agents versioned, branchable memory. This is the pattern Memoir is built on.

from prollytree import VersionedKvStore
from langgraph.store.base import BaseStore, Item
from langmem import create_manage_memory_tool, create_search_memory_tool
import json, time

class ProllyTreeLangMemStore(BaseStore):
    def __init__(self, repo_path: str):
        self.store = VersionedKvStore(f"{repo_path}/data")

    def put(self, namespace, key, value):
        prolly_key = f"{'/'.join(namespace)}#{key}".encode()
        self.store.insert(prolly_key, json.dumps(value).encode())
        self.store.commit(f"store memory: {key}")

    def get(self, namespace, key):
        prolly_key = f"{'/'.join(namespace)}#{key}".encode()
        v = self.store.get(prolly_key)
        if v is None:
            return None
        return Item(
            value=json.loads(v.decode()),
            key=key, namespace=namespace,
            created_at=time.time(), updated_at=time.time(),
        )

store = ProllyTreeLangMemStore("./langmem_store")

manage = create_manage_memory_tool(
    namespace=("memories", "user_001"),
    store=store,
    instructions="Store important user preferences and context",
)
search = create_search_memory_tool(
    namespace=("memories", "user_001"),
    store=store,
)

# Agent flow.
for memory in [
    {"content": "User prefers dark mode interfaces", "memory_type": "preference"},
    {"content": "User is learning ML with Python",   "memory_type": "context"},
]:
    manage.invoke(memory)

hits = search.invoke({"query": "user preferences"})
print("hits:", len(hits))

# Isolate experimental memories on a branch.
store.store.create_branch("experiment")
store.store.checkout("experiment")
manage.invoke({"content": "Testing new assistant features",
               "memory_type": "experimental"})
store.store.checkout("main")  # experimental memory stays isolated