Build
Sidecars
JSON metadata on every version, by namespace. The built-in schemas, writing your own, and keeping a namespace to one tool.
A sidecar is one JSON document attached to one version of a file, under a namespace. A video's version can carry its media facts, a transcript, AI tags, the prompt that generated it, people's ratings and your QC results, each in its own namespace and each written by whoever owns that job.
Sidecars are what search reads, what the apps show under Info, what compare diffs, and what AI agents read through MCP instead of downloading the file.
Read and write
| To | Call |
|---|---|
| Every sidecar of a version | GET /v1/spaces/{sid}/versions/{vid}/sidecars |
| One namespace | GET /v1/spaces/{sid}/versions/{vid}/sidecars/{ns} |
| Write (replaces that namespace's document) | PUT /v1/spaces/{sid}/versions/{vid}/sidecars/{ns} with {"doc": {…}} |
| Remove | DELETE /v1/spaces/{sid}/versions/{vid}/sidecars/{ns} |
curl -X PUT "https://side.example.com/v1/spaces/$SPACE/versions/$VERSION/sidecars/x-acme.qc" \
-H "Authorization: Bearer $SIDESPACE_TOKEN" -H "Content-Type: application/json" \
-d '{"doc": {"passed": false, "issues": [{"at_s": 12.4, "kind": "dropped_frame"}]}, "producer": {"name": "acme-qc", "version": "1.4"}}'await side.putSidecar("Film A", "/Ep01/cut.mp4", "x-acme.qc", { passed: false, issues: [{ at_s: 12.4, kind: "dropped_frame" }] });
const tags = await side.getSidecar("Film A", "/Ep01/cut.mp4", "ai.tags");side.put_sidecar("Film A", "/Ep01/cut.mp4", "x-acme.qc", {"passed": False, "issues": [{"at_s": 12.4, "kind": "dropped_frame"}]})
tags = side.get_sidecar("Film A", "/Ep01/cut.mp4", "ai.tags")sidespace sidecar put "Film A" Ep01/cut.mp4 x-acme.qc '{"passed": false}'
sidespace sidecar get "Film A" Ep01/cut.mp4 ai.tagsWriting needs editor rights and the sidecars:write scope, or sidecars:write:<ns> for one namespace (sidecars:write:x-acme.* for a family). producer records which tool wrote it; the apps show it.
Built-in namespaces
Built-in namespaces are checked against a JSON Schema on write (in proto/sidecar/ in the repository), so every tool can rely on their shape.
| Namespace | Written by | Holds |
|---|---|---|
core | The server | content_hash, size, mime, author_id, device_id, client_mtime, created_at |
media | The server (ffprobe) | duration_s, container, bitrate, width, height (as displayed), fps, video_codec, audio_codec, audio_channels, creation_time |
transcript | side.transcribe, or your tool | text, language, duration, segments (start, end, text, speaker), model, provider |
ai.tags | side.tags, or your tool | description, tags, shot_type, setting, mood, people, text_on_screen, frames, model |
ai.generation | The tool that generated the asset | tool (required), model, provider, prompt, negative_prompt, seed, parameters, inputs, job_id, cost, regenerate_url |
user | People in the apps | tags, rating, label, note, status (draft, review, approved…) |
derived | Actions that make files | from (node_id, version_id, path), action, params, run_id |
core and media are written only by the server. When a new version is saved, its user and ai.generation sidecars are carried over from the previous version (with producer.inherited_from), because a re-export keeps the same prompt and the same rating; the others describe the bytes and are made again.
Recording how an AI asset was made
If your tool generates images or video, write ai.generation when you upload. Search finds files by their prompt, and the apps show the model and a link back to regenerate.
{
"tool": "cliptap",
"model": "video-model-x",
"prompt": "A fishing harbor at night, slow dolly in, rain",
"seed": 1234,
"inputs": [{ "role": "reference", "node_id": "nod_…", "version_id": "ver_…" }],
"regenerate_url": "https://cliptap.example/jobs/9f2c"
}Your own namespaces
Custom namespaces start with x-, usually x-<company>.<tool> (x-acme.qc). Any JSON object up to the server's size limit is accepted; nothing validates it but you.
One writer per namespace
A space manager can hand a namespace to one member, usually an agent. From then on only that member can write it in that space and everyone else can only read it, so two AI tools can't overwrite each other's results.
sidespace namespace claim "Film A" x-qc "Clip Tagger"
sidespace namespace list "Film A"
sidespace namespace release "Film A" x-qcai.generation and x-… namespaces can be claimed. core and media belong to the server, and user is everyone's.