Get started
Quickstart
Try Side Space in one container with sample clips, or make a token on your server, then search, upload a file and attach metadata to it from the shell, TypeScript or Python.
Try it on your machine first
No server or account yet? One container runs everything, and comes with a space full of sample clips to try things on:
git clone https://github.com/blendduck/sidespace && cd sidespace
docker build -f deploy/trial/Dockerfile -t sidespace-trial .
docker run --rm -p 8080:8080 -p 8090:8090 -p 8070:8070 -v sidespace-trial:/data sidespace-trialThe first start makes a developer account, a space "Film A" and a token with full access (also the S3 secret), and prints them in the log; later starts print the same ones.
export SIDESPACE_URL=http://localhost:8080 SIDESPACE_TOKEN=ssp_… # the line from the log
curl -H "Authorization: Bearer $SIDESPACE_TOKEN" "$SIDESPACE_URL/v1/search?q=storm"
curl -H "Authorization: Bearer $SIDESPACE_TOKEN" "$SIDESPACE_URL/v1/search?q=the+ocean+at+dusk&mode=meaning"- "Film A" starts with four sample clips in
/Ep01and/Ep02, already transcribed and tagged by the realside.transcribeandside.tagsactions. The models behind them are stand-ins inside the container with canned answers, so no API key is needed. Search (with the moment a word is spoken), search by meaning, actions, pipelines and MCP athttp://localhost:8080/mcpall work right away. - To use real models, start it with
SIDESPACE_TRANSCRIBE_URLand_KEY,SIDESPACE_ANTHROPIC_API_KEY, orSIDESPACE_EMBED_URLand_KEY; each one you give replaces its stand-in.-e SIDESPACE_DEMO=0starts with an empty space and no stand-ins. - Other people sign in with any email and the code
000000. It sends no mail and keeps no backups, so it's for trying, not for real footage. Delete thesidespace-trialvolume to start over.
With the trial running, skip step 1 and use the token from the log. The rest of this page works as written with http://localhost:8080 in place of https://side.example.com.
1. Get a token
Sign in with the CLI once, then make a personal access token. It is shown only once, so copy it now.
export SIDESPACE_SERVER=https://side.example.com # the CLI's server
sidespace login [email protected]
sidespace token create "quickstart" --scope files:write --scope sidecars:write --space "Film A"
# ssp_6Jw… (shown once)
export SIDESPACE_URL=$SIDESPACE_SERVER # read by the Python SDK
export SIDESPACE_TOKEN=ssp_6Jw… # read by the CLI and the Python SDK--space limits the token to one space; leave it out to reach every space you are in. Authentication explains scopes, agents and OAuth.
2. Add an SDK (optional)
Both SDKs have no dependencies and are Apache-2.0. They are not on npm or PyPI yet: install them from a checkout of the repository, or copy the folder into your project.
npm install ./sdks/typescript # import { SideSpace } from "@sidespace/sdk"pip install ./sdks/python # from sidespace import SideSpace# Nothing to install. Every call sends: -H "Authorization: Bearer $SIDESPACE_TOKEN"3. Find something
Search covers names, tags, AI prompts, transcripts and review comments. Hits inside a transcript come with the moments where the words are spoken.
curl -H "Authorization: Bearer $SIDESPACE_TOKEN" "$SIDESPACE_URL/v1/search?q=harbor+night"import { SideSpace } from "@sidespace/sdk";
const side = new SideSpace({ baseUrl: process.env.SIDESPACE_URL!, token: process.env.SIDESPACE_TOKEN! });
for (const hit of await side.search("harbor night")) {
console.log(hit.space_name, hit.folder, hit.node.name, hit.moments?.[0]?.at_ms);
}from sidespace import SideSpace
side = SideSpace() # reads SIDESPACE_URL and SIDESPACE_TOKEN
for hit in side.search("harbor night"):
print(hit["space_name"], hit["folder"], hit["node"]["name"])4. Upload a file
Saving to a path that already exists adds a version; nothing is overwritten. Folders are created as needed.
await side.upload("Film A", "/Ep01/notes.md", "# Notes\n\nPick-ups on Tuesday.\n");side.upload("Film A", "/Ep01/notes.md", "# Notes\n\nPick-ups on Tuesday.\n")
with open("A001_C003.mov", "rb") as f:
side.upload("Film A", "/Ep01/Shots/A001_C003.mov", f) # streamed, not read into memorysidespace put "Film A" ./notes.md Ep01/notes.md
# Over plain HTTP an upload is three calls; see "Files and versions".5. Attach your own metadata
Write results to a sidecar instead of a file next to the original. Custom namespaces start with x-.
await side.putSidecar("Film A", "/Ep01/Shots/A001_C003.mov", "x-shotcheck", { focus: "soft", score: 0.42 });
const media = await side.getSidecar("Film A", "/Ep01/Shots/A001_C003.mov", "media");
console.log(media?.duration_s, media?.width, media?.height);side.put_sidecar("Film A", "/Ep01/Shots/A001_C003.mov", "x-shotcheck", {"focus": "soft", "score": 0.42})
media = side.get_sidecar("Film A", "/Ep01/Shots/A001_C003.mov", "media")curl -X PUT "$SIDESPACE_URL/v1/spaces/$SPACE/versions/$VERSION/sidecars/x-shotcheck" \
-H "Authorization: Bearer $SIDESPACE_TOKEN" -H "Content-Type: application/json" \
-d '{"doc": {"focus": "soft", "score": 0.42}}'The file's page in the app now shows your fields under Info, and search finds them.
Next
- Follow changes with webhooks instead of polling.
- Run AI actions: transcribe or tag a video and read the result.
- Use it in Claude, or connect your own agent over MCP.
- Look back and rewind a folder, or change part of a file.