Usage & metering
What is metered
Section titled “What is metered”| Metric | Basis | Billed |
|---|---|---|
| Storage | physical bytes — post-dedup, post-compression | managed storage only |
| Egress | bytes served on download authorization, per calendar month | managed storage only |
| Objects, operations | counted for reporting | no |
| BYOS storage and egress | reported, split from managed | no — your provider bills you |
Two things follow from “physical, not logical”:
- Deduplication is a direct discount. Better dedup means a smaller bill, not just a nicer number in the dashboard.
- Logical size is not your bill. A repository showing 500 GB logical and 60 GB physical costs 60 GB.
Where the numbers come from
Section titled “Where the numbers come from”Two independent mechanisms, which is deliberate — one is precise, the other is the safety net.
Reconciliation (what the dashboard reads)
Section titled “Reconciliation (what the dashboard reads)”Finalizing a push publishes repository.usage.changed. The worker then:
- Sums the real stored bytes under the repository’s storage namespace, straight from the object store.
- Writes the daily usage snapshot that
GET …/usageand the dashboard read. - Evaluates the plan’s thresholds and emits quota warnings.
Latency is seconds. If the object store is briefly unreachable it falls back to a conservative estimate and retries — so a figure can be approximate for a short window, never silently wrong for long.
Object count and generation update immediately at finalize; byte totals follow.
The usage ledger
Section titled “The usage ledger”Every metered operation also appends an immutable ledger entry — the authoritative per-event record that billing, quotas and margin analysis read:
| Field | Meaning |
|---|---|
timestamp |
When |
organization_id, project_id |
Who and where (project_id is the repository) |
user_id |
The acting user, when there is one |
operation |
upload, download, finalize, delete |
logical_bytes, physical_bytes, deduplicated_bytes |
Sizes |
uploaded_bytes, downloaded_bytes |
Transfer direction |
object_count, operations |
Counts |
storage_class |
managed or byos |
plan, region |
Context at the time |
Ledger appends are best-effort from the request path — a failure is logged and never blocks your push. Under normal operation the ledger is complete, with the daily rollup as a cross-check.
Reading your usage
Section titled “Reading your usage”export API=https://cavsnode.com/api/v1export H="Authorization: Bearer $CAVS_TOKEN"
curl -sS "$API/organizations/acme-ai/usage" -H "$H"curl -sS "$API/organizations/acme-ai/usage/series?days=90" -H "$H"curl -sS "$API/organizations/acme-ai/dashboard" -H "$H"curl -sS "$API/repositories/$REPO/usage" -H "$H"curl -sS "$API/repositories/$REPO/storage/series?days=90" -H "$H"cav storagecav storage --json | jq '.saved_pct'Permission: usage.read — every role except… none, actually. All five roles have it,
including VIEWER and BILLING. Token scopes usage:read or org:read also reach it.
usage splits managed from BYOS bytes, since only managed is metered.
Forecasting
Section titled “Forecasting”The organization dashboard projects storage and egress to the end of the billing period from the current trend, alongside the plan’s included amounts and the overage that would result.
curl -sS "$API/organizations/acme-ai/dashboard" -H "$H" | jq '.forecast'It’s a linear projection, not a promise. Treat a forecast crossing your limit as a prompt to look at the folder breakdown, not as a bill.
Overage
Section titled “Overage”| Plan | Storage / GB-month | Egress / GB |
|---|---|---|
| Developer | $0.10 | $0.05 |
| Team | $0.10 | $0.05 |
| Business | $0.09 | $0.04 |
| Free | none — hard limits | none |
Computed at micro-cent precision (1 cent = 1,000,000 micro-cents), so small amounts are billed exactly rather than rounded up.
Nothing is cut off on a paid plan — you’re billed for what you use. On Free, the limits
are hard and an over-limit upload is refused with 402.
Quota events
Section titled “Quota events”| Event | Effect |
|---|---|
storage.quota.warning |
Notification + email + webhook. Nothing blocked. |
storage.quota.exceeded |
Notification + email + webhook. Organization marked PAST_DUE. |
Storage quota is checked before upload authorization, using logical sizes as an upper bound, so an overflowing batch is refused up front rather than half-written.
Reducing your bill
Section titled “Reducing your bill”In rough order of effect:
- Use the CAVS transfer agent. Without it there’s no chunking, and a re-pushed file costs full price every time.
- Stop shipping solid archives.
.tar.gzand.tar.zstre-encode the whole stream on any change. A plain.targets the same compression from CAVS and near-total reuse on subsequent pushes. This is usually the single biggest win. - Delete stale branches.
GET …/branchesflags branches with no commits in 30 days and branches over 2× the default branch’s footprint — a long-lived experiment branch pinning a dozen checkpoints is a common surprise. - Find the actual culprit.
GET …/storage/folders?depth=3, thenGET …/objects?sort=size. Guessing wastes time. - Cut needless egress. Fetch selectively (
git lfs pull --include=…); don’t re-download in CI what a cache already holds; don’t pre-authorize downloads speculatively — metering happens at authorization, not at transfer. - Read the recommendations.
GET …/recommendations— CAVS may have already spotted it. - Consider BYOS. If you already have committed storage capacity or negotiated rates, moving bytes to your own bucket removes them from CAVS metering entirely.
Common surprises
Section titled “Common surprises”| Symptom | Explanation |
|---|---|
| Usage looks stale right after a push | Reconciliation lags by seconds. Object count and generation update immediately. |
| Physical ≈ logical | Nothing deduped. Almost always: the agent isn’t wired, or the format is a solid archive. |
| Egress higher than expected | Download authorizations are metered, not completed transfers. |
| Storage didn’t drop after deleting a branch | GC does not yet reclaim unreferenced chunks — see Lifecycle. |
| BYOS repository shows bytes but no charge | Correct. BYOS is reported, not billed. |
Summing per-object physical_size ≠ repository physical |
Expected — shared chunks would be double-counted. |
- Plans & quotas — the limits themselves.
- Managing your subscription — changing plan.
- Storage insights — the diagnostic tools.

