Skip to main content

DuxxDB — the database built for AI agents. Hybrid (vector + BM25 + structured) retrieval, agent-native primitives (MEMORY / TOOL_CACHE / SESSION), embedded-or-server, RESP / gRPC / MCP.

Project description

duxxdb — Python bindings

Native Python bindings for DuxxDB, the agent-native hybrid database. Built with PyO3 + maturin against the stable Python ABI (abi3-py38) so a single wheel supports Python 3.8 through 3.13.

Install

From a wheel (recommended)

pip install duxxdb-0.1.0-cp38-abi3-<platform>.whl

(For now, build the wheel locally — see the next section. Public PyPI release lands with v0.1.0.)

Build from source

# Prerequisites: Rust toolchain, Python ≥ 3.8.
pip install --user maturin
cd bindings/python
maturin build --release
pip install --force-reinstall ../../target/wheels/duxxdb-0.1.0-cp38-abi3-*.whl

On Windows + Git Bash the workspace uses the GNU toolchain — see ../../docs/SETUP.md for the WinLibs MinGW prerequisite.

Quickstart

import duxxdb

store = duxxdb.MemoryStore(dim=4)

def embed(text):
    """Replace this with a real embedder (OpenAI / Cohere / local BGE)."""
    import hashlib
    h = int(hashlib.sha1(text.lower().encode()).hexdigest()[:16], 16)
    v = [(h >> (i*4)) & 0xff for i in range(4)]
    norm = sum(x*x for x in v) ** 0.5 or 1.0
    return [x / norm for x in v]

store.remember(key="alice", text="I lost my wallet at the cafe", embedding=embed("wallet"))
store.remember(key="alice", text="My favorite color is blue",     embedding=embed("blue"))

hits = store.recall(key="alice", query="wallet",
                    embedding=embed("wallet"), k=3)
for hit in hits:
    print(f"{hit.score:.4f}  {hit.text}")

Output:

0.0328  I lost my wallet at the cafe
0.0161  My favorite color is blue

API surface

Embedded (native, no server required)

Class Constructor Methods
MemoryStore dim, capacity=100_000 remember(key, text, embedding) -> id, recall(key, query, embedding, k=10) -> [MemoryHit], len(), dim
MemoryHit (returned by recall) id, key, text, score
ToolCache threshold=0.95 put(tool, args_hash, args_embedding, result, ttl_secs=3600), get(tool, args_hash, args_embedding) -> ToolCacheHit | None, purge_expired(), len()
ToolCacheHit (returned by get) kind ("exact" or "semantic_near_hit"), similarity, result
SessionStore ttl_secs=1800 put(session_id, data), get(session_id) -> bytes | None, delete(session_id) -> bool, purge_expired(), len()
PromptRegistry dim=32, storage=None put(name, content, metadata=None) -> version, get(name, version_or_tag=None) -> Prompt | None, list(name) -> [Prompt], names() -> [str], tag(name, version, tag), untag(name, tag) -> bool, delete(name, version) -> bool, search(query, k=10) -> [(name, version, score, content)], diff(name, v_a, v_b) -> str
Prompt (returned by get / list) name, version, content, tags, metadata (decoded JSON), created_at_unix_ns
PromptHit (returned by search) prompt, score

Phase 7 (Phase-7 agent ops, native bindings new in v0.2.1)

