Metadata-Version: 2.4
Name: quatzal
Version: 0.1.0a1
Summary: Quatzal — local-first vector + graph database with trust tiers, temporal edges, and claim verification. Zero-dependency Python client (MCP Streamable-HTTP).
License: Apache-2.0
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# quatzal (Python)

Zero-dependency, fully typed (`py.typed`) Python client for [**Quatzal**](https://www.quatzal.com/) —
a local-first vector + graph database that records who vouched for every fact and when it
stopped being true. Talks to a Quatzal server over the MCP Streamable-HTTP transport using
only the standard library; no third-party packages. Sync and asyncio clients with
identical surfaces.

```bash
pip install quatzal
```

```python
from quatzal import UaceClient, Row

client = UaceClient("https://quatzal.example.com:8443", token="...",
                    ca_file="dev-root.pem", retries=2, project="prod-corpus")

# Bulk ingest — one WAL fsync per batch; chunking handled for you
client.insert_rows_chunked([Row(f"doc-{i}", scalars={"src": "web"}, vector=v)
                            for i, v in enumerate(vecs)])

# Search with the evidence contract
resp = client.search_vectors(10, query_vector=q, max_distance=0.5)
if resp.sufficient_evidence is False:
    print(resp.message)          # honest "no relevant rows" instead of junk hits
for hit in resp.results:
    print(hit.key, hit.score, hit.trust_tier, hit.parent_key)

# Graph — search hits feed expansion directly
client.add_edge("doc-1", "doc-2", "cites", 1.0)
print(client.expand_graph(resp.results, hops=2, k=10))
```

Async (agent frameworks, high-concurrency services) — same surface, `await`ed:

```python
from quatzal import AsyncUaceClient

async with AsyncUaceClient("https://quatzal.example.com:8443", token="...",
                           ca_file="dev-root.pem") as client:
    resp = await client.search_vectors(10, query_vector=q)
    neighbors = await client.expand_graph(resp.results, hops=2, k=10)
```

## Notes that matter

- **Auth**: static bearer tokens and IdP-issued JWTs are sent identically. On 401,
  `AuthError` exposes the parsed OAuth challenge: `resource_metadata` (RFC 9728
  discovery URL) and `error_description` (why a JWT was refused).
- **Multi-project servers**: pass `project="name"` to set the `uace-project` header
  (case-sensitive). Required when the credential is bound to several projects;
  ignored by single-project servers.
- **Retries**: `retries=N` applies only to *idempotent* operations (reads, ping,
  metrics, delete) and only to transport-level failures, with exponential backoff.
  Writes are never retried; tool refusals and auth failures are never retried.
- **Vectors go over the wire as `vector_b64`** (base64 little-endian `f32`)
  automatically.
- **`score` polarity flips**: squared-Euclidean distance (lower is better) for vector
  queries, BM25/RRF (higher is better) once `query_text` is involved. The payload
  carries no discriminator, so the caller must know which query shape it sent.
- `hit.stale is None` means the row never declared an expiry — that is *not* the same
  as `False`.
- Tool refusals raise `ToolError`; bad credentials `AuthError`; unknown tools
  `RpcError`; partial bulk failures `PartialInsertError` (with the durably-inserted
  count).
- **Thread/task safety**: every request opens its own connection; use one client
  across threads or tasks freely.
- Self-signed deployments: pin the root cert via `ca_file=`; the system trust store
  won't know it.

`import uace` and `import quatzal` are the same module surface — the class names keep
the `Uace` prefix, the project's original internal name; renaming the public API would
break every existing caller for no functional gain.

## Status

Pre-release (0.1.0a1), tracking Quatzal 0.1.0. Quatzal's data formats are not yet
stable; treat a store as reproducible from its source data rather than as an archive.

## Links

- Documentation: https://www.quatzal.com/docs/index.html
- Source: https://github.com/logixrcorp/quatzal (`clients/python/`)
- Tests: `python -m unittest discover -s tests`

## License

Apache-2.0. Quatzal is open core — the separately licensed commercial modules are not
part of this package, and nothing in the client depends on them.
