Home / API / Vault objects

Vault objects

The pointer store: the ciphertext objects a vault is made of, addressed by opaque identifiers the server cannot interpret. This is what sgit push and sgit pull are doing underneath.

Endpoints

MethodPathAuthNotes
PUT/api/vault/write/{vault_id}/{file_id}access token + write keyBody is raw ciphertext
GET/api/vault/read/{vault_id}/{file_id}noneRaw bytes. Reads are public by default on the shared host
GET/api/vault/read-base64/{vault_id}/{file_id}noneBase64 in JSON — MCP-safe. Around 3.75 MB ceiling
DELETE/api/vault/delete/{vault_id}/{file_id}access token + write key
POST/api/vault/batch/{vault_id}per operationMixed reads and writes, max 100 per request
POST/api/vault/list/{vault_id}
GET/api/vault/health/{vault_id}
GET/api/vault/public-info/{vault_id}
DELETE/api/vault/destroy/{vault_id}write keyBody {vault_id, purge?}. Without purge it writes a tombstone that blocks reuse of the ID

Large blobs go through presigned URLs rather than the request body: POST /api/vault/presigned/initiate|complete|cancel/{vault_id} and GET /api/vault/presigned/read-url/{vault_id}/{file_id}.

GET /api/vault/zip/{vault_id} is registered in the route table but marked PROPOSED upstream. It is deliberately not documented until that is reconciled.

Destroy, and why the tombstone matters

destroy without purge:true leaves a tombstone that prevents the vault ID being registered again. That is a security property, not bookkeeping: vault IDs are short and a released ID is a squattable namespace. If somebody still holds a read key pointing at that ID, a new vault claiming it would be answering reads meant for the old one. purge:true skips the tombstone and frees the ID — use it only when you are sure no credential survives.

The caching contract

Anyone writing a client needs this, and getting it wrong produces a bug that looks like corruption:

ObjectResponse header
File ID containing -imm- — immutable, content-addressedCache-Control: public, max-age=31536000, immutable
Refs and indexes — mutableCache-Control: no-store

Immutable objects are content-addressed, so their bytes can never change and a year-long cache is safe — which is what lets a vault sit behind a CDN. Mutable refs must never be cached: a stale ref renders a previous commit’s tree from ciphertext that is itself perfectly valid, so nothing errors and the reader simply sees the wrong version of the vault.

Storage layout

bare/data/obj-cas-imm-{hex}     blobs, trees, commits — content-addressed, immutable
bare/keys/key-rnd-imm-{hex}     PKI public keys — immutable
bare/refs/                      branch refs — mutable
bare/indexes/                   branch index — mutable
bare/append/                    append lanes — managed, outside the commit DAG

The prefixes are load-bearing. obj-cas-imm- is SHA-256 over the ciphertext, which gives deduplication without the server knowing any plaintext, and makes the caching rule above derivable from the ID alone. Append lanes sit outside the commit DAG on purpose — a message arriving does not rewrite your history.

This site is itself served from a vault, so these are the objects behind the page you are reading. The live-vault case study shows the fetch sequence.

See also