getcargohq/cargo-skills包含需要注意的行为
SKILL DETAIL
cargo-hosting
getcargohq/cargo-skills/cargo-hosting
Cargo Hosting 技能支持在 Cargo 工作区中创建和管理两类资源:应用(App)和 Worker,以及它们的部署。应用是基于 Vite 的单页应用,通过 @cargo-ai/app-sdk 构建,并托管在 https://<slug>.cargo.app 上。Worker 是无服务器边缘 HTTP 处理器,基于 @cargo-ai/worker-sdk,自动生成 OpenAPI 3.1 规范(位于 /openapi.json)和 Swagger UI(位于 /docs)。部署是将本地源代码目录构建并上传到应用或 Worker 的过程,但部署只有在提升(promote)后才会生效。 该技能提供了完整的生命周期管理:从本地脚手架(init)、创建槽位(create)、部署(deployment create)到提升(deployment promote)。您可以使用命令行工具 cargo-ai 执行各种操作,如列出、获取、更新和删除资源。关键规则包括:slug 必须在托管域内全局唯一,部署不等于上线,--source 必须指向包根目录而非 dist/,构建是异步的,需要轮询状态直到终态。此外,托管会按月消耗积分,请及时移除不再使用的资源。
安装量 · 135查看来源
Installation
npx skills add https://github.com/getcargohq/cargo-skills --skill cargo-hosting
技能文件
SKILL.md
最近同步 · 2026年8月29日
references/examples/apps.md›
# App examples
Apps are Vite single-page apps served on `https://<slug>.cargo.app`, scaffolded from `@cargo-ai/app-sdk`.
## Scaffold → create → deploy → promote (end to end)
```bash
# 1. See what templates exist, then scaffold a local project
cargo-ai hosting app init ./territories --list-templates
cargo-ai hosting app init ./territories --template territories-overview --name "Territories"
# 2. Create the workspace slot. --slug is the live subdomain → must be globally unique.
cargo-ai hosting app create --name "Territories" --slug territories
# → { "uuid": "<app-uuid>", "slug": "territories", "url": "https://territories.cargo.app", ... }
# 3. (optional) Develop locally — write the .env.local the app needs, then run Vite
cargo-ai hosting app env <app-uuid> > ./territories/.env.local
cd ./territories && npm install && npm run dev
# 4. Build & upload (source = package root, not dist/). The backend runs `npm ci && vite build`.
cargo-ai hosting deployment create --app-uuid <app-uuid> --source ./territories
# → { "uuid": "<deployment-uuid>", "status": "...", ... }
# 5. Poll until the build is terminal
cargo-ai hosting deployment get <deployment-uuid>
# 6. Promote to make it live at https://territories.cargo.app
cargo-ai hosting deployment promote --uuid <deployment-uuid>
# 7. Confirm what's live
cargo-ai hosting deployment get-promoted --app-uuid <app-uuid>
```
## List and inspect
```bash
cargo-ai hosting app list # all apps in the workspace
cargo-ai hosting app list --folder-uuid <uuid> # only apps in one folder
cargo-ai hosting app get <app-uuid> # one app's details + live URL
```
## Local development env
`app env` prints the `.env.local` lines a local copy of the app needs — Cargo OAuth client, workspace UUID, app UUID, and API URL — so `getCargoEnv()` / `useCargoApi()` talk to the right workspace.
```bash
# Default API URL (https://api.getcargo.io)
cargo-ai hosting app env <app-uuid> > ./my-app/.env.local
# Point at a different API (e.g. a staging environment)
cargo-ai hosting app env <app-uuid> --api-url https://api.staging.getcargo.io > ./my-app/.env.local
```
## Rename, move, remove
```bash
# Rename
cargo-ai hosting app update --uuid <app-uuid> --name "Renamed App"
# Move into a folder (folders are managed by cargo-workspace-management)
cargo-ai workspaceManagement folder list # find the folder UUID
cargo-ai hosting app update --uuid <app-uuid> --folder-uuid <folder-uuid>
# Move back to the workspace root (literal string "null")
cargo-ai hosting app update --uuid <app-uuid> --folder-uuid null
# Remove (also removes every deployment of this app)
cargo-ai hosting app remove <app-uuid>
```
## Ship a new version of an existing app
The app slot and slug stay put; you just create and promote a fresh deployment.
```bash
cargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app
# poll deployment get <new-deployment-uuid> until terminal
cargo-ai hosting deployment promote --uuid <new-deployment-uuid>
```
Roll back by promoting an earlier deployment — `deployment list --app-uuid <uuid>` shows the history; `deployment promote --uuid <older-uuid>` points the live URL back at it.
references/examples/deployments.md›
# Deployment examples
A deployment is one build+upload of a local source directory to an app or worker. Two facts drive everything below:
1. A deployment belongs to **exactly one** app or worker — `--app-uuid` and `--worker-uuid` are mutually exclusive.
2. **Building is not promoting.** `deployment create` builds; the live URL only moves when you `deployment promote`.
## Create a deployment
```bash
# App: backend runs `npm ci && vite build` in a sandbox
cargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app
# Worker: backend bundles the entrypoint
cargo-ai hosting deployment create --worker-uuid <worker-uuid> --source ./my-worker
```
- `--source` is the **package root** (where `package.json` lives), not a pre-built `dist/`. The build happens server-side.
- Default ignore list: `node_modules,dist,build,.git,.next`. Override the whole list with `--ignore`:
```bash
cargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app \
--ignore "node_modules,dist,build,.git,.next,coverage,.turbo"
```
## Poll the build, then promote
```bash
# Builds are async — poll until the status field is terminal
cargo-ai hosting deployment get <deployment-uuid>
# when terminal (built/succeeded), promote:
cargo-ai hosting deployment promote --uuid <deployment-uuid>
```
If the build failed, inspect the deployment record for the error and fix the source before re-running `deployment create`. See `../response-shapes.md` for the fields to check.
## List deployment history
```bash
cargo-ai hosting deployment list --app-uuid <app-uuid> # newest first
cargo-ai hosting deployment list --worker-uuid <worker-uuid>
```
## See what's currently live
```bash
cargo-ai hosting deployment get-promoted --app-uuid <app-uuid>
cargo-ai hosting deployment get-promoted --worker-uuid <worker-uuid>
```
## Roll back to a previous deployment
Promotion just points the live URL at a deployment, so rolling back is promoting an older one — no rebuild needed.
```bash
# 1. Find the deployment you want to go back to
cargo-ai hosting deployment list --app-uuid <app-uuid>
# 2. Promote it
cargo-ai hosting deployment promote --uuid <older-deployment-uuid>
# 3. Verify
cargo-ai hosting deployment get-promoted --app-uuid <app-uuid>
```
references/examples/workers.md›
# Worker examples
Workers are serverless HTTP handlers that run on the edge — a standard `fetch(request, env)` entrypoint built on `@cargo-ai/worker-sdk`. The `blank` template ships an automatic OpenAPI 3.1 spec at `/openapi.json` and Swagger UI at `/docs`.
## Scaffold → create → deploy → promote (end to end)
```bash
# 1. Scaffold a local worker project
cargo-ai hosting worker init ./my-api --list-templates
cargo-ai hosting worker init ./my-api --template blank --name "My API"
# 2. Create the workspace slot. --slug is the live subdomain → must be globally unique.
cargo-ai hosting worker create --name "My API" --slug my-api
# → { "uuid": "<worker-uuid>", "slug": "my-api", "url": "https://my-api.cargo.app", ... }
# 3. Build & upload (source = package root). The backend bundles the entrypoint.
cargo-ai hosting deployment create --worker-uuid <worker-uuid> --source ./my-api
# → { "uuid": "<deployment-uuid>", "status": "...", ... }
# 4. Poll until the build is terminal
cargo-ai hosting deployment get <deployment-uuid>
# 5. Promote to go live
cargo-ai hosting deployment promote --uuid <deployment-uuid>
# 6. Confirm what's live, then hit it
cargo-ai hosting deployment get-promoted --worker-uuid <worker-uuid>
curl https://my-api.cargo.app/openapi.json
```
## List and inspect
```bash
cargo-ai hosting worker list # all workers
cargo-ai hosting worker list --folder-uuid <uuid> # only workers in one folder
cargo-ai hosting worker get <worker-uuid> # one worker's details + URL
```
## Templates
```bash
cargo-ai hosting worker init ./tmp --list-templates
```
- **`blank`** — edge worker on `@cargo-ai/worker-sdk` with automatic OpenAPI 3.1 spec at `/openapi.json` and Swagger UI at `/docs`.
- **`custom-integration`** — a Cargo Custom Integration worker: manifest / actions / extractors / autocompletes / dynamic schemas, also with `/openapi.json`. Use this when you're building an integration the rest of Cargo can call as a connector action.
## Rename, move, remove
```bash
cargo-ai hosting worker update --uuid <worker-uuid> --name "Renamed Worker"
cargo-ai hosting worker update --uuid <worker-uuid> --folder-uuid <folder-uuid>
cargo-ai hosting worker update --uuid <worker-uuid> --folder-uuid null # back to root
cargo-ai hosting worker remove <worker-uuid> # also removes its deployments
```
## App vs worker — when to use which
- **App** — you want a UI on `*.cargo.app` (dashboard, internal tool, data grid). Vite SPA, `app init`, has an `env` subcommand for local dev.
- **Worker** — you want an HTTP endpoint with no UI (webhook receiver, API, custom integration backend). Edge `fetch` handler, `worker init`, **no** `env` subcommand — runtime config arrives via the `env` argument to `fetch`.
references/response-shapes.md›
# Hosting response shapes
JSON response structures for the `hosting` domain. All commands output JSON to stdout; failures exit non-zero with `{"errorMessage": "..."}`.
## App (`hosting app get` / items in `hosting app list`)
```json
{
"uuid": "app-uuid",
"workspaceUuid": "...",
"name": "My App",
"description": null,
"slug": "my-app",
"url": "https://my-app.cargo.app",
"userUuid": "...",
"folderUuid": null,
"promotedDeployment": null,
"chargedUntil": "2026-02-01T00:00:00Z",
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-15T00:00:00Z",
"deletedAt": null
}
```
**Key fields:** `uuid` (pass as `--app-uuid` to deployment commands), `slug` (the live subdomain), `url` (the live address), `folderUuid` (null unless filed into a folder), `promotedDeployment` (the App Deployment object currently live, or `null` if nothing is promoted yet), `chargedUntil` (end of the period already billed hosting credits — advanced a month at a time, so hosting an app costs credits monthly; see [`cargo-billing`](../../cargo-billing/SKILL.md)).
## Worker (`hosting worker get` / items in `hosting worker list`)
Identical to an app, with one difference: `promotedDeployment` is a **Worker Deployment** (carries `workerUuid` + `meta`, see below). The `uuid` is passed as `--worker-uuid` to deployment commands.
## Deployment (`hosting deployment get` / items in `hosting deployment list`)
A deployment is a discriminated union on `kind` (`"app"` | `"worker"`). Shared fields:
```json
{
"uuid": "deployment-uuid",
"kind": "app",
"appUuid": "app-uuid",
"workspaceUuid": "...",
"status": "success",
"url": "https://my-app.cargo.app",
"sourceS3Path": "...",
"bundleS3Path": "...",
"buildLogS3Filename": "...",
"errorMessage": null,
"meta": {},
"userUuid": "...",
"promotedAt": "2026-01-01T00:01:30Z",
"promotedByUserUuid": "...",
"finishedAt": "2026-01-01T00:01:10Z",
"temporalWorkflowId": "...",
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-01T00:01:30Z"
}
```
- **`kind: "app"`** carries `appUuid` and an empty `meta` (`{}`).
- **`kind: "worker"`** carries `workerUuid` instead of `appUuid`, and `meta: { "bundleSha256": "...", "outboundAllowlist": ["..."] }`.
**Key fields:**
- `uuid` — pass to `deployment promote --uuid`.
- `appUuid` / `workerUuid` — exactly one is set, matching `kind`.
- **`status`** — one of `"pending"`, `"building"`, `"success"`, `"error"`, `"cancelled"`. **Terminal** at `success` / `error` / `cancelled`; only a `success` deployment is worth promoting.
- `errorMessage` — populated when `status` is `error`; `buildLogS3Filename` points at the build log for diagnosing a failed build.
- `promotedAt` / `promotedByUserUuid` — non-null once this deployment has been promoted to the live URL (this is how "is it live?" is represented — there is no separate `isPromoted` flag).
- `finishedAt` — when the build reached a terminal state.
## get-promoted (`hosting deployment get-promoted`)
Returns the currently-promoted Deployment for the given `--app-uuid` / `--worker-uuid` (same shape as above, with `promotedAt` set), or null/empty if nothing is promoted yet. Equivalent to reading `promotedDeployment` off the app/worker.
## env (`hosting app env`)
Not JSON — `hosting app env <appUuid>` prints `.env.local` lines (Cargo OAuth client, workspace UUID, app UUID, `VITE_CARGO_DEPLOYMENT_UUID`, API URL) to stdout. Redirect into a file: `cargo-ai hosting app env <app-uuid> > .env.local`.
## init templates (`hosting app init <dir> --list-templates`)
```json
[
{ "slug": "blank", "description": "..." },
{ "slug": "territories-overview", "description": "..." }
]
```
Workers list their own templates (`blank`, `custom-integration`) via `hosting worker init <dir> --list-templates`. Note `--list-templates` still requires the `<directory>` positional argument.
references/troubleshooting.md›
# Hosting troubleshooting
Common errors in the `hosting` domain and how to fix them.
## `unknown command 'hosting'`
The `hosting` domain shipped in a recent CLI. If `cargo-ai hosting --help` errors, bump the CLI: `npm install -g @cargo-ai/cli@latest`.
## Slug already taken / `create` fails on `--slug`
The `--slug` is the live subdomain (`<slug>.cargo.app`) and **must be globally unique within the hosting domain** — not just unique to your workspace. Pick a more specific slug and re-run `create`.
## I deployed but the URL still shows the old version
`deployment create` only builds and uploads — it does **not** change the live URL. Promote the new deployment:
```bash
cargo-ai hosting deployment get <deployment-uuid> # confirm the build is terminal/succeeded
cargo-ai hosting deployment promote --uuid <deployment-uuid>
cargo-ai hosting deployment get-promoted --app-uuid <app-uuid> # verify what's live
```
## `deployment create` build fails
The build runs server-side in a sandbox (`npm ci && vite build` for apps, entrypoint bundling for workers). A failed build usually means:
- **`--source` points at the wrong directory.** Pass the **package root** (where `package.json` lives), not a pre-built `dist/`.
- **`npm ci` can't resolve the lockfile.** Ensure `package-lock.json` is present and in sync with `package.json`, and that it isn't in the ignore list.
- **Something needed got ignored.** The default ignore list is `node_modules,dist,build,.git,.next`. If you override `--ignore`, you replace the whole list — don't accidentally drop `node_modules` from the ignores (it should stay ignored; the sandbox installs deps itself) while keeping source files you need.
When `status` is `error`, `deployment get <uuid>` exposes the cause: read `errorMessage`, and `buildLogS3Filename` points at the full build log. Fix the source and re-run `deployment create`.
## `--app-uuid` and `--worker-uuid` both passed (or neither)
On `deployment create`, `deployment list`, and `deployment get-promoted` the two flags are **mutually exclusive** — pass exactly one. A deployment targets one app or one worker, never both.
## `folderNotFound` on `--folder-uuid`
The folder UUID doesn't exist. Folders are managed by the [`cargo-workspace-management`](../../cargo-workspace-management/SKILL.md) skill — run `cargo-ai workspaceManagement folder list` to find valid UUIDs. To move a resource back to the workspace root, pass the literal string `null`: `--folder-uuid null`.
## `app env` writes the wrong API URL
By default `hosting app env` points at `https://api.getcargo.io`. For a different environment, override it: `cargo-ai hosting app env <app-uuid> --api-url <url>`. Workers have no `env` subcommand — they receive config via the `env` argument to `fetch(request, env)` at runtime.
## Removing an app/worker took its deployments too
That's by design — `app remove` / `worker remove` cascade to every deployment of that resource. There's no undo; recreate the slot and redeploy if needed.
## Still stuck
File a report so the Cargo team can improve the CLI and these docs:
```bash
cargo-ai workspaceManagement report create \
--title "<one-line summary>" \
--description "<exact command(s), errorMessage, expected vs actual, UUIDs involved>"
```
skill-metadata.json›
{
"$comment": "Generated by .github/scripts/skills-metadata.mjs — do not hand-edit. Regenerate with: node .github/scripts/skills-metadata.mjs --write .",
"name": "cargo-hosting",
"version": "1.0.1",
"documents": [
{
"path": "SKILL.md",
"kind": "entrypoint",
"title": "Cargo CLI — Hosting"
},
{
"path": "references/examples/apps.md",
"kind": "example",
"title": "App examples"
},
{
"path": "references/examples/deployments.md",
"kind": "example",
"title": "Deployment examples"
},
{
"path": "references/examples/workers.md",
"kind": "example",
"title": "Worker examples"
},
{
"path": "references/response-shapes.md",
"kind": "reference",
"title": "Hosting response shapes"
},
{
"path": "references/troubleshooting.md",
"kind": "reference",
"title": "Hosting troubleshooting"
}
],
"contentHash": "5a919e446a59160d7f12000e800253616619cb4a1e839a136b05d0e15641e70f"
}
SKILL.md›
---
name: cargo-hosting
description: "Put something on the internet from Cargo — Vite single-page apps served at https://<slug>.cargo.app and serverless edge workers that answer HTTP requests, plus the deployments that build and promote them. Triggers: \"build me a dashboard for this\", \"host this app\", \"give me a URL to share\", \"deploy this\", \"I need a webhook endpoint\", \"make it live\", \"promote to production\", \"put it on cargo.app\", \"ship a UI for my team\". Skip when: the app or worker should be declared as committed workspace code — use cargo-cdk."
version: "1.0.1"
compatibility: Requires @cargo-ai/cli (npm). Sign in or create an account with `cargo-ai login --email` (emailed code, no browser), `--oauth`, or an API token
homepage: https://github.com/getcargohq/cargo-skills
metadata:
author: getcargo
openclaw:
requires:
bins:
- cargo-ai
install:
- kind: node
package: "@cargo-ai/cli@latest"
bins:
- cargo-ai
homepage: https://github.com/getcargohq/cargo-skills
---
# Cargo CLI — Hosting
**Cargo Hosting** runs two kinds of workspace-scoped resources, plus the deployments that ship them:
- **App** — a Vite single-page app served on `https://<slug>.cargo.app`, built on `@cargo-ai/app-sdk` (Vite + refine + shadcn primitives, with `getCargoEnv()` / `useCargoApi()` wired to the workspace).
- **Worker** — a serverless HTTP handler that runs on the edge (`fetch(request, env)`), built on `@cargo-ai/worker-sdk` (auto OpenAPI 3.1 spec at `/openapi.json`, Swagger UI at `/docs`).
- **Deployment** — one build+upload of a local source directory to an app or worker. A deployment is **not live until it's promoted**.
> For organizing apps/workers into **folders**, use [`cargo-workspace-management`](../cargo-workspace-management/SKILL.md) (`folder …`). The `--folder-uuid` flags here consume those folder UUIDs.
> See `references/examples/apps.md`, `references/examples/workers.md`, and `references/examples/deployments.md` for end-to-end walkthroughs.
> See `references/response-shapes.md` for JSON response structures.
> See `references/troubleshooting.md` for common errors and how to fix them.
## Bootstrap
Already signed in (`cargo-ai whoami` returns a workspace)? Skip to the next section.
```bash
npm install -g @cargo-ai/cli # no global install? prefix every command with `npx @cargo-ai/cli`
cargo-ai login --email [email protected] # emailed code, no browser; creates the account on first use
# alternatives: --oauth (browser) · --token <api-token> (CI)
cargo-ai whoami # confirm the active workspace before any write
```
Every command prints JSON to stdout; failures exit non-zero with `{"errorMessage": "..."}`. Anything that creates a run or a batch is async — pass `--wait-until-finished` or poll the matching `get`. When the full skill bundle is installed, [`../cargo/references/prerequisites.md`](../cargo/references/prerequisites.md) adds the CLI version pin, token scopes, and the admin-only surface.
## The lifecycle
Apps and workers follow the same shape — **scaffold → create slot → deploy → promote**:
```
init (local scaffold) → create (slot + slug) → deployment create (build+upload) → deployment promote (go live)
```
1. **Scaffold** a local project from a template — `hosting app init <dir>` / `hosting worker init <dir>`.
2. **Create the slot** in the workspace — `hosting app create --name --slug` → `appUuid` (or `workerUuid`). The `--slug` becomes the subdomain and **must be globally unique within the hosting domain**.
3. **(apps, optional) Wire local dev** — `hosting app env <appUuid>` prints the `.env.local` lines a local copy needs (Cargo OAuth + workspace + app UUID + API URL).
4. **Deploy** — `hosting deployment create --app-uuid <uuid> --source <dir>` uploads the source; the backend runs `npm ci && vite build` (apps) or bundles the entrypoint (workers) in a sandbox. Returns a `deploymentUuid`.
5. **Promote** — `hosting deployment promote --uuid <deploymentUuid>` points the live URL at that build.
Deploys build asynchronously — **poll `hosting deployment get <uuid>`** until the status is terminal before promoting (see [Async polling](#async-polling)).
## Apps
```bash
# Discover
cargo-ai hosting app list # all apps (filter with --folder-uuid <uuid>)
cargo-ai hosting app get <uuid> # one app's details + URL
# Scaffold locally (Vite + @cargo-ai/app-sdk)
cargo-ai hosting app init ./my-app --list-templates # see available templates, then:
cargo-ai hosting app init ./my-app --template blank --name "My App"
# Create the slot (slug must be globally unique → it's the subdomain)
cargo-ai hosting app create --name "My App" --slug my-app --folder-uuid <folder-uuid>
# Print .env.local for local development
cargo-ai hosting app env <app-uuid>
cargo-ai hosting app env <app-uuid> --api-url https://api.getcargo.io
# Update / remove
cargo-ai hosting app update --uuid <app-uuid> --name "Renamed"
cargo-ai hosting app update --uuid <app-uuid> --folder-uuid null # move to workspace root
cargo-ai hosting app remove <app-uuid> # also removes its deployments
```
Templates: `blank` (minimal starting point) and `territories-overview` (read-only territories grid demoing `useCargoApi()` + react-query). Run `app init <dir> --list-templates` for the current list.
## Workers
Same command shape as apps — substitute `worker` for `app`:
```bash
cargo-ai hosting worker list # filter with --folder-uuid <uuid>
cargo-ai hosting worker get <uuid>
# Scaffold (edge fetch(request, env) handler on @cargo-ai/worker-sdk)
cargo-ai hosting worker init ./my-worker --list-templates
cargo-ai hosting worker init ./my-worker --template blank --name "My Worker"
cargo-ai hosting worker create --name "My Worker" --slug my-worker --folder-uuid <folder-uuid>
cargo-ai hosting worker update --uuid <worker-uuid> --name "Renamed"
cargo-ai hosting worker remove <worker-uuid> # also removes its deployments
```
Templates: `blank` (auto OpenAPI spec + Swagger UI) and `custom-integration` (a Cargo Custom Integration — manifest / actions / extractors / autocompletes / dynamic schemas). Workers have **no `env` subcommand** — they read config from the `env` argument passed to `fetch` at runtime.
## Deployments
A deployment belongs to exactly one app **or** one worker (`--app-uuid` and `--worker-uuid` are mutually exclusive).
```bash
# List / inspect
cargo-ai hosting deployment list --app-uuid <uuid> # or --worker-uuid <uuid>
cargo-ai hosting deployment get <deployment-uuid> # status + metadata
cargo-ai hosting deployment get-promoted --app-uuid <uuid> # what's currently live
# Build & upload a local source directory (point at the package root, NOT dist/)
cargo-ai hosting deployment create --app-uuid <uuid> --source ./my-app
cargo-ai hosting deployment create --worker-uuid <uuid> --source ./my-worker
# default ignores: node_modules,dist,build,.git,.next — override with --ignore "a,b,c"
# Go live
cargo-ai hosting deployment promote --uuid <deployment-uuid>
```
## Critical rules
- **`--slug` must be globally unique within the hosting domain** — it's the live subdomain (`<slug>.cargo.app`). A clash fails at `create`.
- **Deploying ≠ going live.** `deployment create` builds and uploads; the URL only changes when you `deployment promote` that deployment. Use `deployment get-promoted` to see what's live now.
- **`--source` is the package root, not `dist/`.** The build runs in a Cargo sandbox: `npm ci && vite build` for apps, entrypoint bundling for workers. Shipping a pre-built `dist/` will not work.
- **Builds are async** — poll `deployment get` until terminal before promoting (see below).
- **`--app-uuid` / `--worker-uuid` are mutually exclusive** on `deployment create`, `deployment list`, and `deployment get-promoted`. Pass exactly one.
- **`remove` cascades** — removing an app or worker also removes all of its deployments.
- **`update --folder-uuid null`** (literal string `null`) moves a resource back to the workspace root.
- **Hosting consumes credits monthly per resource.** Each app/worker carries a `chargedUntil` that an hourly sweep advances a month at a time, so a live app or worker bills hosting credits on an ongoing basis — `remove` resources you no longer serve. Track consumption via [`cargo-billing`](../cargo-billing/SKILL.md).
## Async polling
`deployment create` kicks off a sandboxed build. The deployment's `status` moves `pending → building → success` (or `error` / `cancelled`). Poll until terminal, then promote the `success` one:
```bash
cargo-ai hosting deployment get <deployment-uuid> # poll ~2–5s until status is terminal
```
Terminal statuses are `success`, `error`, and `cancelled` — only promote a `success` deployment. On `error`, read the deployment's `errorMessage` (and `buildLogS3Filename`) to diagnose the build. For the general polling pattern (intervals, retries), see [`../cargo-orchestration/references/polling.md`](../cargo-orchestration/references/polling.md).
## Help
Every command supports `--help`:
```bash
cargo-ai hosting app create --help
cargo-ai hosting deployment create --help
```