# KyroDB Python SDK (`kyrodb`)

Official Python SDK for KyroDB gRPC APIs.

This SDK provides:
- Sync + async clients with matching behavior.
- Typed public response models (no protobuf objects in public returns).
- Strict input validation for IDs, vectors, filters, and call options.
- Production-oriented reliability defaults (timeouts, retries, circuit breaker support).
- TLS + API-key authentication, including key rotation providers.

## Install

```bash
pip install kyrodb
```

Optional extras:

```bash
pip install "kyrodb[dev]"    # lint/type/test tooling
pip install "kyrodb[proto]"  # protobuf regeneration tooling
pip install "kyrodb[docs]"   # MkDocs toolchain
pip install "kyrodb[numpy]"  # faster vector validation path
```

## Quick Start (Sync)

```python
from kyrodb import KyroDBClient

with KyroDBClient(target="127.0.0.1:50051", api_key="kyro_live_key") as client:
    client.wait_for_ready(timeout_s=5.0)

    client.insert(
        doc_id=1,
        embedding=[0.0] * 768,
        metadata={"tenant": "acme", "source": "sdk-readme"},
        namespace="default",
    )

    result = client.search(
        query_embedding=[0.0] * 768,
        k=10,
        namespace="default",
    )
    print(result.total_found)
```

## Quick Start (Async)

```python
import asyncio
from kyrodb import AsyncKyroDBClient


async def main() -> None:
    async with AsyncKyroDBClient(target="127.0.0.1:50051", api_key="kyro_live_key") as client:
        await client.wait_for_ready(timeout_s=5.0)
        await client.insert(
            doc_id=1,
            embedding=[0.0] * 768,
            metadata={"tenant": "acme"},
            namespace="default",
        )
        result = await client.search(
            query_embedding=[0.0] * 768,
            k=10,
            namespace="default",
        )
        print(result.total_found)


asyncio.run(main())
```

## Core Behavior

### Public API contract
- Public SDK surface is what is exported from `src/kyrodb/__init__.py`.
- `kyrodb._generated.*` is internal implementation detail and not part of compatibility guarantees.

### Error model
All RPC failures map to typed exceptions under `KyroDBError`, including:
- `AuthenticationError`
- `PermissionDeniedError`
- `InvalidArgumentError`
- `NotFoundError`
- `QuotaExceededError`
- `DeadlineExceededError`
- `ServiceUnavailableError`
- `CircuitOpenError`

### Timeouts, retries, and circuit breaker
- Default call timeout is `30.0s`.
- `timeout_s=None` explicitly requests unbounded timeout.
- Read-like operations are retry-enabled by default; writes are not.
- Retries use bounded exponential backoff with jitter and elapsed-time budget.
- Optional circuit breaker can fail fast under sustained transient failures.

### Transport defaults
By default:
- gRPC keepalive is enabled.
- Send/receive message limits are set to 64 MiB.
- One client/channel should be reused per process/worker.

## Filters

Filter builders:
- `exact(key, value)`
- `in_values(key, values)`
- `range_match(key, gte=..., lte=..., gt=..., lt=...)`
- `all_of([...])`
- `any_of([...])`
- `negate(filter_value)`

Example:

```python
from kyrodb import KyroDBClient, all_of, exact, in_values

with KyroDBClient(target="127.0.0.1:50051", api_key="kyro_live_key") as client:
    filt = all_of([exact("tenant", "acme"), in_values("tier", ["pro", "enterprise"])])
    result = client.search(query_embedding=[0.0] * 768, k=10, filter=filt, namespace="default")
    print(result.total_found)
```

## Security and TLS

```python
from kyrodb import KyroDBClient, TLSConfig

with open("ca.pem", "rb") as f:
    ca_pem = f.read()
with open("client.crt", "rb") as f:
    client_crt = f.read()
with open("client.key", "rb") as f:
    client_key = f.read()

tls = TLSConfig(
    root_certificates=ca_pem,
    certificate_chain=client_crt,
    private_key=client_key,
)

client = KyroDBClient(target="db.internal:50051", api_key="kyro_live_key", tls=tls)
```

Security notes:
- Non-loopback targets require TLS.
- API key is sent as gRPC metadata (`x-api-key`).
- mTLS requires both certificate chain and private key.
- API key rotation:
  - sync: `set_api_key(...)`, `set_api_key_provider(...)`
  - async: `set_api_key(...)`, `set_api_key_provider(...)`, `set_api_key_provider_async(...)`

## API Surface

Both `KyroDBClient` and `AsyncKyroDBClient` provide:
- `insert`, `bulk_insert`, `bulk_load_hnsw`, `delete`, `update_metadata`, `batch_delete_ids`
- `query`, `search`, `bulk_search`, `bulk_query`
- `health`, `metrics`
- `flush_hot_tier`, `create_snapshot`, `get_config`
- `wait_for_ready`, `close`

## Development

```bash
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev,proto]"
python scripts/gen_proto.py --proto proto/kyrodb.proto --out src/kyrodb/_generated
```

Run local CI parity:

```bash
./scripts/run_ci_local.sh
```

## Documentation

- `docs/README.md` — docs index
- `docs/api-reference.md` — method-level reference
- `docs/operations.md` — reliability and runtime behavior
- `docs/troubleshooting.md` — operational failure modes
- `docs/performance-benchmarks.md` — validation overhead benchmarks

Hosted docs are generated from `mkdocs.yml` via `.github/workflows/docs.yml`.
