Run GPU training jobs from Claude Code, or any MCP client.
From SSH key to finished artifacts in two steps: connect, then submit and collect. Estimates and status checks are free; money moves only at submitJob.
Step zero, do it now: send the output of cat ~/.ssh/id_ed25519.pub to access@symbioza.dev. Access is by invitation, one customer at a time — nothing below works until that key is enrolled. Then two things happen on the operator’s side:
HostName and User. Nothing else in it changes. That key is your credential — over ssh there is no second secret to paste.ssh-keygen -t ed25519 makes one; send the .pub half only.Connect
Your MCP client launches ssh as the server transport and speaks JSON-RPC over the pipe. Two config blocks, then one command to prove it: ssh symbioza should connect and sit there waiting for JSON-RPC. Ctrl-C out — that silence is success.
Your session only enqueues and returns an id — the always-on daemon owns the run. Dotted = per-session; solid = always-on.
Host symbioza
HostName <SYMBIOZA_HOST>
User symbioza
IdentityFile ~/.ssh/<YOUR_KEY>
IdentitiesOnly yes
StrictHostKeyChecking accept-new
BatchMode yes{
"mcpServers": {
"symbioza": {
"command": "ssh",
"args": ["-o", "BatchMode=yes",
"symbioza",
"/srv/symbioza/bin/symbioza-mcp"]
}
}
}IdentitiesOnly yes in the block above fixes it.accept-new trusts it on first use; verify out-of-band with ssh-keyscan if you’d rather.Submit, disconnect, collect
You submit one JSON object, a TrainingJobSpec. The contract is strict: unknown fields are rejected, so a typo can never silently fall through to a default. Put your own success check inside the command — your exit code is the verdict.
Declare your data under datasets. Two mechanisms exist: "transferMode": "https", where the rented box fetches the file itself from a URL you can sign — use it for large or public data — and "push", where the control plane streams a file you staged with us over ssh, resumable. Either way the sha256 you declare is verified before your command starts, and the file lands at destination inside the container. Nothing on your laptop is ever on the data path.
{
"image": "ghcr.io/you/train:latest",
"command": ["python", "train.py",
"--epochs", "40"],
"gpu": { "minVramGb": 24, "cuda": true },
"budgetUsd": 12,
"maxRuntimeSeconds": 43200,
"checkpoint": { "enabled": true },
"datasets": [{
"source": "https://<signed-url>/train.tar",
"sha256": "<sha256>", "sizeBytes": 41000000000,
"destination": "/data/train.tar",
"transferMode": "https"
}]
}Status is one of queued · running · completed · failed · cancelled · lost. The id is durable — reconnect tomorrow in a fresh session and ask again. If the box dies, the run restarts on another machine under the same ceiling; the checkpoints already streamed off it are kept. Automatic resume from those checkpoints is next. Artifacts tier to offsite storage the moment the record is written; getArtifact returns a presigned download link per file, each already re-hashed against its recorded sha256.
A GPU-provider API key · the Symbioza control-plane key · any SSH private key. Those stay on the control plane. If an onboarding step asks you for one, stop and report it.
reason; fix the spec or raise the budget.authKey is wrong or absent — the same message for every tool, by design.getStatus().incidents[] and the exit code say why. Infra failures were already retried or moved to another box; a workload failure is your code.Errors are plain messages with a next step, not stack traces.
Ready when you are.
Send your SSH public key to access@symbioza.dev — it gets enrolled, your host entry arrives out-of-band, and the first estimate is one call away.