# 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:

```sh
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-trial
```

The 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.

```sh
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 `/Ep01` and `/Ep02`, already transcribed and tagged by the real `side.transcribe` and `side.tags` actions. 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](/docs/mcp) at `http://localhost:8080/mcp` all work right away.
- To use real models, start it with `SIDESPACE_TRANSCRIBE_URL` and `_KEY`, `SIDESPACE_ANTHROPIC_API_KEY`, or `SIDESPACE_EMBED_URL` and `_KEY`; each one you give replaces its stand-in. `-e SIDESPACE_DEMO=0` starts 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 the `sidespace-trial` volume 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.

```sh
export SIDESPACE_SERVER=https://side.example.com   # the CLI's server
sidespace login you@studio.example
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](/docs/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.

```sh tab=TypeScript
npm install ./sdks/typescript      # import { SideSpace } from "@sidespace/sdk"
```

```sh tab=Python
pip install ./sdks/python          # from sidespace import SideSpace
```

```sh tab=curl
# 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.

```sh tab=curl
curl -H "Authorization: Bearer $SIDESPACE_TOKEN" "$SIDESPACE_URL/v1/search?q=harbor+night"
```

```ts tab=TypeScript
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);
}
```

```python tab=Python
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.

```ts tab=TypeScript
await side.upload("Film A", "/Ep01/notes.md", "# Notes\n\nPick-ups on Tuesday.\n");
```

```python tab=Python
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 memory
```

```sh tab=curl
sidespace 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-`.

```ts tab=TypeScript
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);
```

```python tab=Python
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")
```

```sh tab=curl
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](/docs/changes) with webhooks instead of polling.
- [Run AI actions](/docs/actions): transcribe or tag a video and read the result.
- [Use it in Claude](/docs/claude), or [connect your own agent](/docs/mcp) over MCP.
- [Look back and rewind](/docs/history) a folder, or [change part of a file](/docs/files#change-part-of-a-file).
