Python SDK

Full guide for integrating ZizkaDB in Python agents — FastAPI services, LangChain, CrewAI, notebooks, or scripts.

1
Prerequisites

Python 3.10+. Works in venv, conda, or system Python.

bashpython3 --version # 3.10 or higher
2
Choose your environment

Managed cloud: Sign up → Settings → Create API key (zizkadb_live_…).

Self-host: use host="http://localhost:8000" (dev key auto-sent). See Self-host docs → click Open my dashboard → on the login page.

3
Install
bashpip install "zizkadb-sdk>=0.5.0"
Install zizkadb-sdk on PyPI — not the unrelated agentdb package.
4
Initialize the client
pythonfrom zizkadb import ZizkaDB

# Managed cloud (db.zizka.ai)
db = ZizkaDB("zizkadb_live_xxxx")

# Self-hosted
# db = ZizkaDB(host="http://localhost:8000")
5
Log your first event

The SDK is async-first. Wrap calls in async def main() and run with asyncio.run(main()).

pythonimport asyncio
from zizkadb import ZizkaDB

db = ZizkaDB("zizkadb_live_xxxx")

async def main():
    result = await db.log(
        agent="support-bot",
        event="tool_call",
        data={"tool": "search", "query": "pricing"},
        session_id="sess_abc123",   # group one conversation
    )
    print("Saved:", result.event_id)

asyncio.run(main())
6
Link events causally

Pass parent_id so you can call why() later.

pythonasync def main():
    msg = await db.log(
        agent="support-bot", event="user_message",
        data={"text": "why is my bill $200?"},
        session_id="sess_abc123",
    )
    tool = await db.log(
        agent="support-bot", event="tool_call",
        data={"tool": "get_billing"},
        parent_id=msg.event_id,
        session_id="sess_abc123",
    )
    resp = await db.log(
        agent="support-bot", event="assistant_response",
        data={"text": "I found a duplicate charge."},
        parent_id=tool.event_id,
        session_id="sess_abc123",
    )
    chain = await db.why(resp.event_id)
    chain.print()

asyncio.run(main())
7
Use search, replay, and memory
pythonasync def main():
    # Search: keyword out of the box, hybrid with embeddings (mode="keyword"|"semantic"|"hybrid")
    hits = await db.search("billing complaint", agent="support-bot", limit=5)

    # Safe retries and batches
    await db.log("support-bot", "tool_call", {"tool": "refund"}, idempotency_key="req-42")
    await db.log_batch([
        {"agent": "support-bot", "event": "user_message", "data": {"text": "hi"}},
        {"agent": "support-bot", "event": "llm_response", "data": {"text": "hello"}, "parent_index": 0},
    ])

    # Prove the history is untouched; keep chain_head elsewhere as an anchor
    check = await db.verify_chain("support-bot")
    print(check["intact"], check["chain_head"])

    # Reconstruct logged state at a time
    from datetime import datetime, timezone
    state = await db.at("support-bot", datetime(2026, 5, 1, 15, 0, tzinfo=timezone.utc))

    # Prompt-ready memory block
    ctx = await db.context_for(
        agent="support-bot",
        task="user asking about refund policy",
        max_tokens=2000,
    )

    # Drift vs baseline (needs enough sessions with session_id)
    baseline = await db.baseline("support-bot", recent_window=50)
    print(baseline)

asyncio.run(main())

Framework example: OpenAI tool loop

pythonimport asyncio
from openai import AsyncOpenAI
from zizkadb import ZizkaDB

db = ZizkaDB("zizkadb_live_xxxx")
openai = AsyncOpenAI()

async def run_turn(user_text: str, session_id: str):
    msg = await db.log(
        agent="my-agent", event="user_message",
        data={"text": user_text}, session_id=session_id,
    )
    parent_id = msg.event_id

    response = await openai.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": user_text}],
    )
    text = response.choices[0].message.content or ""
    await db.log(
        agent="my-agent", event="assistant_response",
        data={"text": text}, parent_id=parent_id, session_id=session_id,
    )
    return text

asyncio.run(run_turn("Hello", "sess_001"))

All Python methods

db.log()Log any event. parent_id links cause → effect; idempotency_key makes retries safe; supersedes retires an outdated fact.
db.log_batch(events)Up to 500 events in one request, with per-event results.
db.why(event_id)Walk the causal chain from an event to its root.
db.search(query)Search agent history in plain English: keyword out of the box, hybrid keyword + vector with embeddings.
db.verify_chain(agent)Prove no event was edited, removed or reordered (per-agent hash chain).
db.at(agent, timestamp)Reconstruct logged state at a past timestamp.
db.query(agent)List recent events, optionally filtered by event type.
db.context_for(agent, task)Memory block formatted for system prompt injection.
db.baseline(agent)Behavioral baseline and drift score vs historical sessions.
db.memory_diff(session_id)Summary of what happened in one session.
db.forget(key, value)GDPR erasure by metadata filter; leaves a content-free tombstone in the audit chain.
db.export_events(agent)Stream every event as NDJSON; import_events() loads it into another workspace.
db.iter_events(agent)Every event, newest first, cursor-paged.
db.agents()List all agents for your tenant.

Troubleshooting

SyntaxError: await outside async function
Wrap code in async def main() and asyncio.run(main()).
401 Invalid API key
Copy the full key from Dashboard → Agents (no spaces). Use ZIZKADB_API_KEY or AGENTDB_API_KEY in your env.
403 Agent mismatch
Your key is scoped to one agent (e.g. my-bot) but code logged to a different agent name. Use the same name in db.log(), or create a tenant-wide key in Settings.
Dashboard empty but SDK works
Check you are viewing the same agent name your code logs to. Click Test agent on the agent page. Settings test event goes to dashboard-connection-test, not your app agent.
Search returns nothing
Configure embeddings in Settings. Log a few events first so there is history to search.
baseline shows warming_up
Log more sessions with session_id on each event. Drift needs volume.
Cookie and Privacy Consent
We use cookies/local storage for essential site functionality and to improve the product. You can accept or decline — you’ll still have full access either way. Privacy policy.