Class Constructor Methods
CostLedger dim=32, storage=None record(tenant, model, tokens_in, tokens_out, cost_usd, ...), query(...), total(tenant), aggregate(group_by, ...), set_budget(tenant, period, amount_usd, warn_pct=0.8, ...), get_budget(tenant), delete_budget(tenant), status(tenant)
CostEntry / Budget (returned by ledger methods) typed fields incl. metadata (decoded JSON)
DatasetRegistry dim=32, storage=None create(name, schema=None), add(name, rows, metadata=None) -> version, get(name, version_or_tag=None), list(name), names(), tag/untag/delete, sample(name, version, n, split=None), size, splits, search(query, k=10, name_filter=None)
Dataset / DatasetRow (returned by registry) typed fields incl. metadata, data, annotations, schema (all decoded JSON)
EvalRegistry dim=32, storage=None start(...), score(run_id, row_id, score, output_text="", notes=None), complete(run_id) -> EvalSummary, fail(run_id, reason), get(run_id), scores(run_id), list(dataset_name=None, dataset_version=None), compare(run_a, run_b) -> tuple, cluster_failures(run_id, ...) -> list[tuple]
EvalRun / EvalScore / EvalSummary (returned by registry) typed fields incl. metadata, notes (decoded JSON)
ReplayRegistry storage=None capture(trace_id, kind, input, ...), get_session(trace_id), list_sessions(), start(source_trace_id, mode="live", ...), step(run_id), record_output(run_id, idx, output), complete/fail, set_replay_trace_id, get_run, list_runs(source_trace_id=None)
ReplaySession / ReplayInvocation / ReplayRun (returned by registry) typed fields incl. input, output, metadata (decoded JSON)
TraceStore storage=None record_span(trace_id, span_id, name, ...), close_span(span_id, end_unix_ns, status="ok"), get_trace(trace_id), subtree(span_id), thread(thread_id)
Span (returned by store) typed fields incl. attributes (decoded JSON)

Module-level: duxxdb.__version__.

Server (typed Python facade over RESP)

When you're running duxx-server as a daemon and want a typed Python surface over every Phase 7 agent-ops primitive (traces, prompts, datasets, evals, replay, cost ledger), install the server extra:

pip install 'duxxdb[server]'
from duxxdb.server import ServerClient

client = ServerClient(url="redis://:<token>@localhost:6379")

# Phase 7.2 — prompt registry
v1 = client.prompts.put("classifier", "you are a refund agent")
prompt = client.prompts.get("classifier", v1)

# Phase 7.3 — dataset registry
client.datasets.create("refunds")
ds_v = client.datasets.add("refunds", [
    {"id": "r1", "text": "I want a refund", "split": "train"},
    {"id": "r2", "text": "Where is my package?", "split": "test"},
])

# Phase 7.4 — evals with summary stats + failure clustering
run_id = client.evals.start(
    dataset_name="refunds",
    dataset_version=ds_v,
    model="gpt-4o-mini",
    scorer="llm_judge",
    prompt_name="classifier",
    prompt_version=v1,
)
client.evals.score(run_id, row_id="r1", score=0.9, output_text="REFUND")
client.evals.score(run_id, row_id="r2", score=0.1, output_text="REFUND")
summary = client.evals.complete(run_id)
print(summary.mean, summary.pass_rate_50)

# Phase 7.6 — cost ledger
client.cost.record(tenant="acme", model="gpt-4o-mini",
                   tokens_in=120, tokens_out=80, cost_usd=0.0023)
print(client.cost.total("acme"))
Namespace Wraps Methods (highlights)
client.trace TRACE.* (6 cmds) record, close, get, subtree, thread, search
client.prompts PROMPT.* (9 cmds) put, get, list, names, tag, untag, delete, search, diff
client.datasets DATASET.* (13 cmds) create, add, get, sample, size, splits, search, from_recall, …
client.evals EVAL.* (9 cmds) start, score, complete, get, scores, list, compare, cluster_failures
client.replay REPLAY.* (12 cmds) capture, start, step, record, complete, diff, list_runs, …
client.cost COST.* (10 cmds) record, query, aggregate, total, set_budget, status, alerts, cluster_expensive

All return types are plain dataclasses decoded from the server's JSON responses. The raw redis.Redis client is exposed as client.raw for anything not yet wrapped.

PromptRegistry (embedded, native bindings): versioned prompts with semantic search

New in v0.2.0: native PyO3 bindings for the prompt registry, so you can use it embedded — no server, no redis-py — straight from a notebook or batch script. The same Rust crate that powers duxx-server's PROMPT.* commands is exposed directly.

import duxxdb

# In-memory (default; matches v0.1.x in-memory feel).
r = duxxdb.PromptRegistry(dim=16)
v1 = r.put("classifier", "You are a refund agent.", metadata={"author": "alice"})
v2 = r.put("classifier", "You are a friendly refund agent.")
r.tag("classifier", v2, "prod")

p = r.get("classifier", "prod")     # resolves the tag
print(p.version, p.content, p.metadata)

