← Asset Platform
Operations

Set up a worker seat

A "seat" is any machine that helps process the pool. One seat does both jobs from a single process: it transcribes & describes lesson videos and turns finished briefs into vectors. It signs in to the hub as an outbound client — no inbound ports, no shared network. Follow the steps for your OS; the one admin step (minting a key) is done once by Vinay.

OS
Commands below switch to match your OS. The GPU box (the 5090) uses the same steps with one CUDA tweak, called out in step 6.
1

Install the tools

A combined seat needs: git, Python 3.12, ffmpeg + Whisper (transcription), and the Claude CLI (the Describe pass, on your Max plan). The embedding libraries come in step 6.

# Homebrew first if needed:
# /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install git python@3.12 ffmpeg
pip3 install -U openai-whisper
# Claude CLI (if not already installed):
curl -fsSL https://claude.ai/install.sh | bash
On the 5090 (Linux) use your package manager instead of brew: apt install git python3.12 ffmpeg, then the same pip3 / Claude CLI lines.
# In an elevated PowerShell:
winget install Git.Git Python.Python.3.12 Gyan.FFmpeg
pip install -U openai-whisper
# Claude CLI (if not already installed):
irm https://claude.ai/install.ps1 | iex
Close and reopen PowerShell after installs so PATH refreshes.
2

Get the code

Clone the Asset Platform repo (or copy its pipeline/ folder). Everything runs from the repo root.

git clone <asset-platform repo URL> asset-platform
cd asset-platform
3

Mint a worker keyadmin · Vinay

Each seat needs its own worker token (so you can see who did what and revoke one seat without touching the others). Vinay mints it once on the admin machine and hands the value over privately — never in chat.

3a. Create the token (via the MCP, db_execute_sql, schemaId=sandbox). Name the label after the machine:

INSERT INTO ax_token (token, role, label)
VALUES (replace(gen_random_uuid()::text,'-','')||replace(gen_random_uuid()::text,'-',''),
        'worker', 'seat-mumbai-01')
RETURNING label;

3b. Read the value back locally (prints only to your terminal), on a machine that already has MCPDB_USER/PASS in ~/.claude/.env:

python3 - <<'PY'
import os,json,base64,urllib.request
e={}
for l in open(os.path.expanduser("~/.claude/.env")):
    if "=" in l and not l.startswith("#"): k,v=l.strip().split("=",1); e[k]=v
a="Basic "+base64.b64encode(f"{e['MCPDB_USER']}:{e['MCPDB_PASS']}".encode()).decode()
b=json.dumps({"name":"db_query","arguments":{"schemaId":"sandbox",
  "sql":"SELECT label, token FROM ax_token WHERE role='worker' ORDER BY label"}}).encode()
r=urllib.request.Request("https://mcp-db.classrootsedu.com/api/mcp/call",data=b,
  headers={"Content-Type":"application/json","Authorization":a})
for row in json.loads(json.loads(urllib.request.urlopen(r).read())["result"]["content"][0]["text"])["rows"]:
    print(row["label"],"->",row["token"])
PY
Windows: save that block as get_tokens.py and run python get_tokens.py. Copy the token next to your new label — that's the seat's AX_TOKEN.
4

Collect the shared secrets

Same on every seat (Vinay provides them privately):

5

Create the .env file

The worker reads its secrets from ~/.claude/.env (/Users/<you>/.claude/.env)(on Windows: %USERPROFILE%\.claude\.env). Create it with your real values:

mkdir -p ~/.claude
cat >> ~/.claude/.env <<'EOF'
AX_TOKEN=your-worker-token
CF_ACCESS_CLIENT_ID=your-cf-client-id
CF_ACCESS_CLIENT_SECRET=your-cf-client-secret
MCPDB_USER=the-db-user
MCPDB_PASS=the-db-pass
EOF
chmod 600 ~/.claude/.env
New-Item -ItemType Directory -Force "$env:USERPROFILE\.claude" | Out-Null
@"
AX_TOKEN=your-worker-token
CF_ACCESS_CLIENT_ID=your-cf-client-id
CF_ACCESS_CLIENT_SECRET=your-cf-client-secret
MCPDB_USER=the-db-user
MCPDB_PASS=the-db-pass
"@ | Set-Content "$env:USERPROFILE\.claude\.env"
The CF secret can contain characters a shell dislikes. The quoted here-doc (<<'EOF') and the PowerShell here-string store values literally — don't wrap them in quotes. If a value looks wrong afterward, edit the file in a plain text editor.
6

Set up embedding (Python env + bge-m3)

An isolated virtualenv holds the embedding libraries. First run downloads the bge-m3 model (~2.3 GB).

python3.12 -m venv ~/.ax-venv
~/.ax-venv/bin/pip install -U pip FlagEmbedding torch
py -3.12 -m venv "$env:USERPROFILE\.ax-venv"
& "$env:USERPROFILE\.ax-venv\Scripts\pip" install -U pip FlagEmbedding torch
On the 5090 (Linux + NVIDIA) install the CUDA build so it uses the GPU:
python3.12 -m venv ~/.ax-venv
~/.ax-venv/bin/pip install -U pip FlagEmbedding
~/.ax-venv/bin/pip install torch --index-url https://download.pytorch.org/whl/cu128
A Mac/CPU seat still works — it just embeds slower than the GPU box.
7

Log the Claude CLI into your Max plan

The Describe pass calls claude -p — no API key, your Max subscription.

claude            # then type /login, sign in with your Max account, then /exit
claude -p "Reply with one word: pong"   # should print: pong
8

Run the seat

One command does both jobs each cycle: claim a video → transcribe → describe → submit, and claim a finished brief → embed. Run it with the venv's Python (so bge-m3 is available); it calls whisper / claude as needed.

~/.ax-venv/bin/python pipeline/ax_worker.py --loop 20
& "$env:USERPROFILE\.ax-venv\Scripts\python" pipeline\ax_worker.py --loop 20
Limit a machine to one job if you want — --roles extract (video only) or --roles embed (e.g. the 5090). Re-run any time; it always picks up the next available work and stops when there's nothing left.
9

Watch it on the portal

Open assets.classrootsedu.inWork in Progress. Units move across the board and the By chapter view fills in — live, no refresh.

If something goes wrong