Voses and versions
Create, read and iterate programs over HTTP, with lineage and typed changelogs.
The content loop over raw HTTP: fetch a program, push a private vos with
lineage, iterate against a tracked base, read the typed changelog. This is
the contract vos fetch, vos push and vos pull ride; use it directly
when a CLI is not in the room.
Read
GET /api/vos/{id} metadata: title, params, currentVersionId, contentUrls
GET /api/vos/{id}/config { "config": VosConfigJson }
GET /api/vos/{id}/output the compiled programPublic voses need no auth. The metadata answers { "vos": { … } }, and
contentUrls sits inside it. Never construct byte URLs yourself; follow
contentUrls, never the raw thumbnailUrl or previewUrl storage paths.
Create
POST /api/vos
Authorization: Bearer vos_sk_...
{
"title": "Aurora Ribbons, dusk",
"slug": "aurora-ribbons-dusk",
"visibility": "private",
"config": { ... },
"remixOfId": "{source vos id}",
"folderId": "{folder id}"
}
→ 201 { "vos": { "id", ... } }The push compiles server-side, so a push is also a validation: a config that
does not compile answers 400 with the compile error. remixOfId records
lineage and renders as remix credit; folderId files the work onto the
user's shelf (see Folders and recipes).
The preview render queues automatically.
Lineage is stored as remixedFromId and read back as remixedFrom. It is a
chain, not a star: a copy names the vos it was copied from, one hop, so
a → b → c stays legible as three separate acts.
Duplicating your own vos
POST /api/vos/{id}/duplicate
→ 201 { "vos": { "id", "title": "Copy of …", … }, "version": { … } }A private sibling on the same shelf, head only, in the source's folder. Owner
only: someone else's work is remixed instead, which is a POST /api/vos with
remixOfId. It copies the config, the compiled artifact and (for a take) its
doc.json, so a duplicated take keeps every edit. Metered like any other
create.
Without any credential there is the claimable push: a program, and the files it draws with.
POST /api/claim/uploads (no auth)
→ 201 { "uploadToken": "vos_cu_…", "expiresAt", "limits" }
POST /api/claim/uploads/files Bearer the uploadToken
{ "filename", "size", "contentType"?, "durationSeconds"? }
PUT /api/claim/uploads/files/{uploadId}/parts/{n}
POST /api/claim/uploads/files/{uploadId}/complete { "parts": [ … ] }
→ 201 { "asset": { "id", "ref": "asset:…", "fileUrl", "kind", … } }
POST /api/claim { "title": "...", "config": { ... },
"uploadToken"?, "prompt"?, "share"? }
→ 201 { "claimUrl", "expiresAt", "vos": { "id" }, "files"? }The files go first, through the same part protocol as the account's upload
door, each read and typed by its bytes. Name each one in the config by the
ref it answered; the claim spends the session. At most 12 files and 50 MB,
sound up to 5 minutes, video up to 60 seconds. prompt is shown on the watch
page, so send only what the person wrote and said to show; share: true
makes the claim page lead with Claim and share. vos push --claimable
does all of this.
Hand claimUrl to the human and nowhere else. It lasts 72 hours; unclaimed
work is deleted with its files. Until the claim, those files are read only
through the claim link.
Iterate
GET /api/vos/{id} note currentVersionId
GET /api/vos/{id}/changes?since={yourBase} the typed changelog
POST /api/vos/{id}/versions
{ "config": { ... },
"baseVersionId": "{currentVersionId}",
"label": "tighter ring pulse",
"note": "0.4s felt slow; 0.3s reads snappier" }
GET /api/vos/{id}/versions the attributed history
POST /api/vos/{id}/versions { "restoreOf": "{versionId}" }Always send baseVersionId, and always stamp label and note; the
version history reads as a conversation. The changes payload carries each
intervening version's origin, label, note, typed ops and a prose summary,
plus the computed protected node set.
The two rejections you must handle, 409 stale_base (the body carries the
changelog you should have pulled) and 409 protected_conflict (humans win by
default), are specified in
Versions and conflicts.
Update metadata
PATCH /api/vos/{id} { "title" | "tags" | "visibility": "private" | "unlisted"
| "config" (send baseVersionId too) }A config PATCH recompiles and takes the same base and protection guards as
a version push. It creates a version, so it also takes the same label,
note and client attribution the versions POST takes; stamp them there
too. Keys cannot set "public".
Delete
DELETE /api/vos/{id} the vos and every version of it, for goodThe owner's key may delete; a remix or folder grant may not. There is no undo, so ask the human before you delete their work.
Hand back
The human reviews at vos.so/vos/{id} and edits at
vos.so/studio?vos={id}; tell them both URLs. Their saves join the same
version chain your pushes do.
Related
- Overview and auth for credentials, clamps and errors.
/llms-remix.txtfor this contract in its canonical terse form, including the remix knob and font recipes.