Resources
For AI agents
If you're an agent reading this: everything you need to operate LiveLLM lives in one file. Save it locally as a skill and you can provision workloads, ship repos and check status on your human's behalf.
docs.live-llm.com/SKILL.md
docs.live-llm.com/llms-full.txt
SKILL.md
# LiveLLM Cloud — Agent Skill
> **If you are an AI agent reading this file**, this is your complete guide to
> driving LiveLLM Cloud on a human's behalf. Read it fully before acting.
> LiveLLM Cloud is an **AI-first cloud**: every workload — Linux & Windows VMs,
> container apps, headless browsers, and autonomous agents — lives inside a
> **workspace** and is fully driveable through one REST API.
```yaml
name: livellm-cloud
version: "1.0.0"
api: https://docs.live-llm.com
spec: https://docs.live-llm.com/openapi.yaml
docs: https://docs.live-llm.com/
```
## What LiveLLM Cloud is
A cloud where everything a human runs — VMs, container apps, headless browsers,
autonomous agents — is a **workload** inside their **workspace**, and every
workload is created, changed, and torn down through one REST API. You, the
agent, are a first-class operator of that API: you can stand up infrastructure,
ship a repo, wire a model, and watch it come up — all on the human's behalf.
## How to route a human's request
Decide what the human wants, then follow the matching flow below.
| The human says… | Intent | Go to |
|---|---|---|
| "spin up a VM / app / browser" | **Provision** | [Manage workloads](#manage-workloads) |
| "deploy my repo" / "build from Git" | **Ship code** | [Ship code from Git](#ship-code-from-git) |
| "what's running / is it up?" | **Inspect** | [Inspect a workspace](#inspect-a-workspace) |
| "connect OpenAI/Claude" | **Wire a model** | [AI providers](#ai-providers) |
| "give my bot access" | **Mint a key** | [Authentication](#authentication) |
Always confirm before anything destructive (deleting a workload, a repo, or a
workspace). Never print a full API key into shared output.
## Authentication
Every request carries a **per-workspace API key**. The human mints one on their
workspace's **API keys** page; it looks like `llc_AbC123…` and is shown once.
Send it either way:
```bash
curl https://docs.live-llm.com/v1/me/tenant \
-H "Authorization: Bearer $LIVELLM_KEY"
# or: -H "x-api-key: $LIVELLM_KEY"
```
A key is **scoped to one workspace** — it cannot read or change another. If you
get `403 api key is scoped to a different workspace`, you used the wrong key.
Errors come back as JSON with an `error` string and the matching HTTP status —
`401` invalid key, `403` wrong workspace, `404` no such resource, `409` a
conflict (e.g. id already exists), `422` failed validation. Read `error` and
adjust; don't blindly retry.
## Inspect a workspace
```bash
# Which workspace does this key belong to?
curl -H "x-api-key: $K" $API/v1/me/tenant
# Full spec (including workloads):
curl -H "x-api-key: $K" $API/v1/tenants/$NAME
# Live status (phase, endpoints, messages) and quota:
curl -H "x-api-key: $K" $API/v1/tenants/$NAME/status
curl -H "x-api-key: $K" $API/v1/tenants/$NAME/quota
# Resource tree of one workload — the live k8s objects behind it (Deployments,
# ReplicaSets, Pods, Services, PVCs, ConfigMaps, Secret NAMES, Ingress routes,
# VM instances) + recent Events. Flat list; parent/child via ownerKind/ownerName:
curl -H "x-api-key: $K" $API/v1/tenants/$NAME/workloads/web/resources
# Recent activity — who did what, when (?actor=you|agents, ?object=workload:web):
curl -H "x-api-key: $K" $API/v1/tenants/$NAME/activity
# Live agent fleet — every master + worker agent with status and in-flight task:
curl -H "x-api-key: $K" $API/v1/tenants/$NAME/agents/fleet
# Push activity to a notification channel (scope: asks = human-help requests only | agents | all):
curl -X PUT -H "x-api-key: $K" -d '{"enabled":true,"channelId":"<channel id>","scope":"asks"}' $API/v1/tenants/$NAME/activity-alerts
# Billing — allocation usage series (?days=30) and monthly invoices (current month is a provisional "open" invoice; ?id for the line-item breakdown):
curl -H "x-api-key: $K" $API/v1/tenants/$NAME/usage
curl -H "x-api-key: $K" $API/v1/tenants/$NAME/invoices
```
## Manage workloads
Each resource is a **workload**. Create uses a **per-type** endpoint —
`POST .../workloads/{type}` — because each type has its own body (a VM body
differs from a container-app body). Update/delete are by id.
```bash
# CREATE a container app — POST to /workloads/pod, body is the pod's fields:
curl -X POST -H "x-api-key: $K" -H 'content-type: application/json' \
-d '{ "id":"web", "image":"nginx:1.27", "ports":[{"name":"http","port":80}] }' \
$API/v1/tenants/$NAME/workloads/pod
# CREATE a VM — POST to /workloads/vm-ubuntu, body is the vm's fields.
# By default LiveLLM picks the host automatically — send NO placement field.
# Only when the user asks for a location, add optional placement:
# a region: "placement":{"strategy":"region","region":"eu-1"}
# a host: "placement":{"strategy":"host","host":"host-a1"}
# (regions, hosts and live capacity: GET $API/v1/fleet/hosts)
curl -X POST -H "x-api-key: $K" -H 'content-type: application/json' \
-d '{ "id":"dev", "cpus":2, "memory":"4Gi", "storageSize":"40Gi",
"credentials":{"username":"ubuntu","password":"…"} }' \
$API/v1/tenants/$NAME/workloads/vm-ubuntu
# UPDATE a workload by id (full desired Workload; the path id wins):
curl -X PUT -H "x-api-key: $K" -H 'content-type: application/json' \
-d '{ "type":"pod", "pod": { "image":"nginx:1.28", "ports":[{"name":"http","port":80}] } }' \
$API/v1/tenants/$NAME/workloads/web
# DELETE it / RESTART it:
curl -X DELETE -H "x-api-key: $K" $API/v1/tenants/$NAME/workloads/web
curl -X POST -H "x-api-key: $K" $API/v1/tenants/$NAME/workloads/web/restart
```
`{type}` is one of `vm-ubuntu`, `vm-ubuntu-desktop`, `vm-windows`, `pod`,
`browser`, `controller`, `browser-agent`, `storage` (managed postgres/redis —
body: `engine` + `credentials.password` required (set once, never shown again),
plus `version`/`instances`/`storageSize`, optional `network.{expose,allowlist}`
/`backup.{schedule,maxBackups}` (backup postgres-only)).
Storage workloads also expose a DB admin surface under
`.../workloads/{id}/db/` — `overview`, `schema`, `users` (GET/POST, DELETE
`/users/{username}`), `migrations` (GET/POST `{name,sql}`).
Set `"adminConsole": true` on a storage workload to attach a web admin
console (pgAdmin for postgres, RedisInsight for redis) at
`https://<id>-admin-<workspace>.cloud.live-llm.com` — login is `admin` +
your database password (HTTP basic-auth; enabling it later requires
re-sending `credentials.password`). The workload status reports `adminUrl`
and `adminReady`.
A `pod` HTTP port becomes a public HTTPS URL at
`<id>-<port>-<workspace>.cloud.live-llm.com`. Create returns **202**; poll
`/status` until the workload is running.
Workload `type` values: `vm-ubuntu`, `vm-ubuntu-desktop`, `vm-windows`, `pod`
(container app), `browser`, `controller`, `browser-agent`, `storage` (managed
database). A VM needs
`vm.credentials.{username,password}` on create (write-only); a container app
needs `pod.image` (prebuilt) or `pod.source.repo` (build from Git).
## Templates
Save a reusable resource blueprint (no cluster resource is created): `GET`
`/v1/tenants/$NAME/templates`, `POST` the same with `{name, description, kind, config}`, `DELETE .../templates/{id}` — `config` is a workload-type spec object and any credential/password is stripped before storage.
## Ship code from Git
```bash
# List repos in the workspace org (with build status):
curl -H "x-api-key: $K" $API/v1/tenants/$NAME/repos
```
To deploy a repo, add a `pod` workload whose `pod.source.repo` points at a repo
in the workspace org — it is auto-built (no Dockerfile required) and rolls on
every push. Delete a repo with `DELETE /v1/tenants/$NAME/repos/{repo}` (refused
while a live app still builds from it).
## Find a known app's chart/image
Asked to run an existing app (Nextcloud, Ghost, n8n, …) and unsure how it
ships? Search Helm charts (Artifact Hub, proxied by the platform):
```bash
curl -H "x-api-key: $K" "$API/v1/tenants/$NAME/charts/search?q=nextcloud&limit=5"
# -> {"charts":[{"name","repository","repoUrl","version","appVersion","description","stars","official"}]}
```
The chart is a **reference**, not something to install: read its values
(`helm show values <name> --repo <repoUrl>`) to learn the app's official
image, port and env — then deploy that image as a container app.
## AI providers
Workspace agents (the on-pod AI daemons) use the providers you connect:
```bash
curl -H "x-api-key: $K" $API/v1/tenants/$NAME/providers # list + catalog
curl -X POST -H "x-api-key: $K" -H 'content-type: application/json' \
-d '{"provider":"anthropic","apiKey":"sk-…"}' \
$API/v1/tenants/$NAME/providers # connect
```
Use a catalog id from the list response (`anthropic`, `openai`,
`zai-coding-plan`, …). `claude-subscription` is special: its `apiKey` is the
token printed by `claude setup-token` (a Claude Pro/Max plan, not an API key),
and agents configured with it run on the Claude Agent engine — the engine is
always derived from the provider, never set by you.
Provider keys are **write-only** — once set they are never read back.
## Agent tasks
Workloads with an **AI daemon** enabled (VMs, controllers, container apps) can
be handed work programmatically — the prompt runs in a fresh session on that
workload's agent and the platform records the trajectory for you:
```bash
# DISPATCH — returns 202 with a task id immediately (fire-and-forget):
curl -X POST -H "x-api-key: $K" -H 'content-type: application/json' \
-d '{"prompt":"install nginx and serve the sample page"}' \
$API/v1/tenants/$NAME/workloads/dev/task
# -> {"id":"task_9f2c01ab34de","workloadId":"dev","status":"running","createdAt":"…"}
# POLL until status leaves "running" (→ done | failed):
curl -H "x-api-key: $K" $API/v1/tenants/$NAME/tasks/task_9f2c01ab34de
# LIST a workload's recent tasks (newest first, max 20):
curl -H "x-api-key: $K" $API/v1/tenants/$NAME/workloads/dev/tasks
```
A finished task carries `result` (the agent's final answer) and `steps` — one
`{title, detail, status}` entry per tool call the agent made. **Read `steps`
when a task fails**: the failing step's title/detail usually shows exactly
which command or fetch broke. Add `"channelId":"<alert channel id>"` to the
dispatch body to get a completion notification on one of the workspace's alert
channels. Dispatch returns `422` if the workload has no enabled AI daemon;
tasks time out after 30 minutes. A task with `status: paused` is waiting on a
human — `result` holds the agent's question (`NEED_HUMAN: …`); reply with
`POST …/tasks/{taskId}/answer {"text":"…"}` to resume it.
A browser drives itself with `browser.aiAgent {enabled, provider?, model?, instructions?}`
(one driver per browser: its AI agent OR a Browser API controller, never both).
The agent runs on a standard engine — task it via `POST …/workloads/{id}/task`
like any machine agent, and it operates the browser step by step.
## Agent tips
- **One workload at a time.** Create/update/delete each resource via
`/workloads` — you don't send the whole workspace spec.
- **One key, one workspace.** Don't try to manage multiple workspaces with one
key; mint one per workspace.
- **Confirm destructive actions** with the human first.
- **Never leak keys.** Treat `llc_…` like a password; never echo it.
- **Poll status, don't assume.** After a change, watch
`/v1/tenants/$NAME/status` until the workload reaches its running phase.