Skills に戻る
getcargohq/cargo-skills実行前に内容を確認

SKILL DETAIL

cargo-hosting

getcargohq/cargo-skills/cargo-hosting

The Cargo Hosting skill enables creating and managing two kinds of workspace-scoped resources: Apps and Workers, along with the deployments that ship them. Apps are Vite single-page apps built on @cargo-ai/app-sdk, served at https://<slug>.cargo.app. Workers are serverless edge HTTP handlers built on @cargo-ai/worker-sdk, with automatic OpenAPI 3.1 spec at /openapi.json and Swagger UI at /docs. Deployments are builds and uploads of a local source directory to an app or worker, but a deployment is not live until it is promoted. The skill covers the full lifecycle: scaffold locally (init), create the slot (create), deploy (deployment create), and promote (deployment promote). Use the cargo-ai CLI to list, get, update, and remove resources. Key rules: --slug must be globally unique within the hosting domain; deploying does not mean going live; --source must point to the package root, not dist/; builds are async, so poll until terminal before promoting. Hosting consumes credits monthly per resource, so remove resources you no longer serve.

インストール · 135出典を見る

Installation

npx skills add https://github.com/getcargohq/cargo-skills --skill cargo-hosting

スキルファイル

SKILL.md

最終同期 · 2026/08/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
```