Skip to main content

cavs — Python SDK for CAVS Hub

Official Python client for CAVS Hub, the content-addressed, deduplicating artifact store for AI, CI/CD and build pipelines. It speaks the same canonical API the CLI uses — one API, one permission model, one data plane. The wire behaviour is defined in ../CONTRACT.md and pinned by the shared vectors in ../spec/contract/.

  • Requires Python 3.9+.
  • Only runtime dependency: httpx.

Install

pip install cavs

From this monorepo checkout:

cd python
pip install -e ".[dev]"

Quickstart

from cavs import CAVS

client = CAVS.from_env()          # reads CAVS_TOKEN + CAVS_API

artifact = client.artifacts.upload(
    path="./model",
    project="vision-models",
    name="resnet50",
    kind="model",
    version="1.4.0",
    metadata={"framework": "pytorch", "accuracy": 0.942},
)
print(artifact.reference)          # cavs://acme-ai/vision-models/model/resnet50:1.4.0
print(artifact.deduplication_ratio)

client.artifacts.download(artifact.reference, dest="./restored")

Track training runs and lineage:

run = client.runs.create(project="vision-models", name="nightly", system="mlflow")
client.runs.update("vision-models", run.id, status="completed")

Authentication

Create a service account in the CAVS dashboard and export its key. Tokens are resolved in this order: an explicit token= argument, then $CAVS_TOKEN.

export CAVS_TOKEN=cavs_sk_...
export CAVS_API=https://cavsnode.com        # default; use http://localhost:8080 for dev

Other environment variables:

Variable Purpose
CAVS_TOKEN Auth token (cavs_sk_…, cavs_pat_…, …)
CAVS_API Base URL (default https://cavsnode.com)
CAVS_ORG Default organization slug
CAVS_CA_BUNDLE Path to a custom CA bundle for TLS verification

Or construct explicitly:

client = CAVS(token="cavs_sk_...", api="https://cavsnode.com", org="acme-ai")

project and org resolution

project is an alias for a repository. It is resolved within an org by matching the value against each repository's id, slug or name (GET /organizations/{org}/repositories); if nothing matches, the value is used verbatim as a repository id. The org comes from an explicit argument, then CAVS_ORG, then the caller's default org from GET /users/me.

Security

Following ../CONTRACT.md §2, this SDK:

  • never prints the token in repr, exceptions, or logs — it is redacted to e.g. cavs_sk_…abcd;
  • never logs presigned URLs or full request headers;
  • verifies TLS and honours CAVS_CA_BUNDLE; caps redirects at 5;
  • always sets connect + read timeouts;
  • verifies sha256 == oid on every download and refuses to write a mismatched file (ChecksumError), cleaning up the temp file;
  • guards against path traversal when expanding directories / archive members;
  • honours Retry-After and cleans up temp files on failure;
  • supports cancellation via a threading.Event (or any object with is_set()).

Uploads and downloads

Large files never travel through the control plane — they stream directly to object storage via presigned URLs (CONTRACT §5).

  • Upload: hash every file (streamed sha256, 64 KiB chunks) → open a session with an Idempotency-Key → authorize objects (the Hub reports which already exists, so dedup and resume are automatic) → PUT the missing bytes → complete each object → finalize (idempotent), which returns dedup stats.
  • Download: authorize → stream to a deterministic temp file while hashing → verify sha256 == oid → atomically rename into place.

Progress and cancellation:

import threading

cancel = threading.Event()
client.artifacts.upload(
    path="./big-dataset",
    project="datasets",
    name="imagenet",
    kind="dataset",
    version="2026.07.24",
    on_progress=lambda done, total: print(f"{done}/{total}"),
    cancel=cancel,
)

cavs:// URIs

from cavs import parse, format_uri

p = parse("cavs://acme-ai/vision-models/model/resnet50:1.4.0")
p.org, p.name, p.version        # 'acme-ai', 'resnet50', '1.4.0'
format_uri(p)                    # round-trips to the canonical form

Errors

All exceptions derive from cavs.CAVSError. The HTTP → exception mapping follows CONTRACT §8:

HTTP Exception
401 AuthenticationError
403 AuthorizationError
404 NotFoundError
409 ConflictError
413 / 402 QuotaExceededError
429 RateLimitError (honours Retry-After)
5xx / network TemporaryServiceError (retried, ≤4 attempts)
client-side checksum mismatch ChecksumError
upload / download transport UploadError / DownloadError
from cavs import CAVS, NotFoundError, RateLimitError

try:
    client.artifacts.get("does-not-exist")
except NotFoundError as e:
    print(e.code, e.status)
except RateLimitError as e:
    print("retry after", e.retry_after)

Development

cd python
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
ruff check . && mypy src && pytest --cov=cavs --cov-fail-under=90

Tests mock httpx with respx — no network is used. See ../CONTRIBUTING.md and the docs in ../docs/.

License

Apache 2.0 — see ../LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cavs-0.2.0.tar.gz (26.6 kB view details)

Uploaded Source

Built Distribution

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

cavs-0.2.0-py3-none-any.whl (25.6 kB view details)

Uploaded Python 3

File details

Details for the file cavs-0.2.0.tar.gz.

File metadata

  • Download URL: cavs-0.2.0.tar.gz
  • Upload date:
  • Size: 26.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for cavs-0.2.0.tar.gz
Algorithm Hash digest
SHA256 f00572805f61caf8d82710cdaa934c8c9b4b87d6fc56d4326db60d0f906f8048
MD5 1c8276c9ccf60bdac0655815508d0704
BLAKE2b-256 1b5cc218f2500b990157a0748875c0568b71a9a503acabbcffb1639ffe367c08

See more details on using hashes here.

File details

Details for the file cavs-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: cavs-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 25.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for cavs-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6d770394cc2163379a3cdeafc9b99a6a887cd2796818fd77093be6e986bab84e
MD5 5f5d777b63b7482e2d4f1f4c17d151fc
BLAKE2b-256 0e2633aac92a19fa615f3a4c72f3c9c8f16cbc324ffd5524ecc23135a0d83ec8

See more details on using hashes here.

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