Wire Protocol
Clients and servers speak one protocol over HTTPS, at https://HOST/REPO/oxy/v1/. Messages are deterministic CBOR. The transport only carries bytes: integrity comes from the objects themselves, which are hashed and signed, whatever channel they cross.
Endpoints
| Endpoint | Purpose |
|---|---|
GET capabilities | protocol versions, features, the repository id |
GET refs | every bookmark and tag with its state, heads and attestation, plus the current trust policy |
POST negotiate | which changes the client lacks |
POST fetch | those changes, the seals covering them, and their content |
POST objects | particular objects, such as blobs a partial clone skipped |
GET checkpoint | the nearest checkpoint, for shallow clones |
POST push | changes, objects, seals and the signed bookmark moves |
A fetch
sequenceDiagram
participant C as Client
participant S as Server
C->>S: GET capabilities
S-->>C: versions, features, repository id
C->>S: GET refs
S-->>C: main = state S2 (heads, attestation), policy
C->>C: check the attestation against the policy
C->>S: POST negotiate (have: my heads, want: S2's heads)
S-->>C: hashes of the changes I lack, in dependency order
C->>S: POST fetch (those hashes)
S-->>C: bundle: changes, seals, blobs, chunks
C->>C: hash every object, check every seal or signature
C->>C: move origin/main to S2
Negotiation is simple because history is a set: the server walks back from the wanted heads and stops at anything the client has. Changes always arrive after the changes they depend on.
A push
sequenceDiagram
participant C as Client
participant S as Server
C->>S: GET refs
S-->>C: main = S1
C->>C: seal unsigned changes, sign attestation main: S1 to S2
C->>S: POST push (bundle, update main S1 to S2, attestation)
S->>S: signatures and seals, policy, old state is still S1,<br/>every dependency present
alt all pass
S->>S: move main atomically
S-->>C: ok
else any fails
S-->>C: refused, with the reason
end
A push either applies entirely or not at all.
Unbound repositories
A hub can create an empty repository with no id yet. The first push gives it the pusher's id, so an existing repository keeps its identity when it moves to a hub.
Implementers: the full message encodings are in docs/protocol.md and section 16 of the spec.