# Durable (rows + tags + monotonic counter survive process exit).
r = duxxdb.PromptRegistry(dim=16, storage="redb:./prompts.redb")
r.put("greeting", "Hello! How can I help today?")
# ... process dies ...
r = duxxdb.PromptRegistry(dim=16, storage="redb:./prompts.redb")
assert r.get("greeting").content == "Hello! How can I help today?"

# Semantic search across the catalog.
for hit in r.search("hello", k=3):
    print(hit.score, hit.prompt.name, hit.prompt.content)

The HNSW vector index is rebuilt on open by re-embedding every persisted prompt — fine for the typical prompt-catalog scale (<1000 rows). Larger Phase 7 primitives (datasets, evals) keep shipping through duxxdb.server.ServerClient for now; native PyO3 bindings for them land progressively through v0.2.x.

Phase 7 (embedded, native) — v0.2.1 worked example

The five Phase 7 primitives that shipped through the RESP facade in v0.1.3 are now available natively too — no duxx-server, no redis-py. Same Rust crates the server uses.

import duxxdb

# Cost ledger
cost = duxxdb.CostLedger(dim=16, storage="redb:./cost.redb")
cost.record(tenant="acme", model="gpt-4o-mini",
            tokens_in=120, tokens_out=80, cost_usd=0.0023,
            input_text="please refund order #9910")
cost.set_budget("acme", "monthly", 100.0, warn_pct=0.8)
print(cost.total("acme"), cost.status("acme"))

# Dataset registry
ds = duxxdb.DatasetRegistry(dim=16, storage="redb:./ds.redb")
ds.create("refunds", schema={"columns": ["text", "label"]})
v = ds.add("refunds", [
    {"id": "r1", "text": "I want a refund", "split": "train"},
    {"id": "r2", "text": "Where is my package?", "split": "test"},
])

# Eval registry
evals = duxxdb.EvalRegistry(dim=16, storage="redb:./evals.redb")
rid = evals.start(dataset_name="refunds", dataset_version=v,
                  model="gpt-4o-mini", scorer="llm_judge")
evals.score(rid, row_id="r1", score=0.9, output_text="REFUND")
evals.score(rid, row_id="r2", score=0.1, output_text="REFUND")
summary = evals.complete(rid)
print(summary.mean, summary.p99, summary.pass_rate_50)

# Replay
replay = duxxdb.ReplayRegistry(storage="redb:./replay.redb")
replay.capture(trace_id="t1", kind="llm_call",
               input={"messages": [{"role": "user", "content": "hi"}]},
               output={"role": "assistant", "content": "hello"})
run_id = replay.start("t1", mode="live")

# Trace store
trace = duxxdb.TraceStore(storage="redb:./trace.redb")
trace.record_span(trace_id="t1", span_id="root", name="agent.turn",
                  attributes={"user": "alice"}, status="ok",
                  start_unix_ns=1_000_000_000)
spans = trace.get_trace("t1")
print(spans[0].name, spans[0].attributes)

Every JSON-shaped field (metadata, attributes, data, annotations, notes, input, output, schema) round-trips transparently to native Python dicts/lists.

ToolCache: semantic-near-hit demo

cache = duxxdb.ToolCache(threshold=0.95)

# Cache the result of an expensive web_search call.
cache.put(tool="web_search", args_hash=hash("what is rust?"),
          args_embedding=embed("what is rust?"),
          result=b"A systems programming language ...",
          ttl_secs=600)

# Later, a paraphrased query — different hash, similar embedding.
hit = cache.get("web_search",
                args_hash=hash("describe rust"),
                args_embedding=embed("describe rust"))

if hit and hit.kind == "semantic_near_hit":
    print(f"cache hit by paraphrase, similarity={hit.similarity:.3f}")
    answer = hit.result.decode() if isinstance(hit.result, bytes) else bytes(hit.result).decode()

What's missing today

  • Single-file redb: mode for --phase7-storage. Today only dir:<directory> is supported (one redb file per primitive). Single-file mode requires sharing one Arc<Database> across all six backends — queued for a future v0.2.x.
  • Subscriptions (MemoryStore.subscribe()) — Phase 4.5; the Rust / RESP servers already support this, the Python wrapper just needs to bridge tokio::broadcast::Receiver into a Python iterator.
  • Async API — currently sync only. async def wrappers are planned.
  • Numpy / typed-array fast path — embeddings are currently list[float]. Phase 3.5 will accept np.ndarray[float32] directly via numpy::PyArrayLike.

