Bring Your Own S3
Bring Your Own S3 (BYOS) points a repository at a bucket you own. The bytes stay in your cloud, under your credentials, your policies and your account. CAVS keeps only metadata, indexing, coordination and optimization.
Your data stays in your cloud, under your credentials, your policies and your account.
| Reason | What BYOS gives you |
|---|---|
| Data residency | Choose the region and provider yourself |
| Compliance | The bytes never leave your compliance boundary |
| Existing commitments | Use the storage you already pay for |
| Cost control | Your negotiated rates, your lifecycle policies |
| Exit | Your objects are already in your bucket; nothing to migrate out |
The trade-off: bucket configuration — encryption, versioning, lifecycle, public-access settings, IAM — becomes yours to get right.
Supported providers
Section titled “Supported providers”aws_s3, r2 (Cloudflare R2), wasabi, b2 (Backblaze B2’s S3 API), minio,
and generic for any other S3-compatible endpoint.
Azure Blob and native Google Cloud Storage are on the roadmap. GCS’s
S3-interoperability endpoint works today as generic.
Bucket requirements
Section titled “Bucket requirements”Your bucket must support:
- Multipart uploads
- Range GET — required for CAVS partial chunk fetches
- Strong read-after-write consistency
- List, put, get, delete
- Presigned URL generation
- Checksums
Versioning is recommended (it protects you from accidental deletion). Lifecycle rules are optional but useful.
Availability by plan
Section titled “Availability by plan”| Plan | BYOS | Connections |
|---|---|---|
| Free | not available | 0 |
| Developer | paid add-on, $29/mo | 1 |
| Team | included | 3 (+$25 each beyond) |
| Business | included | unlimited, plus per-repository storage |
“Per-repository storage” means each repository can target a different connection. On Developer and Team, connections are organization-wide.
Enable the Developer add-on:
curl -sS -X POST "https://cavsnode.com/api/v1/organizations/acme-ai/billing/byos-addon" \ -H "Authorization: Bearer $CAVS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"enabled": true}'Authentication
Section titled “Authentication”Three options, in order of preference.
CAVS assumes an IAM role you create and exchanges it for temporary STS credentials. No long-lived secret is ever stored.
You provide: the role ARN, an external ID, and the bucket/prefix.
{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "AWS": "<the CAVS principal shown in the dashboard>" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "<the external id shown in the dashboard>" } } }]}{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": "arn:aws:s3:::my-cavs-bucket", "Condition": { "StringLike": { "s3:prefix": ["cavs/*"] } } }, { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject", "s3:AbortMultipartUpload", "s3:ListMultipartUploadParts" ], "Resource": "arn:aws:s3:::my-cavs-bucket/cavs/*" } ]}Suitable for R2, MinIO, Wasabi, B2 and generic endpoints, which have no AssumeRole equivalent.
You provide an access key id and a secret access key. The secret is encrypted at rest with AES-256-GCM using a master key held outside the database, is never returned by any API response, and is never logged.
Grant the key the same six operations as the AssumeRole policy above, scoped as tightly as your provider allows, and rotate it on a schedule.
# R2 dashboard → Manage R2 API Tokens → Create token# Permission: Object Read & Write# Bucket: my-cavs-bucket# Then use:# endpoint = https://<account-id>.r2.cloudflarestorage.com# region = autoKeyless federation for GCP, AWS and Azure. On the roadmap, not available today.
Creating a connection
Section titled “Creating a connection”-
Go to Organization settings → Storage → Connections → New connection.
-
Choose the provider and fill in endpoint, region, bucket and an optional prefix. A prefix is strongly recommended — it keeps CAVS objects in their own sub-tree so a lifecycle rule or a cleanup script can’t reach anything else.
-
Choose the auth method and supply the credentials or the role details.
-
Save. CAVS immediately runs the connectivity suite and records the result as the connection’s health.
curl -sS -X POST "https://cavsnode.com/api/v1/organizations/acme-ai/storage/connections" \ -H "Authorization: Bearer $CAVS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "acme-prod-eu", "provider": "aws_s3", "region": "eu-central-1", "bucket": "acme-cavs-prod", "prefix": "cavs/", "auth_method": "access_keys", "access_key_id": "AKIA…", "secret_access_key": "…" }'Requires storage.manage — ADMIN or OWNER.
The connectivity suite
Section titled “The connectivity suite”Saving or testing a connection runs seven checks and measures round-trip latency:
- List the allowed prefix
- Write a temporary object
- Read it back (read-after-write)
- Range GET — required for CAVS partial fetch
- Multipart upload
- Presigned URL generation
- Delete the temporary object
Probe objects are always cleaned up. Re-run it any time:
curl -sS -X POST \ "https://cavsnode.com/api/v1/organizations/acme-ai/storage/connections/$CONN/test" \ -H "Authorization: Bearer $CAVS_TOKEN"Using a connection
Section titled “Using a connection”Choose it when creating a repository:
curl -sS -X POST "https://cavsnode.com/api/v1/organizations/acme-ai/repositories" \ -H "Authorization: Bearer $CAVS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "EU Models", "storage_mode": "byos", "storage_connection_id": "<connection uuid>" }'The mode is validated at creation: your plan must allow BYOS and the connection must be healthy. Object keys are the same as managed storage, additionally prefixed by the connection’s prefix:
<prefix><namespace>/objects/<xx>/<yy>/<oid><prefix><namespace>/cas/<relative path>Health monitoring
Section titled “Health monitoring”The worker re-probes every connection roughly every 10 minutes.
| Status | Meaning |
|---|---|
HEALTHY |
All checks pass |
DEGRADED |
Working, but slow or partially failing |
AUTH_FAILED |
Credentials rejected — rotated, expired or revoked |
PERMISSION_ERROR |
Authenticated, but the policy denies an operation |
UNREACHABLE |
Endpoint or DNS failure |
THROTTLED |
Provider rate-limiting |
MISCONFIGURED |
Bucket, region or endpoint mismatch |
UNKNOWN |
Not yet probed |
Crossing the healthy/unhealthy boundary emits storage.connection.failed or
storage.connection.restored, and notifies the organization by email and in-app.
curl -sS "https://cavsnode.com/api/v1/organizations/acme-ai/storage/connections" \ -H "Authorization: Bearer $CAVS_TOKEN"Billing
Section titled “Billing”BYOS changes what gets metered:
| Managed | BYOS | |
|---|---|---|
| Physical storage | billed as overage above the plan | not billed — you pay your provider |
| Egress | billed as overage above the plan | not billed — you pay your provider |
| Reported in the dashboard | yes | yes |
Cost accounting splits managed_* from byos_* bytes, so an organization mixing
both gets a single invoice with each modality separated. BYOS is monetized
through the plan fee, the Developer add-on and per-connection charges — not
through your bytes.
Ownership and disconnection
Section titled “Ownership and disconnection”Objects in your bucket are yours. CAVS never claims ownership, and your cloud account pays storage and egress throughout.
A connection cannot be deleted while repositories still reference it — move or delete those repositories first. Deleting the connection removes the encrypted credentials and the connection record from CAVS. It does not touch your bucket or your objects.
curl -sS -X DELETE \ "https://cavsnode.com/api/v1/organizations/acme-ai/storage/connections/$CONN" \ -H "Authorization: Bearer $CAVS_TOKEN"After disconnecting, your objects remain under the prefix, content-addressed by
oid. They are readable with any S3 client; the CAVS chunk tree under cas/ needs
the open-source engine to reassemble, which
is exactly why that engine is open source.
Your responsibilities
Section titled “Your responsibilities”- Encryption at rest — enable SSE (or SSE-KMS) on the bucket.
- Versioning — recommended; it’s your protection against accidental deletion.
- Public access — keep the bucket private. CAVS uses presigned URLs; it never needs public reads.
- Lifecycle rules — be careful. A rule that transitions CAVS objects to a cold class breaks range reads and therefore breaks pulls.
- Credential rotation — rotate keys and update the connection. Test after.
- Capacity and cost — CAVS reports usage but enforces no ceiling.
- Managed storage — the comparison.
- Lifecycle & maintenance — GC and repack, in both modes.
- Plans & quotas — the add-on and connection pricing.