See ../../docs/ROADMAP.md for the broader plan.

License

Apache 2.0. See ../../LICENSE.

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

duxxdb-0.2.2.tar.gz (166.6 kB view details)

Uploaded Source

Built Distributions

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

duxxdb-0.2.2-cp38-abi3-win_amd64.whl (4.3 MB view details)

Uploaded CPython 3.8+Windows x86-64

duxxdb-0.2.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.4 MB view details)

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

duxxdb-0.2.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (4.3 MB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

duxxdb-0.2.2-cp38-abi3-macosx_11_0_arm64.whl (3.9 MB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

File details

Details for the file duxxdb-0.2.2.tar.gz.

File metadata

  • Download URL: duxxdb-0.2.2.tar.gz
  • Upload date:
  • Size: 166.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for duxxdb-0.2.2.tar.gz
Algorithm Hash digest
SHA256 f21ca9fe52575da96823bcd9cca413cc59ce888401bd0ce8a7ab7cfaeaddae0e
MD5 1dcc85bf91e07e818e6f40ca60a2a740
BLAKE2b-256 f4d595b1cc53696a4734ba1f7414b39504ebc3a2b3910311ba1b6a0f292859f8

See more details on using hashes here.

Provenance

The following attestation bundles were made for duxxdb-0.2.2.tar.gz:

Publisher: pypi.yml on bankyresearch/duxxdb

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

File details

Details for the file duxxdb-0.2.2-cp38-abi3-win_amd64.whl.

File metadata

  • Download URL: duxxdb-0.2.2-cp38-abi3-win_amd64.whl
  • Upload date:
  • Size: 4.3 MB
  • Tags: CPython 3.8+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for duxxdb-0.2.2-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 ddab4cec6eb9b6519c832c81a112aef15f81bfac78643e9db3ef57b9cf23bac7
MD5 3efdbca1a3be9269c68dd475071e7c36
BLAKE2b-256 e48a954f33588e994b1994b8905d949307b22654836256b7cfbda499706ef641

See more details on using hashes here.

Provenance

The following attestation bundles were made for duxxdb-0.2.2-cp38-abi3-win_amd64.whl:

Publisher: pypi.yml on bankyresearch/duxxdb

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

File details

Details for the file duxxdb-0.2.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for duxxdb-0.2.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 4319a944a48a55b3675a0b641639750266eeeaf73e4d0089a9b23877a67b913e
MD5 0852042b272d122183f270b63a9bb14c
BLAKE2b-256 c870d13066bae9e6cbd5be95224917771a33cd8602b668e3cd74b0bc8e29dc9a

See more details on using hashes here.

Provenance

The following attestation bundles were made for duxxdb-0.2.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on bankyresearch/duxxdb

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

File details

Details for the file duxxdb-0.2.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for duxxdb-0.2.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 4daf42878c6551b500e8a9a6e79c1fabb37154bbe21cd8a375835166c86f5874
MD5 b2fd14cf071e23745836258316df929f
BLAKE2b-256 5dbb6dd7cbc7ccbecc81932a66ce2d9d09b9144bd6902797368b87ed2e1bec46

See more details on using hashes here.

Provenance

The following attestation bundles were made for duxxdb-0.2.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: pypi.yml on bankyresearch/duxxdb

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

File details

Details for the file duxxdb-0.2.2-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for duxxdb-0.2.2-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 e9eac35ad94eb913e0bdbdacddc4fb0d0241c9bd4588d0de7a3a8df916e96688
MD5 d4b51d53fa14947214e4b722a8d36290
BLAKE2b-256 5da00ed4739fe77b04db703fd948755c8533c63e574dbf5a42f481bc2d091ed5

See more details on using hashes here.

Provenance

The following attestation bundles were made for duxxdb-0.2.2-cp38-abi3-macosx_11_0_arm64.whl:

Publisher: pypi.yml on bankyresearch/duxxdb

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

Supported by

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