{"id":"8b97efe4-da51-4a50-8b00-7ea7ac90e9b5","entityType":"agent","slug":"clawhub-cargo-ai-cargo-hosting","name":"cargo-hosting","canonicalUrl":"https://www.xpersona.co/agent/clawhub-cargo-ai-cargo-hosting","canonicalPath":"/agent/clawhub-cargo-ai-cargo-hosting","generatedAt":"2026-10-11T21:51:06.681Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T18:49:48.704Z","emptyReason":null},"description":"Put something on the internet from Cargo — hosted web apps (Vite by default, other static frameworks detected) and serverless edge workers that answer HTTP requests, plus the deployments that build and promote them, the env vars and secrets a worker reads, running a worker locally, and custom domains and search indexing for public sites. 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\", \"ship a UI for my team\", \"give my worker an API token\", \"set a secret on the worker\", \"Missing CARGO_API_TOKEN\", \"my app cannot call my worker\", \"run the worker locally\", \"put it on my own domain\", \"make the site indexable by Google\". Skip when: the app or worker should be declared as committed workspace code — use cargo-project.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s178dcd9wkfn0a2fqrygmt3jzn87j9e1:cargo-hosting","sourceUrl":"https://clawhub.ai/cargo-ai/cargo-hosting","homepage":"https://clawhub.ai/cargo-ai/skills/cargo-hosting","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/cargo-ai/cargo-hosting","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/cargo-ai/skills/cargo-hosting","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"cargo-hosting technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T18:49:48.704Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T18:49:48.704Z","emptyReason":null},"stars":null,"forks":null,"downloads":1007,"likes":null,"task":null,"library":null,"packageName":null,"latestVersion":"1.1.1","tractionLabel":"1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T18:49:48.690Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T18:49:48.704Z","lastCrawledAt":"2026-10-11T18:49:48.690Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T18:49:48.690Z","lastVerifiedAt":null,"highlights":[{"version":"1.1.1","createdAt":"2026-09-24T17:56:43.670Z","changelog":"cargo-hosting 1.1.1 - Bumped version to 1.1.1. - Updated skill-metadata and documentation in SKILL.md. - Removed deprecated skill-card.md file.","fileCount":9,"zipByteSize":22270},{"version":"1.1.0","createdAt":"2026-09-21T22:03:59.091Z","changelog":"### Version 1.1.0 This is a big update expanding hosting capabilities and documentation. - Added support for more front-end frameworks (Next.js static export, Astro, SvelteKit, Nuxt, Gatsby, Create React App) with automatic detection and appropriate build commands. - Introduced environment variable and secret management for workers, including support for injecting `CARGO_API_TOKEN` and other secrets. - Added support for running workers locally and improved documentation around local development workflows. - Clarified domain and URL structure for hosted apps and workers (unique host pattern by workspace, CORS caveats documented). - Expanded and updated documentation: new examples, more troubleshooting tips, details on custom domains and public site indexing. - Updated and reorganized sample/reference files; removed deprecated files (e.g., skill-card.md).","fileCount":9,"zipByteSize":22360},{"version":"1.0.2","createdAt":"2026-09-14T06:27:06.938Z","changelog":"- Revised and shortened the skill description for greater clarity and focus on practical triggers and use cases. - Added a new \"Bootstrap\" section with clearer prerequisites and login instructions. - Restructured and condensed introductory and prerequisite content to improve onboarding. - Removed outdated or redundant details; clarified JSON output and error conventions. - skill-card.md was removed as part of content streamlining.","fileCount":9,"zipByteSize":13257},{"version":"1.0.1","createdAt":"2026-08-11T21:44:31.338Z","changelog":"- Added skill-metadata.json and removed skill-card.md. - Updated SKILL.md with improved wording for authentication: now clarifies you can sign in or create an account with `cargo-ai login --email` (emailed code, no browser), `--oauth`, or an API token. - Bumped version to 1.0.1. - No changes to core commands or behaviors.","fileCount":9,"zipByteSize":12652},{"version":"1.0.0","createdAt":"2026-07-10T00:56:04.560Z","changelog":"Initial release of cargo-hosting skill. - Build, deploy, and manage Vite SPA apps and serverless workers on Cargo using the Cargo CLI. - Supports scaffolding new apps or workers from templates. - Manage deployments: build, upload, promote, and list deployment states. - Apps served as SPAs on *.cargo.app; workers provide edge HTTP handlers with automatic OpenAPI docs. - Requires @cargo-ai/cli (npm) and a Cargo account. - Includes support for workspace folders and separation of app/worker resources.","fileCount":8,"zipByteSize":12256}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s178dcd9wkfn0a2fqrygmt3jzn87j9e1:cargo-hosting","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s178dcd9wkfn0a2fqrygmt3jzn87j9e1:cargo-hosting` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/cargo-ai/cargo-hosting before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-cargo-ai-cargo-hosting/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-cargo-ai-cargo-hosting/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-cargo-ai-cargo-hosting/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-cargo-ai-cargo-hosting/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-cargo-ai-cargo-hosting/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-cargo-ai-cargo-hosting/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T21:51:06.677Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-cargo-ai-cargo-hosting/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-cargo-ai-cargo-hosting/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-cargo-ai-cargo-hosting/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-cargo-ai-cargo-hosting/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T18:49:48.704Z","emptyReason":null},"readme":"Skill: cargo-hosting\n\nOwner: cargo-ai\n\nSummary: Put something on the internet from Cargo — hosted web apps (Vite by default, other static frameworks detected) and serverless edge workers that answer HTTP requests, plus the deployments that build and promote them, the env vars and secrets a worker reads, running a worker locally, and custom domains and search indexing for public sites. 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\", \"ship a UI for my team\", \"give my worker an API token\", \"set a secret on the worker\", \"Missing CARGO_API_TOKEN\", \"my app cannot call my worker\", \"run the worker locally\", \"put it on my own domain\", \"make the site indexable by Google\". Skip when: the app or worker should be declared as committed workspace code — use cargo-project.\n\nTags: latest:1.1.1\n\nVersion history:\n\nv1.1.1 | 2026-09-24T17:56:43.670Z | auto\n\ncargo-hosting 1.1.1\n\n- Bumped version to 1.1.1.\n- Updated skill-metadata and documentation in SKILL.md.\n- Removed deprecated skill-card.md file.\n\nv1.1.0 | 2026-09-21T22:03:59.091Z | auto\n\n### Version 1.1.0\n\nThis is a big update expanding hosting capabilities and documentation.\n\n- Added support for more front-end frameworks (Next.js static export, Astro, SvelteKit, Nuxt, Gatsby, Create React App) with automatic detection and appropriate build commands.\n- Introduced environment variable and secret management for workers, including support for injecting `CARGO_API_TOKEN` and other secrets.\n- Added support for running workers locally and improved documentation around local development workflows.\n- Clarified domain and URL structure for hosted apps and workers (unique host pattern by workspace, CORS caveats documented).\n- Expanded and updated documentation: new examples, more troubleshooting tips, details on custom domains and public site indexing.\n- Updated and reorganized sample/reference files; removed deprecated files (e.g., skill-card.md).\n\nv1.0.2 | 2026-09-14T06:27:06.938Z | auto\n\n- Revised and shortened the skill description for greater clarity and focus on practical triggers and use cases.\n- Added a new \"Bootstrap\" section with clearer prerequisites and login instructions.\n- Restructured and condensed introductory and prerequisite content to improve onboarding.\n- Removed outdated or redundant details; clarified JSON output and error conventions.\n- skill-card.md was removed as part of content streamlining.\n\nv1.0.1 | 2026-08-11T21:44:31.338Z | auto\n\n- Added skill-metadata.json and removed skill-card.md.\n- Updated SKILL.md with improved wording for authentication: now clarifies you can sign in or create an account with `cargo-ai login --email` (emailed code, no browser), `--oauth`, or an API token.\n- Bumped version to 1.0.1.\n- No changes to core commands or behaviors.\n\nv1.0.0 | 2026-07-10T00:56:04.560Z | auto\n\nInitial release of cargo-hosting skill.\n\n- Build, deploy, and manage Vite SPA apps and serverless workers on Cargo using the Cargo CLI.\n- Supports scaffolding new apps or workers from templates.\n- Manage deployments: build, upload, promote, and list deployment states.\n- Apps served as SPAs on *.cargo.app; workers provide edge HTTP handlers with automatic OpenAPI docs.\n- Requires @cargo-ai/cli (npm) and a Cargo account.\n- Includes support for workspace folders and separation of app/worker resources.\n\nArchive index:\n\nArchive v1.1.1: 9 files, 22270 bytes\n\nFiles: references/examples/apps.md (4236b), references/examples/deployments.md (2336b), references/examples/workers.md (7321b), references/response-shapes.md (4082b), references/troubleshooting.md (7549b), skill-card.md (2178b), skill-metadata.json (1035b), SKILL.md (21637b), _meta.json (132b)\n\nFile v1.1.1:SKILL.md\n\n---\nname: cargo-hosting\ndescription: \"Put something on the internet from Cargo — hosted web apps (Vite by default, other static frameworks detected) and serverless edge workers that answer HTTP requests, plus the deployments that build and promote them, the env vars and secrets a worker reads, running a worker locally, and custom domains and search indexing for public sites. 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\\\", \\\"ship a UI for my team\\\", \\\"give my worker an API token\\\", \\\"set a secret on the worker\\\", \\\"Missing CARGO_API_TOKEN\\\", \\\"my app cannot call my worker\\\", \\\"run the worker locally\\\", \\\"put it on my own domain\\\", \\\"make the site indexable by Google\\\". Skip when: the app or worker should be declared as committed workspace code — use cargo-project.\"\nversion: \"1.1.1\"\ncompatibility: 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\nhomepage: https://github.com/getcargohq/cargo-skills\nmetadata:\n  author: getcargo\n  openclaw:\n    requires:\n      bins:\n        - cargo-ai\n    install:\n      - kind: node\n        package: \"@cargo-ai/cli@latest\"\n        bins:\n          - cargo-ai\n    homepage: https://github.com/getcargohq/cargo-skills\n---\n\n# Cargo CLI — Hosting\n\n**Cargo Hosting** runs two kinds of workspace-scoped resources, plus the deployments that ship them:\n\n- **App** — a static front end (a Vite single-page app by default; Next.js static export, Astro, SvelteKit, Nuxt, Gatsby and Create React App are detected too) served on its own subdomain (see [URLs](#urls)). The templates are built on `@cargo-ai/app-sdk` (Vite + refine + shadcn primitives, with `getCargoEnv()` / `useCargoApi()` wired to the workspace).\n- **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`).\n- **Deployment** — one build+upload of a local source directory to an app or worker. A deployment is **not live until it's promoted**.\n\n> 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.\n\n> See `references/examples/apps.md`, `references/examples/workers.md`, and `references/examples/deployments.md` for end-to-end walkthroughs.\n> See `references/response-shapes.md` for JSON response structures.\n> See `references/troubleshooting.md` for common errors and how to fix them.\n\n## Bootstrap\n\nAlready signed in (`cargo-ai whoami` returns a workspace)? Skip to the next section.\n\n```bash\nnpm install -g @cargo-ai/cli            # no global install? prefix every command with `npx @cargo-ai/cli`\ncargo-ai login --email you@company.com  # emailed code, no browser; creates the account on first use\n                                        # alternatives: --oauth (browser) · --token <api-token> (CI)\ncargo-ai whoami                         # confirm the active workspace before any write\n```\n\nEvery 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.\n\n## The lifecycle\n\nApps and workers follow the same shape — **scaffold → create slot → deploy → promote**:\n\n```\ninit (local scaffold) → create (slot + slug) → deployment create (build+upload) → deployment promote (go live)\n```\n\n1. **Scaffold** a local project from a template — `hosting app init <dir>` / `hosting worker init <dir>`.\n2. **Create the slot** in the workspace — `hosting app create --name --slug` → `appUuid` (or `workerUuid`). The `--slug` becomes part of the subdomain and must be unique within the workspace.\n3. **(optional) Wire local dev** — for an app, `hosting app env <appUuid>` prints the `.env.local` lines a local copy needs (Cargo OAuth + workspace + app UUID + API URL). For a worker, `npm run dev` in the scaffold (see [Run a worker locally](#run-a-worker-locally)). A worker that calls the Cargo API also needs a `CARGO_API_TOKEN` secret before its first deploy (see [Worker env vars and secrets](#worker-env-vars-and-secrets)).\n4. **Deploy** — `hosting deployment create --app-uuid <uuid> --source <dir>` uploads the source. The backend then builds it in a sandbox: for an app, `npm ci --ignore-scripts` followed by the app's own `build` script, or the framework's default build if there is none (see [App builds](#app-builds)); for a worker, it bundles the entrypoint. Returns a `deploymentUuid`.\n5. **Promote** — `hosting deployment promote --uuid <deploymentUuid>` points the live URL at that build.\n\nDeploys build asynchronously — **poll `hosting deployment get <uuid>`** until the status is terminal before promoting (see [Async polling](#async-polling)).\n\n## URLs\n\nThe live host is **`<slug>-<first 8 chars of the workspace UUID>`** under the hosting root domain, and apps and workers have **different root domains** — in production `https://<slug>-<ws>.app.getcargo.run` for an app, `https://<slug>-<ws>.worker.getcargo.run` for a worker. The workspace suffix is what makes the host globally unique, which is why a slug only has to be unique inside your workspace.\n\nDon't build the URL by hand. Read `url` from `create` or `get` — the root domain differs per environment. Each deployment also gets a preview host, `https://deployment-<deploymentUuid>.<root>`, before it is promoted.\n\nBecause the roots differ, **an app calling a worker is always a cross-origin request.** No option serves them on the same origin, so the worker has to answer CORS. See the app + worker pattern in [`references/examples/workers.md`](references/examples/workers.md#calling-a-worker-from-an-app).\n\n## Apps\n\n```bash\n# Discover\ncargo-ai hosting app list                          # all apps (filter with --folder-uuid <uuid>)\ncargo-ai hosting app get <uuid>                     # one app's details + URL\n\n# Scaffold locally (Vite + @cargo-ai/app-sdk)\ncargo-ai hosting app init ./my-app --list-templates # see available templates, then:\ncargo-ai hosting app init ./my-app --template blank --name \"My App\"\n\n# Create the slot (slug unique per workspace; `url` in the response is the live host)\ncargo-ai hosting app create --name \"My App\" --slug my-app --folder-uuid <folder-uuid>\n\n# Print .env.local for local development\ncargo-ai hosting app env <app-uuid>\ncargo-ai hosting app env <app-uuid> --api-url https://api.getcargo.io\n\n# Update / remove\ncargo-ai hosting app update --uuid <app-uuid> --name \"Renamed\"\ncargo-ai hosting app update --uuid <app-uuid> --folder-uuid null   # move to workspace root\ncargo-ai hosting app remove <app-uuid>                             # also removes its deployments\n```\n\nTemplates: `blank` (minimal starting point), `territories-overview` (read-only territories grid demoing `useCargoApi()` + react-query), and `public-site` (a public, indexable site that prerenders every route from its own build script and ships `robots.txt` + `sitemap.xml`). Run `app init <dir> --list-templates` for the current list.\n\n### App builds\n\n**If `package.json` declares a `build` script, Cargo runs it, and that script owns the whole build.** Cargo runs nothing before or after it, so the script must produce the client bundle as well as anything extra, such as prerendered HTML. Without a `build` script, the detected framework's default command runs:\n\n| Framework (detected from dependencies) | Default build | Output dir | Public env prefix |\n|---|---|---|---|\n| Vite, and anything undetected | `vite build` | `dist` | `VITE_` |\n| Next.js (static export) | `next build` | `out` | `NEXT_PUBLIC_` |\n| Astro | `astro build` | `dist` | `PUBLIC_` |\n| SvelteKit | `svelte-kit build` | `build` | `PUBLIC_` |\n| Nuxt | `nuxt generate` | `.output/public` | `NUXT_PUBLIC_` |\n| Gatsby | `gatsby build` | `public` | `GATSBY_` |\n| Create React App | `react-scripts build` | `build` | `REACT_APP_` |\n\n- **Output must land in that framework's output directory and contain an `index.html`**, or the build fails. Unknown paths fall back to that shell.\n- **Whatever the build script does now runs on every deploy.** That includes a `tsc` pass, a different `--mode`, and `prebuild`/`postbuild` hooks. A script that fails there fails the deploy. The live deployment keeps serving, because promotion only follows a successful build.\n- **A `build` script Cargo can't use falls back silently.** That covers an unparseable `package.json`, an empty script, or a non-string entry. The deploy still goes green, and only the build log says why, so check it when a prerender step seems to have been skipped.\n- **Platform values are injected under every public prefix.** A Vite app reads `VITE_CARGO_API_URL` and a Next.js app reads `NEXT_PUBLIC_CARGO_API_URL`. When a `build` script is used, they are also passed as real process env vars, so a plain-Node prerender step sees them. User env values are redacted from build logs.\n\n### App env vars are public\n\nAn app reads only env vars whose key starts with a **public prefix**: `VITE_`, `NEXT_PUBLIC_`, `PUBLIC_`, `NUXT_PUBLIC_`, `GATSBY_` or `REACT_APP_`. Any of these prefixes works whatever the framework. They come from workspace env vars and from app-level entries (`POST /v1/hosting/env-vars` with `\"kind\":\"app\"`, or CDK `defineApp({ env })`). Every one of them is compiled into a bundle anyone can download. For that reason:\n\n- **App env vars cannot be secret.** The API rejects `isSecret: true` with `secretNotSupportedForApp`, CDK `defineApp` throws on a `secret()` value, and secret workspace entries never reach an app build. Credentials belong in a worker that the app calls.\n- Keys matching a platform key under any prefix (`*_CARGO_API_URL`, `*_CARGO_WORKSPACE_UUID`, `*_APP_BASE_PATH`, …) are reserved.\n- Values are baked in at build time, so a change needs a new deploy + promote.\n\n### Custom domains and search indexing\n\n**Cargo-owned hosts are `noindex`.** The default `*.app.getcargo.run` host and every `deployment-<uuid>` preview answer with `X-Robots-Tag: noindex`, so **an app only becomes indexable on a custom domain**. No CLI command attaches one at CLI 1.0.96, so use the API:\n\n```bash\nCARGO_API_BASE=$(cargo-ai whoami | jq -r '.baseUrl')   # https://api.getcargo.io in production\ncurl -X POST \"$CARGO_API_BASE/v1/hosting/custom-domains\" \\\n  -H \"authorization: Bearer $CARGO_API_TOKEN\" -H \"content-type: application/json\" \\\n  -d '{\"kind\":\"app\",\"appUuid\":\"<uuid>\",\"hostname\":\"www.example.com\"}'\n# → DNS records to add: certificate validation records + a cnameTarget for the hostname\ncurl -X POST \"$CARGO_API_BASE/v1/hosting/custom-domains/<domain-uuid>/refresh-status\" \\\n  -H \"authorization: Bearer $CARGO_API_TOKEN\"                                   # repeat until status is \"active\"\n```\n\n- The hostname needs **at least three labels**, so attach `www.example.com`, not `example.com`.\n- Workers take custom domains too (`\"kind\":\"worker\",\"workerUuid\":…`). Separate hostnames are still separate origins, so app → worker CORS still applies.\n- **Indexing also needs real HTML per URL.** Prerender in the `build` script (the `public-site` template shows how). Link prerendered routes as `.html` paths: `/about.html` serves the prerendered file, while `/about` falls back to the SPA shell. Ship `public/robots.txt` + `public/sitemap.xml`, and put a title, description, canonical and Open Graph tags in each prerendered head.\n- **A hosted app never returns a 404.** An unknown path serves the SPA shell with a `200`, so a client-side not-found view should set `<meta name=\"robots\" content=\"noindex\">` itself.\n- **Apps built on `CargoRefineApp` require a Cargo login** and cannot be indexed. A public site renders its own tree.\n- Nothing is submitted to search engines for you. Submit the sitemap in Search Console.\n\n## Workers\n\nSame command shape as apps — substitute `worker` for `app`:\n\n```bash\ncargo-ai hosting worker list                        # filter with --folder-uuid <uuid>\ncargo-ai hosting worker get <uuid>\n\n# Scaffold (edge fetch(request, env) handler on @cargo-ai/worker-sdk)\ncargo-ai hosting worker init ./my-worker --list-templates\ncargo-ai hosting worker init ./my-worker --template blank --name \"My Worker\"\n\ncargo-ai hosting worker create --name \"My Worker\" --slug my-worker --folder-uuid <folder-uuid>\ncargo-ai hosting worker update --uuid <worker-uuid> --name \"Renamed\"\ncargo-ai hosting worker remove <worker-uuid>        # also removes its deployments\n```\n\nTemplates: `blank` (auto OpenAPI spec + Swagger UI) and `custom-integration` (a Cargo Custom Integration — manifest / actions / extractors / autocompletes / dynamic schemas).\n\n**Entrypoint.** The build bundles the first of `src/index.ts`, `src/index.js`, `index.ts`, `index.js` that exists, and fails if there is none. `.mjs`, `.mts` and `.cjs` entrypoints are not picked up, so rename them to `.js`/`.ts`; ES module syntax works in `.js` because the scaffold's `package.json` sets `\"type\": \"module\"`.\n\n### Worker env vars and secrets\n\nA worker reads configuration from `c.env.KEY` (Hono context) or the `env` argument to `fetch(request, env)`. Three sources feed it:\n\n| Source | Set with | Reaches |\n|---|---|---|\n| **Platform bindings** | automatic | `CARGO_API_URL`, `CARGO_WORKSPACE_UUID`, `CARGO_WORKER_UUID` |\n| **Workspace env vars** | `cargo-ai workspaceManagement envVar create --key K [--secret]` | every worker in the workspace (apps get only the non-secret, public-prefixed ones) |\n| **Worker env vars** | `defineWorker({ env })` in CDK, or `POST /v1/hosting/env-vars` (no `hosting` CLI command at CLI 1.0.96) | that worker only, and a worker entry overrides a workspace entry with the same key |\n\n**`CARGO_API_TOKEN` is not injected.** `createCargoApi(c.env)` throws `Missing CARGO_API_TOKEN…` until you provide one. Mint a workspace API token and store it as a secret before the first deploy:\n\n```bash\ncargo-ai workspaceManagement token create --name \"worker: my-worker\"   # value shown ONCE\nexport CARGO_API_TOKEN=<token value>\ncargo-ai workspaceManagement envVar create --key CARGO_API_TOKEN --secret \\\n  --description \"Cargo API token for hosted workers\"                     # --value omitted → read from $CARGO_API_TOKEN\n```\n\nA workspace entry gives *every* worker that token. If only one worker should hold it, set it on that worker instead:\n\n- **CDK:** `defineWorker(\"my-worker\", { path, env: { CARGO_API_TOKEN: secret(\"CARGO_API_TOKEN\") } })`.\n- **API:** `POST /v1/hosting/env-vars` with `{\"kind\":\"worker\",\"workerUuid\":\"<uuid>\",\"key\":\"CARGO_API_TOKEN\",\"value\":\"…\",\"isSecret\":true}`. From TypeScript that is `api.hosting.envVars.create(…)` in `@cargo-ai/api`, and `list` takes `{ workerUuid }`.\n\n**Values are captured at deploy time, not read live.** Bindings are attached when a deployment is promoted, and non-secret values are also compiled into the bundle as `process.env.KEY`. After adding or changing a variable, **run `deployment create` and `promote` again**. The running worker keeps the old values until then.\n\n**Secrets never enter the bundle.** A secret binds as an encrypted runtime value. Only non-secret values are compiled in, and bundles can be downloaded from the per-deployment preview host, so anything sensitive must be `--secret` / `isSecret: true`.\n\n### Run a worker locally\n\nBoth templates ship a `dev.ts` harness: `npm run dev` serves `src/index.ts` under Node with hot reload on `http://localhost:8787` (override with `PORT`). `dev.ts` is never deployed.\n\n- **No platform bindings exist locally**, so `c.env` is empty. `createCargoApi` falls back to `process.env`, so export `CARGO_API_TOKEN` (and `CARGO_API_URL` for a non-production API) in the shell before `npm run dev`. Your own variables need the same fallback in your code.\n- **`manifest.json` `outboundAllowlist` and cron triggers are not enforced locally.** Test them on a deployment.\n\nA project scaffolded before `dev.ts` existed can copy it from a fresh `hosting worker init`, along with the `dev` script and the `@hono/node-server` + `tsx` dev dependencies.\n\n### Worker logs and errors\n\n`createWorker()` captures `console.log/info/warn/error/debug` during each request Cargo dispatches and ships them to the worker's logs (at most 50 lines per request). An **uncaught** error is logged with its stack and answered with a bare `500`.\n\n**A caught error leaves no trace.** If a route catches an exception and returns its own sanitized response, such as `502 \"The data provider is unavailable\"`, the log gets only the HTTP line. **Log the error before you sanitize it:**\n\n```ts\ntry {\n  return c.json(await loadData(createCargoApi(c.env)));\n} catch (err) {\n  console.error(err);                        // stack goes to the logs; the response stays clean\n  return c.json({ error: \"The data provider is unavailable.\" }, 502);\n}\n```\n\nAt CLI 1.0.96 the logs are readable in the web app or through the API: `POST /v1/hosting/logs/list` with `{\"workerUuid\":\"<uuid>\",\"levels\":[\"error\"],\"limit\":50}`, or `api.hosting.log.list(…)` from TypeScript. It also filters on `runUuid`, `search`, and `occurredAfter`/`occurredBefore`. The CLI has no logs command yet.\n\n## Deployments\n\nA deployment belongs to exactly one app **or** one worker (`--app-uuid` and `--worker-uuid` are mutually exclusive).\n\n```bash\n# List / inspect\ncargo-ai hosting deployment list --app-uuid <uuid>          # or --worker-uuid <uuid>\ncargo-ai hosting deployment get <deployment-uuid>           # status + metadata\ncargo-ai hosting deployment get-promoted --app-uuid <uuid>  # what's currently live\n\n# Build & upload a local source directory (point at the package root, NOT dist/)\ncargo-ai hosting deployment create --app-uuid <uuid> --source ./my-app\ncargo-ai hosting deployment create --worker-uuid <uuid> --source ./my-worker\n# default ignores: node_modules,dist,build,.git,.next — override with --ignore \"a,b,c\"\n\n# Go live\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n```\n\n## Critical rules\n\n- **`--slug` is unique per workspace**, and the live host is `<slug>-<workspace prefix>.<root>`, with a different root for apps and workers. Use the `url` from `get` rather than composing it (see [URLs](#urls)). A duplicate slug fails at `create` with `duplicateSlug`.\n- **An app calling a worker is cross-origin.** The worker must send CORS headers for the app's origin. No same-origin mount exists.\n- **`CARGO_API_TOKEN` is yours to provide.** It is never injected, and `createCargoApi` throws without it. Set it as a secret (workspace or worker env var) **before** the deploy that needs it.\n- **Env var changes need a new deploy + promote.** Values are bound at promote and non-secrets are compiled into the bundle, so editing a variable changes nothing until the next deployment is live.\n- **Log before you sanitize.** Only uncaught errors reach the logs with a stack. A `catch` that returns a friendly message must `console.error(err)` first, or the cause is gone.\n- **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.\n- **`--source` is the package root, not `dist/`.** The build runs in a Cargo sandbox: `npm ci --ignore-scripts` then the app's `build` script (or the framework default) for apps, entrypoint bundling for workers. Shipping a pre-built `dist/` will not work.\n- **App env vars are public and never secret.** They are compiled into the bundle, and `isSecret` is rejected. Put credentials in a worker.\n- **Cargo-owned hosts are `noindex`.** A public site needs a custom domain (API only at 1.0.96) and prerendered HTML to be indexed.\n- **Builds are async** — poll `deployment get` until terminal before promoting (see below).\n- **`--app-uuid` / `--worker-uuid` are mutually exclusive** on `deployment create`, `deployment list`, and `deployment get-promoted`. Pass exactly one.\n- **`remove` cascades** — removing an app or worker also removes all of its deployments.\n- **`update --folder-uuid null`** (literal string `null`) moves a resource back to the workspace root.\n- **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).\n\n## Async polling\n\n`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:\n\n```bash\ncargo-ai hosting deployment get <deployment-uuid>   # poll ~2–5s until status is terminal\n```\n\nTerminal 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).\n\n## Help\n\nEvery command supports `--help`:\n\n```bash\ncargo-ai hosting app create --help\ncargo-ai hosting deployment create --help\n```\n\nFile v1.1.1:_meta.json\n\n{\n  \"ownerId\": \"kn7by8t6yt9yghbxtxz6hv0bts87k6bq\",\n  \"slug\": \"cargo-hosting\",\n  \"version\": \"1.1.1\",\n  \"publishedAt\": 1790272603670\n}\n\nFile v1.1.1:references/examples/apps.md\n\n# App examples\n\nApps are static front ends (Vite single-page apps by default; other frameworks are detected, see `SKILL.md` → App builds) served on `https://<slug>-<workspace prefix>.app.getcargo.run` in production (read the exact host from `url`), scaffolded from `@cargo-ai/app-sdk`.\n\n## Scaffold → create → deploy → promote (end to end)\n\n```bash\n# 1. See what templates exist, then scaffold a local project\ncargo-ai hosting app init ./territories --list-templates\ncargo-ai hosting app init ./territories --template territories-overview --name \"Territories\"\n\n# 2. Create the workspace slot. --slug is unique per workspace; the host adds a workspace suffix.\ncargo-ai hosting app create --name \"Territories\" --slug territories\n# → { \"uuid\": \"<app-uuid>\", \"slug\": \"territories\", \"url\": \"https://territories-1a2b3c4d.app.getcargo.run\", ... }\n\n# 3. (optional) Develop locally — write the .env.local the app needs, then run Vite\ncargo-ai hosting app env <app-uuid> > ./territories/.env.local\ncd ./territories && npm install && npm run dev\n\n# 4. Build & upload (source = package root, not dist/). The backend runs `npm ci --ignore-scripts`,\n#    then the app's `build` script (or the framework default, `vite build` here).\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./territories\n# → { \"uuid\": \"<deployment-uuid>\", \"status\": \"...\", ... }\n\n# 5. Poll until the build is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n\n# 6. Promote to make it live at the app's `url`\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n\n# 7. Confirm what's live\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\n```\n\n## List and inspect\n\n```bash\ncargo-ai hosting app list                       # all apps in the workspace\ncargo-ai hosting app list --folder-uuid <uuid>  # only apps in one folder\ncargo-ai hosting app get <app-uuid>             # one app's details + live URL\n```\n\n## Local development env\n\n`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.\n\n```bash\n# Default API URL (https://api.getcargo.io)\ncargo-ai hosting app env <app-uuid> > ./my-app/.env.local\n\n# Point at a different API (e.g. a staging environment)\ncargo-ai hosting app env <app-uuid> --api-url https://api.staging.getcargo.io > ./my-app/.env.local\n```\n\n## A public, indexable site\n\n```bash\ncargo-ai hosting app init ./site --template public-site --name \"Example\"\n# edit the www.example.com canonicals, robots.txt and sitemap.xml to your real domain FIRST\ncargo-ai hosting app create --name \"Example\" --slug site\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./site   # runs the template's prerendering build script\n# poll, promote, then attach a custom domain (API) — the default host is noindex\n```\n\nThe template's `build` script prerenders each route to `<route>.html`. Link pages by those `.html` paths, because extension-less paths fall back to the SPA shell. See `SKILL.md` → Custom domains and search indexing for the domain attach and the checklist.\n\n## Rename, move, remove\n\n```bash\n# Rename\ncargo-ai hosting app update --uuid <app-uuid> --name \"Renamed App\"\n\n# Move into a folder (folders are managed by cargo-workspace-management)\ncargo-ai workspaceManagement folder list                          # find the folder UUID\ncargo-ai hosting app update --uuid <app-uuid> --folder-uuid <folder-uuid>\n\n# Move back to the workspace root (literal string \"null\")\ncargo-ai hosting app update --uuid <app-uuid> --folder-uuid null\n\n# Remove (also removes every deployment of this app)\ncargo-ai hosting app remove <app-uuid>\n```\n\n## Ship a new version of an existing app\n\nThe app slot and slug stay put; you just create and promote a fresh deployment.\n\n```bash\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app\n# poll deployment get <new-deployment-uuid> until terminal\ncargo-ai hosting deployment promote --uuid <new-deployment-uuid>\n```\n\nRoll 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.\n\nFile v1.1.1:references/examples/deployments.md\n\n# Deployment examples\n\nA deployment is one build+upload of a local source directory to an app or worker. Two facts drive everything below:\n\n1. A deployment belongs to **exactly one** app or worker — `--app-uuid` and `--worker-uuid` are mutually exclusive.\n2. **Building is not promoting.** `deployment create` builds; the live URL only moves when you `deployment promote`.\n\n## Create a deployment\n\n```bash\n# App: backend runs `npm ci --ignore-scripts` then the app's `build` script (or the framework default) in a sandbox\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app\n\n# Worker: backend bundles the entrypoint\ncargo-ai hosting deployment create --worker-uuid <worker-uuid> --source ./my-worker\n```\n\n- `--source` is the **package root** (where `package.json` lives), not a pre-built `dist/`. The build happens server-side.\n- Default ignore list: `node_modules,dist,build,.git,.next`. Override the whole list with `--ignore`:\n\n```bash\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app \\\n  --ignore \"node_modules,dist,build,.git,.next,coverage,.turbo\"\n```\n\n## Poll the build, then promote\n\n```bash\n# Builds are async — poll until the status field is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n# when terminal (built/succeeded), promote:\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n```\n\nIf 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.\n\n## List deployment history\n\n```bash\ncargo-ai hosting deployment list --app-uuid <app-uuid>       # newest first\ncargo-ai hosting deployment list --worker-uuid <worker-uuid>\n```\n\n## See what's currently live\n\n```bash\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\ncargo-ai hosting deployment get-promoted --worker-uuid <worker-uuid>\n```\n\n## Roll back to a previous deployment\n\nPromotion just points the live URL at a deployment, so rolling back is promoting an older one — no rebuild needed.\n\n```bash\n# 1. Find the deployment you want to go back to\ncargo-ai hosting deployment list --app-uuid <app-uuid>\n\n# 2. Promote it\ncargo-ai hosting deployment promote --uuid <older-deployment-uuid>\n\n# 3. Verify\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\n```\n\nFile v1.1.1:references/examples/workers.md\n\n# Worker examples\n\nWorkers 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`.\n\n## Scaffold → create → deploy → promote (end to end)\n\n```bash\n# 1. Scaffold a local worker project\ncargo-ai hosting worker init ./my-api --list-templates\ncargo-ai hosting worker init ./my-api --template blank --name \"My API\"\n\n# 2. Create the workspace slot. --slug is unique per workspace; the host adds a workspace suffix.\ncargo-ai hosting worker create --name \"My API\" --slug my-api\n# → { \"uuid\": \"<worker-uuid>\", \"slug\": \"my-api\", \"url\": \"https://my-api-1a2b3c4d.worker.getcargo.run\", ... }\n\n# 2b. (only if the worker calls the Cargo API) give it a token — see \"Env vars and the API token\" below\n\n# 3. Build & upload (source = package root). The backend bundles the entrypoint.\ncargo-ai hosting deployment create --worker-uuid <worker-uuid> --source ./my-api\n# → { \"uuid\": \"<deployment-uuid>\", \"status\": \"...\", ... }\n\n# 4. Poll until the build is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n\n# 5. Promote to go live\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n\n# 6. Confirm what's live, then hit it\ncargo-ai hosting deployment get-promoted --worker-uuid <worker-uuid>\ncurl \"$(cargo-ai hosting worker get <worker-uuid> | jq -r .url)/openapi.json\"\n```\n\n## List and inspect\n\n```bash\ncargo-ai hosting worker list                       # all workers\ncargo-ai hosting worker list --folder-uuid <uuid>  # only workers in one folder\ncargo-ai hosting worker get <worker-uuid>          # one worker's details + URL\n```\n\n## Templates\n\n```bash\ncargo-ai hosting worker init ./tmp --list-templates\n```\n\n- **`blank`** — edge worker on `@cargo-ai/worker-sdk` with automatic OpenAPI 3.1 spec at `/openapi.json` and Swagger UI at `/docs`.\n- **`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.\n\n## Rename, move, remove\n\n```bash\ncargo-ai hosting worker update --uuid <worker-uuid> --name \"Renamed Worker\"\ncargo-ai hosting worker update --uuid <worker-uuid> --folder-uuid <folder-uuid>\ncargo-ai hosting worker update --uuid <worker-uuid> --folder-uuid null   # back to root\ncargo-ai hosting worker remove <worker-uuid>                            # also removes its deployments\n```\n\n## Env vars and the API token\n\n`createCargoApi(c.env)` needs a `CARGO_API_TOKEN`, and Cargo does not inject one. Mint a token, then store it as a **secret** env var **before** deploying:\n\n```bash\ncargo-ai workspaceManagement token create --name \"worker: my-api\"      # value shown once\nexport CARGO_API_TOKEN=<token value>\n\n# Option A — workspace-wide: every worker (and app) in the workspace inherits it\ncargo-ai workspaceManagement envVar create --key CARGO_API_TOKEN --secret\n\n# Option B — this worker only (overrides a workspace entry of the same key)\ncurl -X POST \"https://api.getcargo.io/v1/hosting/env-vars\" \\\n  -H \"Authorization: Bearer $CARGO_API_TOKEN\" -H \"content-type: application/json\" \\\n  -d \"{\\\"kind\\\":\\\"worker\\\",\\\"workerUuid\\\":\\\"<worker-uuid>\\\",\\\"key\\\":\\\"CARGO_API_TOKEN\\\",\\\"value\\\":\\\"$CARGO_API_TOKEN\\\",\\\"isSecret\\\":true}\"\ncurl \"https://api.getcargo.io/v1/hosting/env-vars?workerUuid=<worker-uuid>\" -H \"Authorization: Bearer $CARGO_API_TOKEN\"\n```\n\nIn a CDK project, Option B is `defineWorker(\"my-api\", { path, env: { CARGO_API_TOKEN: secret(\"CARGO_API_TOKEN\") } })`.\n\nThen deploy and promote. Env vars are bound when a deployment is promoted, so **a variable added after the live deploy does nothing until the next `deployment create` + `promote`.**\n\nThe platform already binds `CARGO_API_URL`, `CARGO_WORKSPACE_UUID` and `CARGO_WORKER_UUID`. Don't set them yourself.\n\n## Develop locally\n\n```bash\ncd ./my-api\nnpm install\nexport CARGO_API_TOKEN=<token value>     # c.env is empty locally; createCargoApi falls back to process.env\nnpm run dev                              # → http://localhost:8787  (docs: /docs, spec: /openapi.json)\n```\n\n`dev.ts` serves the same `src/index.ts` under Node with hot reload and is never deployed. Outbound allowlists and cron triggers only apply once deployed.\n\n## Calling a worker from an app\n\nAn app and a worker live on different root domains (`*.app.getcargo.run` vs `*.worker.getcargo.run`), so the browser treats every call as **cross-origin**. Two pieces are needed.\n\n**1. The worker answers CORS for the app's origin.** `hono` is already installed as a dependency of `@cargo-ai/worker-sdk`:\n\n```ts\nimport { createWorker } from \"@cargo-ai/worker-sdk\";\nimport { cors } from \"hono/cors\";\n\nconst { app, openapi } = createWorker({ title: \"my-api\" });\n\napp.use(\n  \"/api/*\",\n  cors({\n    origin: [\"https://my-app-1a2b3c4d.app.getcargo.run\", \"http://localhost:5173\"],\n    allowHeaders: [\"content-type\", \"authorization\"],\n    allowMethods: [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"OPTIONS\"],\n  }),\n);\n```\n\nRegister it **before** the routes it covers so preflight `OPTIONS` requests are answered. List exact origins, taking the app's from `hosting app get <app-uuid>` → `url`, rather than `*` when the worker holds a workspace token.\n\n**2. The app gets the worker URL from an env var, not a hardcoded global.** An app's build receives every env var with a **public prefix** (`VITE_` for a Vite app; `NEXT_PUBLIC_`, `PUBLIC_` and the others work too), whether workspace-level or app-level (`POST /v1/hosting/env-vars` with `\"kind\":\"app\"`):\n\n```bash\ncargo-ai workspaceManagement envVar create --key VITE_MY_API_URL \\\n  --value \"$(cargo-ai hosting worker get <worker-uuid> | jq -r .url)\"\n```\n\n```ts\nconst res = await fetch(`${import.meta.env.VITE_MY_API_URL}/api/data`);\n```\n\nRedeploy the app after setting it, because the value is baked into the build. App env vars can't be secret. The API rejects `isSecret` for apps, and secret workspace entries never reach an app build, because the bundle is public. That is exactly why the token stays in the worker.\n\n## Logging errors\n\n`createWorker()` ships each request's `console.*` output to the worker's logs, and an uncaught exception is logged with its stack. A route that **catches** and sanitizes must log first:\n\n```ts\nopenapi.get(\"/api/data\", GetData);   // …inside GetData.handle:\ntry {\n  return c.json(await fetchData(createCargoApi(c.env)));\n} catch (err) {\n  console.error(err);                                        // → logs, with stack\n  return c.json({ error: \"The data provider is unavailable.\" }, 502);\n}\n```\n\nRead them in the web app, or `POST /v1/hosting/logs/list` with `{\"workerUuid\":\"<uuid>\",\"levels\":[\"error\"]}`.\n\n## App vs worker — when to use which\n\n- **App** — you want a UI (dashboard, internal tool, data grid). Vite SPA, `app init`, `app env` prints `.env.local` for local dev.\n- **Worker** — you want an HTTP endpoint with no UI (webhook receiver, API, custom integration backend). Edge `fetch` handler, `worker init`, `npm run dev` for local dev, runtime config from `c.env`.\n- **Both** — a UI that needs server-side secrets. Keep the token in the worker, call it from the app, and configure CORS as above.\n\nFile v1.1.1:references/response-shapes.md\n\n# Hosting response shapes\n\nJSON response structures for the `hosting` domain. All commands output JSON to stdout; failures exit non-zero with `{\"errorMessage\": \"...\"}`.\n\n## App (`hosting app get` / items in `hosting app list`)\n\n```json\n{\n  \"uuid\": \"app-uuid\",\n  \"workspaceUuid\": \"...\",\n  \"name\": \"My App\",\n  \"description\": null,\n  \"slug\": \"my-app\",\n  \"url\": \"https://my-app-1a2b3c4d.app.getcargo.run\",\n  \"userUuid\": \"...\",\n  \"folderUuid\": null,\n  \"promotedDeployment\": null,\n  \"chargedUntil\": \"2026-02-01T00:00:00Z\",\n  \"createdAt\": \"2026-01-01T00:00:00Z\",\n  \"updatedAt\": \"2026-01-15T00:00:00Z\",\n  \"deletedAt\": null\n}\n```\n\n**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)).\n\n## Worker (`hosting worker get` / items in `hosting worker list`)\n\nIdentical 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.\n\n## Deployment (`hosting deployment get` / items in `hosting deployment list`)\n\nA deployment is a discriminated union on `kind` (`\"app\"` | `\"worker\"`). Shared fields:\n\n```json\n{\n  \"uuid\": \"deployment-uuid\",\n  \"kind\": \"app\",\n  \"appUuid\": \"app-uuid\",\n  \"workspaceUuid\": \"...\",\n  \"status\": \"success\",\n  \"url\": \"https://deployment-deployment-uuid.app.getcargo.run\",\n  \"sourceS3Path\": \"...\",\n  \"bundleS3Path\": \"...\",\n  \"buildLogS3Filename\": \"...\",\n  \"errorMessage\": null,\n  \"meta\": {},\n  \"userUuid\": \"...\",\n  \"promotedAt\": \"2026-01-01T00:01:30Z\",\n  \"promotedByUserUuid\": \"...\",\n  \"finishedAt\": \"2026-01-01T00:01:10Z\",\n  \"temporalWorkflowId\": \"...\",\n  \"createdAt\": \"2026-01-01T00:00:00Z\",\n  \"updatedAt\": \"2026-01-01T00:01:30Z\"\n}\n```\n\n- **`kind: \"app\"`** carries `appUuid` and an empty `meta` (`{}`).\n- **`kind: \"worker\"`** carries `workerUuid` instead of `appUuid`, and `meta: { \"bundleSha256\": \"...\", \"outboundAllowlist\": [\"...\"] }`.\n\n**Key fields:**\n\n- `uuid` — pass to `deployment promote --uuid`.\n- `url` — this deployment's own preview host (`deployment-<uuid>.<root>`), reachable before promotion. The live URL is the app's/worker's `url`.\n- `appUuid` / `workerUuid` — exactly one is set, matching `kind`.\n- **`status`** — one of `\"pending\"`, `\"building\"`, `\"success\"`, `\"error\"`, `\"cancelled\"`. **Terminal** at `success` / `error` / `cancelled`; only a `success` deployment is worth promoting.\n- `errorMessage` — populated when `status` is `error`; `buildLogS3Filename` points at the build log for diagnosing a failed build.\n- `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).\n- `finishedAt` — when the build reached a terminal state.\n\n## get-promoted (`hosting deployment get-promoted`)\n\nReturns 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.\n\n## env (`hosting app env`)\n\nNot 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`.\n\n## init templates (`hosting app init <dir> --list-templates`)\n\n```json\n[\n  { \"slug\": \"blank\", \"description\": \"...\" },\n  { \"slug\": \"territories-overview\", \"description\": \"...\" }\n]\n```\n\nWorkers list their own templates (`blank`, `custom-integration`) via `hosting worker init <dir> --list-templates`. Note `--list-templates` still requires the `<directory>` positional argument.\n\nFile v1.1.1:references/troubleshooting.md\n\n# Hosting troubleshooting\n\nCommon errors in the `hosting` domain and how to fix them.\n\n## `unknown command 'hosting'`\n\nThe `hosting` domain shipped in a recent CLI. If `cargo-ai hosting --help` errors, bump the CLI: `npm install -g @cargo-ai/cli@latest`.\n\n## Slug already taken / `create` fails with `duplicateSlug`\n\nThe `--slug` must be unique **within your workspace**. The live host adds a workspace suffix (`<slug>-<workspace prefix>.<root>`), so another workspace using the same slug is never the cause. Remove or rename the existing app/worker with that slug, or pick another.\n\n## I deployed but the URL still shows the old version\n\n`deployment create` only builds and uploads — it does **not** change the live URL. Promote the new deployment:\n\n```bash\ncargo-ai hosting deployment get <deployment-uuid>      # confirm the build is terminal/succeeded\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>   # verify what's live\n```\n\n## `deployment create` build fails\n\nThe build runs server-side in a sandbox (`npm ci --ignore-scripts` then the app's `build` script, or the framework default, for apps; entrypoint bundling for workers). A failed build usually means:\n\n- **The app's own `build` script failed.** If `package.json` declares one, Cargo runs it verbatim, including any `tsc` pass, `--mode`, or `prebuild`/`postbuild` hook. Run `npm run build` locally first.\n- **No `index.html` in the output directory.** Output must land in the detected framework's directory (`dist` for Vite/Astro/undetected, `out` for Next.js, `build` for SvelteKit/CRA, `public` for Gatsby, `.output/public` for Nuxt).\n\n- **`--source` points at the wrong directory.** Pass the **package root** (where `package.json` lives), not a pre-built `dist/`.\n- **`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.\n- **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.\n\n- **Worker entrypoint not found** (`Expected one of: src/index.ts, src/index.js, index.ts, index.js.`). The worker build only looks for those four names. Rename a `.mjs`/`.mts`/`.cjs` entrypoint (and the files it imports, if they use those extensions) to `.js`/`.ts`. ES module syntax is fine in `.js` with `\"type\": \"module\"` in `package.json`.\n\nWhen `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`.\n\n## `--app-uuid` and `--worker-uuid` both passed (or neither)\n\nOn `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.\n\n## `folderNotFound` on `--folder-uuid`\n\nThe 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`.\n\n## `app env` writes the wrong API URL\n\nBy 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` command. Run them locally with `npm run dev` and export what they need (see below).\n\n## Worker throws `Missing CARGO_API_TOKEN`\n\n`createCargoApi(c.env)` needs a workspace API token, and Cargo does **not** inject one (it only binds `CARGO_API_URL`, `CARGO_WORKSPACE_UUID`, `CARGO_WORKER_UUID`). Create one and store it as a secret, then **deploy and promote again**:\n\n```bash\ncargo-ai workspaceManagement token create --name \"worker: <slug>\"\nexport CARGO_API_TOKEN=<token value>\ncargo-ai workspaceManagement envVar create --key CARGO_API_TOKEN --secret   # every worker inherits it\n```\n\nTo scope it to one worker, see `SKILL.md` → \"Worker env vars and secrets\". Locally, `export CARGO_API_TOKEN=…` before `npm run dev`.\n\n## I set an env var but the worker doesn't see it\n\nEnv vars are bound when a deployment is **promoted**, and non-secret values are also compiled into the bundle. The running deployment keeps the values it was promoted with. Run `deployment create` + `promote` again. To check which keys exist, list them: `workspaceManagement envVar list`, or `GET /v1/hosting/env-vars?workerUuid=<uuid>` for worker-level entries.\n\nDon't debug this by shipping an endpoint that echoes `Object.keys(c.env)`. The listing above answers the same question without a deploy.\n\n## Worker returns 502/500 but the logs show no cause\n\n`createWorker()` logs an **uncaught** exception with its stack. If your route catches the error and returns a sanitized message, only the HTTP line reaches the logs. Add `console.error(err)` in the `catch` before returning, then redeploy. Everything a request writes through `console.*` is captured (the first 50 lines per request). Read logs in the web app or via `POST /v1/hosting/logs/list` with `{\"workerUuid\":\"<uuid>\",\"levels\":[\"error\"]}`.\n\n## Browser blocks the app's calls to the worker (CORS)\n\nApps and workers are served from different root domains, so every app → worker call is cross-origin and preflighted. Add `hono/cors` middleware on the worker for the app's exact origin (from `hosting app get` → `url`) plus your local dev origin, registered before the routes. Pass the worker URL to the app as a public-prefixed env var (`VITE_…` for a Vite app), not a hardcoded global. Full snippet: [`examples/workers.md`](examples/workers.md#calling-a-worker-from-an-app).\n\n## Build went green but my prerender step didn't run\n\nIf Cargo can't use the declared `build` script (unparseable `package.json`, empty script, non-string entry), it falls back to the framework default without failing. The build log names the reason: `No usable \\`build\\` script (…); running … instead`.\n\n## `secretNotSupportedForApp` / CDK \"must be a plain string\"\n\nApp env vars are compiled into a public bundle, so they cannot be secret. Move the credential to a worker, and have the app call that worker.\n\n## `App environment variables must start with a recognized prefix`\n\nApp keys need a public prefix: `VITE_`, `NEXT_PUBLIC_`, `PUBLIC_`, `NUXT_PUBLIC_`, `GATSBY_` or `REACT_APP_`.\n\n## My public app isn't showing up in search\n\nThe default host and every deployment preview send `X-Robots-Tag: noindex`, so attach a custom domain (`POST /v1/hosting/custom-domains`, then `refresh-status` until `active`). Serve prerendered HTML at `.html` paths and submit the sitemap. Apps on `CargoRefineApp` require a login and can't be indexed at all. Full checklist: `SKILL.md` → Custom domains and search indexing.\n\n## Removing an app/worker took its deployments too\n\nThat'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.\n\n## Still stuck\n\nFile a report so the Cargo team can improve the CLI and these docs:\n\n```bash\ncargo-ai workspaceManagement report create \\\n  --title \"<one-line summary>\" \\\n  --description \"<exact command(s), errorMessage, expected vs actual, UUIDs involved>\"\n```\n\nFile v1.1.1:skill-card.md\n\n## Description:\n\nGuides developers through creating and deploying Cargo-hosted web apps and edge workers, including configuration, secrets, custom domains, and promotion to production.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[cargo-ai](https://clawhub.ai/user/cargo-ai)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers use this skill to scaffold, deploy, and manage public web apps and HTTP workers in a Cargo workspace, including their deployments and environment settings.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Creating or promoting a deployment can make an app or worker publicly accessible.\n\nMitigation: Confirm the workspace, resource UUID, source directory, and intended visibility before creating or promoting a deployment.\n\nRisk: API tokens or environment values may be exposed by overly broad access or public app bundles.\n\nMitigation: Use worker-scoped or least-privilege tokens when possible, store credentials as worker secrets, and keep tokens and .env.local files out of version control.\n\nRisk: Hosted resources consume recurring credits, and removing a resource also removes its deployments.\n\nMitigation: Confirm cost and deletion impact before creating or removing resources; remove resources no longer needed.\n\n## Reference(s):\n\n- [Cargo Hosting skill release](https://clawhub.ai/cargo-ai/skills/cargo-hosting)\n- [Cargo skills homepage](https://github.com/getcargohq/cargo-skills)\n- [Hosting troubleshooting](artifact/references/troubleshooting.md)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, Code, Configuration]\n\n**Output Format:** [Markdown with CLI commands and code examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Includes deployment steps and JSON response examples.]\n\n## Skill Version(s):\n\n1.1.1 (source: skill frontmatter and ClawHub release)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.1.1:skill-metadata.json\n\n{\n  \"$comment\": \"Generated by .github/scripts/skills-metadata.mjs — do not hand-edit. Regenerate with: node .github/scripts/skills-metadata.mjs --write .\",\n  \"name\": \"cargo-hosting\",\n  \"version\": \"1.1.1\",\n  \"documents\": [\n    {\n      \"path\": \"SKILL.md\",\n      \"kind\": \"entrypoint\",\n      \"title\": \"Cargo CLI — Hosting\"\n    },\n    {\n      \"path\": \"references/examples/apps.md\",\n      \"kind\": \"example\",\n      \"title\": \"App examples\"\n    },\n    {\n      \"path\": \"references/examples/deployments.md\",\n      \"kind\": \"example\",\n      \"title\": \"Deployment examples\"\n    },\n    {\n      \"path\": \"references/examples/workers.md\",\n      \"kind\": \"example\",\n      \"title\": \"Worker examples\"\n    },\n    {\n      \"path\": \"references/response-shapes.md\",\n      \"kind\": \"reference\",\n      \"title\": \"Hosting response shapes\"\n    },\n    {\n      \"path\": \"references/troubleshooting.md\",\n      \"kind\": \"reference\",\n      \"title\": \"Hosting troubleshooting\"\n    }\n  ],\n  \"contentHash\": \"431a5cca2fe4dfb2a29fbb36b9274fc63e4884c059dd0a1582939e6e1e657f31\"\n}\n\nArchive v1.1.0: 9 files, 22360 bytes\n\nFiles: references/examples/apps.md (4236b), references/examples/deployments.md (2336b), references/examples/workers.md (7321b), references/response-shapes.md (4082b), references/troubleshooting.md (7549b), skill-card.md (2563b), skill-metadata.json (1035b), SKILL.md (21554b), _meta.json (132b)\n\nFile v1.1.0:SKILL.md\n\n---\nname: cargo-hosting\ndescription: \"Put something on the internet from Cargo — hosted web apps (Vite by default, other static frameworks detected) and serverless edge workers that answer HTTP requests, plus the deployments that build and promote them, the env vars and secrets a worker reads, running a worker locally, and custom domains and search indexing for public sites. 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\\\", \\\"ship a UI for my team\\\", \\\"give my worker an API token\\\", \\\"set a secret on the worker\\\", \\\"Missing CARGO_API_TOKEN\\\", \\\"my app cannot call my worker\\\", \\\"run the worker locally\\\", \\\"put it on my own domain\\\", \\\"make the site indexable by Google\\\". Skip when: the app or worker should be declared as committed workspace code — use cargo-project.\"\nversion: \"1.1.0\"\ncompatibility: 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\nhomepage: https://github.com/getcargohq/cargo-skills\nmetadata:\n  author: getcargo\n  openclaw:\n    requires:\n      bins:\n        - cargo-ai\n    install:\n      - kind: node\n        package: \"@cargo-ai/cli@latest\"\n        bins:\n          - cargo-ai\n    homepage: https://github.com/getcargohq/cargo-skills\n---\n\n# Cargo CLI — Hosting\n\n**Cargo Hosting** runs two kinds of workspace-scoped resources, plus the deployments that ship them:\n\n- **App** — a static front end (a Vite single-page app by default; Next.js static export, Astro, SvelteKit, Nuxt, Gatsby and Create React App are detected too) served on its own subdomain (see [URLs](#urls)). The templates are built on `@cargo-ai/app-sdk` (Vite + refine + shadcn primitives, with `getCargoEnv()` / `useCargoApi()` wired to the workspace).\n- **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`).\n- **Deployment** — one build+upload of a local source directory to an app or worker. A deployment is **not live until it's promoted**.\n\n> 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.\n\n> See `references/examples/apps.md`, `references/examples/workers.md`, and `references/examples/deployments.md` for end-to-end walkthroughs.\n> See `references/response-shapes.md` for JSON response structures.\n> See `references/troubleshooting.md` for common errors and how to fix them.\n\n## Bootstrap\n\nAlready signed in (`cargo-ai whoami` returns a workspace)? Skip to the next section.\n\n```bash\nnpm install -g @cargo-ai/cli            # no global install? prefix every command with `npx @cargo-ai/cli`\ncargo-ai login --email you@company.com  # emailed code, no browser; creates the account on first use\n                                        # alternatives: --oauth (browser) · --token <api-token> (CI)\ncargo-ai whoami                         # confirm the active workspace before any write\n```\n\nEvery 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.\n\n## The lifecycle\n\nApps and workers follow the same shape — **scaffold → create slot → deploy → promote**:\n\n```\ninit (local scaffold) → create (slot + slug) → deployment create (build+upload) → deployment promote (go live)\n```\n\n1. **Scaffold** a local project from a template — `hosting app init <dir>` / `hosting worker init <dir>`.\n2. **Create the slot** in the workspace — `hosting app create --name --slug` → `appUuid` (or `workerUuid`). The `--slug` becomes part of the subdomain and must be unique within the workspace.\n3. **(optional) Wire local dev** — for an app, `hosting app env <appUuid>` prints the `.env.local` lines a local copy needs (Cargo OAuth + workspace + app UUID + API URL). For a worker, `npm run dev` in the scaffold (see [Run a worker locally](#run-a-worker-locally)). A worker that calls the Cargo API also needs a `CARGO_API_TOKEN` secret before its first deploy (see [Worker env vars and secrets](#worker-env-vars-and-secrets)).\n4. **Deploy** — `hosting deployment create --app-uuid <uuid> --source <dir>` uploads the source. The backend then builds it in a sandbox: for an app, `npm ci --ignore-scripts` followed by the app's own `build` script, or the framework's default build if there is none (see [App builds](#app-builds)); for a worker, it bundles the entrypoint. Returns a `deploymentUuid`.\n5. **Promote** — `hosting deployment promote --uuid <deploymentUuid>` points the live URL at that build.\n\nDeploys build asynchronously — **poll `hosting deployment get <uuid>`** until the status is terminal before promoting (see [Async polling](#async-polling)).\n\n## URLs\n\nThe live host is **`<slug>-<first 8 chars of the workspace UUID>`** under the hosting root domain, and apps and workers have **different root domains** — in production `https://<slug>-<ws>.app.getcargo.run` for an app, `https://<slug>-<ws>.worker.getcargo.run` for a worker. The workspace suffix is what makes the host globally unique, which is why a slug only has to be unique inside your workspace.\n\nDon't build the URL by hand. Read `url` from `create` or `get` — the root domain differs per environment. Each deployment also gets a preview host, `https://deployment-<deploymentUuid>.<root>`, before it is promoted.\n\nBecause the roots differ, **an app calling a worker is always a cross-origin request.** No option serves them on the same origin, so the worker has to answer CORS. See the app + worker pattern in [`references/examples/workers.md`](references/examples/workers.md#calling-a-worker-from-an-app).\n\n## Apps\n\n```bash\n# Discover\ncargo-ai hosting app list                          # all apps (filter with --folder-uuid <uuid>)\ncargo-ai hosting app get <uuid>                     # one app's details + URL\n\n# Scaffold locally (Vite + @cargo-ai/app-sdk)\ncargo-ai hosting app init ./my-app --list-templates # see available templates, then:\ncargo-ai hosting app init ./my-app --template blank --name \"My App\"\n\n# Create the slot (slug unique per workspace; `url` in the response is the live host)\ncargo-ai hosting app create --name \"My App\" --slug my-app --folder-uuid <folder-uuid>\n\n# Print .env.local for local development\ncargo-ai hosting app env <app-uuid>\ncargo-ai hosting app env <app-uuid> --api-url https://api.getcargo.io\n\n# Update / remove\ncargo-ai hosting app update --uuid <app-uuid> --name \"Renamed\"\ncargo-ai hosting app update --uuid <app-uuid> --folder-uuid null   # move to workspace root\ncargo-ai hosting app remove <app-uuid>                             # also removes its deployments\n```\n\nTemplates: `blank` (minimal starting point), `territories-overview` (read-only territories grid demoing `useCargoApi()` + react-query), and `public-site` (a public, indexable site that prerenders every route from its own build script and ships `robots.txt` + `sitemap.xml`). Run `app init <dir> --list-templates` for the current list.\n\n### App builds\n\n**If `package.json` declares a `build` script, Cargo runs it, and that script owns the whole build.** Cargo runs nothing before or after it, so the script must produce the client bundle as well as anything extra, such as prerendered HTML. Without a `build` script, the detected framework's default command runs:\n\n| Framework (detected from dependencies) | Default build | Output dir | Public env prefix |\n|---|---|---|---|\n| Vite, and anything undetected | `vite build` | `dist` | `VITE_` |\n| Next.js (static export) | `next build` | `out` | `NEXT_PUBLIC_` |\n| Astro | `astro build` | `dist` | `PUBLIC_` |\n| SvelteKit | `svelte-kit build` | `build` | `PUBLIC_` |\n| Nuxt | `nuxt generate` | `.output/public` | `NUXT_PUBLIC_` |\n| Gatsby | `gatsby build` | `public` | `GATSBY_` |\n| Create React App | `react-scripts build` | `build` | `REACT_APP_` |\n\n- **Output must land in that framework's output directory and contain an `index.html`**, or the build fails. Unknown paths fall back to that shell.\n- **Whatever the build script does now runs on every deploy.** That includes a `tsc` pass, a different `--mode`, and `prebuild`/`postbuild` hooks. A script that fails there fails the deploy. The live deployment keeps serving, because promotion only follows a successful build.\n- **A `build` script Cargo can't use falls back silently.** That covers an unparseable `package.json`, an empty script, or a non-string entry. The deploy still goes green, and only the build log says why, so check it when a prerender step seems to have been skipped.\n- **Platform values are injected under every public prefix.** A Vite app reads `VITE_CARGO_API_URL` and a Next.js app reads `NEXT_PUBLIC_CARGO_API_URL`. When a `build` script is used, they are also passed as real process env vars, so a plain-Node prerender step sees them. User env values are redacted from build logs.\n\n### App env vars are public\n\nAn app reads only env vars whose key starts with a **public prefix**: `VITE_`, `NEXT_PUBLIC_`, `PUBLIC_`, `NUXT_PUBLIC_`, `GATSBY_` or `REACT_APP_`. Any of these prefixes works whatever the framework. They come from workspace env vars and from app-level entries (`POST /v1/hosting/env-vars` with `\"kind\":\"app\"`, or CDK `defineApp({ env })`). Every one of them is compiled into a bundle anyone can download. For that reason:\n\n- **App env vars cannot be secret.** The API rejects `isSecret: true` with `secretNotSupportedForApp`, CDK `defineApp` throws on a `secret()` value, and secret workspace entries never reach an app build. Credentials belong in a worker that the app calls.\n- Keys matching a platform key under any prefix (`*_CARGO_API_URL`, `*_CARGO_WORKSPACE_UUID`, `*_APP_BASE_PATH`, …) are reserved.\n- Values are baked in at build time, so a change needs a new deploy + promote.\n\n### Custom domains and search indexing\n\n**Cargo-owned hosts are `noindex`.** The default `*.app.getcargo.run` host and every `deployment-<uuid>` preview answer with `X-Robots-Tag: noindex`, so **an app only becomes indexable on a custom domain**. No CLI command attaches one at CLI 1.0.96, so use the API:\n\n```bash\ncurl -X POST https://api.getcargo.io/v1/hosting/custom-domains \\\n  -H \"authorization: Bearer $CARGO_API_TOKEN\" -H \"content-type: application/json\" \\\n  -d '{\"kind\":\"app\",\"appUuid\":\"<uuid>\",\"hostname\":\"www.example.com\"}'\n# → DNS records to add: certificate validation records + a cnameTarget for the hostname\ncurl -X POST https://api.getcargo.io/v1/hosting/custom-domains/<domain-uuid>/refresh-status \\\n  -H \"authorization: Bearer $CARGO_API_TOKEN\"                                   # repeat until status is \"active\"\n```\n\n- The hostname needs **at least three labels**, so attach `www.example.com`, not `example.com`.\n- Workers take custom domains too (`\"kind\":\"worker\",\"workerUuid\":…`). Separate hostnames are still separate origins, so app → worker CORS still applies.\n- **Indexing also needs real HTML per URL.** Prerender in the `build` script (the `public-site` template shows how). Link prerendered routes as `.html` paths: `/about.html` serves the prerendered file, while `/about` falls back to the SPA shell. Ship `public/robots.txt` + `public/sitemap.xml`, and put a title, description, canonical and Open Graph tags in each prerendered head.\n- **A hosted app never returns a 404.** An unknown path serves the SPA shell with a `200`, so a client-side not-found view should set `<meta name=\"robots\" content=\"noindex\">` itself.\n- **Apps built on `CargoRefineApp` require a Cargo login** and cannot be indexed. A public site renders its own tree.\n- Nothing is submitted to search engines for you. Submit the sitemap in Search Console.\n\n## Workers\n\nSame command shape as apps — substitute `worker` for `app`:\n\n```bash\ncargo-ai hosting worker list                        # filter with --folder-uuid <uuid>\ncargo-ai hosting worker get <uuid>\n\n# Scaffold (edge fetch(request, env) handler on @cargo-ai/worker-sdk)\ncargo-ai hosting worker init ./my-worker --list-templates\ncargo-ai hosting worker init ./my-worker --template blank --name \"My Worker\"\n\ncargo-ai hosting worker create --name \"My Worker\" --slug my-worker --folder-uuid <folder-uuid>\ncargo-ai hosting worker update --uuid <worker-uuid> --name \"Renamed\"\ncargo-ai hosting worker remove <worker-uuid>        # also removes its deployments\n```\n\nTemplates: `blank` (auto OpenAPI spec + Swagger UI) and `custom-integration` (a Cargo Custom Integration — manifest / actions / extractors / autocompletes / dynamic schemas).\n\n**Entrypoint.** The build bundles the first of `src/index.ts`, `src/index.js`, `index.ts`, `index.js` that exists, and fails if there is none. `.mjs`, `.mts` and `.cjs` entrypoints are not picked up, so rename them to `.js`/`.ts`; ES module syntax works in `.js` because the scaffold's `package.json` sets `\"type\": \"module\"`.\n\n### Worker env vars and secrets\n\nA worker reads configuration from `c.env.KEY` (Hono context) or the `env` argument to `fetch(request, env)`. Three sources feed it:\n\n| Source | Set with | Reaches |\n|---|---|---|\n| **Platform bindings** | automatic | `CARGO_API_URL`, `CARGO_WORKSPACE_UUID`, `CARGO_WORKER_UUID` |\n| **Workspace env vars** | `cargo-ai workspaceManagement envVar create --key K [--secret]` | every worker in the workspace (apps get only the non-secret, public-prefixed ones) |\n| **Worker env vars** | `defineWorker({ env })` in CDK, or `POST /v1/hosting/env-vars` (no `hosting` CLI command at CLI 1.0.96) | that worker only, and a worker entry overrides a workspace entry with the same key |\n\n**`CARGO_API_TOKEN` is not injected.** `createCargoApi(c.env)` throws `Missing CARGO_API_TOKEN…` until you provide one. Mint a workspace API token and store it as a secret before the first deploy:\n\n```bash\ncargo-ai workspaceManagement token create --name \"worker: my-worker\"   # value shown ONCE\nexport CARGO_API_TOKEN=<token value>\ncargo-ai workspaceManagement envVar create --key CARGO_API_TOKEN --secret \\\n  --description \"Cargo API token for hosted workers\"                     # --value omitted → read from $CARGO_API_TOKEN\n```\n\nA workspace entry gives *every* worker that token. If only one worker should hold it, set it on that worker instead:\n\n- **CDK:** `defineWorker(\"my-worker\", { path, env: { CARGO_API_TOKEN: secret(\"CARGO_API_TOKEN\") } })`.\n- **API:** `POST /v1/hosting/env-vars` with `{\"kind\":\"worker\",\"workerUuid\":\"<uuid>\",\"key\":\"CARGO_API_TOKEN\",\"value\":\"…\",\"isSecret\":true}`. From TypeScript that is `api.hosting.envVars.create(…)` in `@cargo-ai/api`, and `list` takes `{ workerUuid }`.\n\n**Values are captured at deploy time, not read live.** Bindings are attached when a deployment is promoted, and non-secret values are also compiled into the bundle as `process.env.KEY`. After adding or changing a variable, **run `deployment create` and `promote` again**. The running worker keeps the old values until then.\n\n**Secrets never enter the bundle.** A secret binds as an encrypted runtime value. Only non-secret values are compiled in, and bundles can be downloaded from the per-deployment preview host, so anything sensitive must be `--secret` / `isSecret: true`.\n\n### Run a worker locally\n\nBoth templates ship a `dev.ts` harness: `npm run dev` serves `src/index.ts` under Node with hot reload on `http://localhost:8787` (override with `PORT`). `dev.ts` is never deployed.\n\n- **No platform bindings exist locally**, so `c.env` is empty. `createCargoApi` falls back to `process.env`, so export `CARGO_API_TOKEN` (and `CARGO_API_URL` for a non-production API) in the shell before `npm run dev`. Your own variables need the same fallback in your code.\n- **`manifest.json` `outboundAllowlist` and cron triggers are not enforced locally.** Test them on a deployment.\n\nA project scaffolded before `dev.ts` existed can copy it from a fresh `hosting worker init`, along with the `dev` script and the `@hono/node-server` + `tsx` dev dependencies.\n\n### Worker logs and errors\n\n`createWorker()` captures `console.log/info/warn/error/debug` during each request Cargo dispatches and ships them to the worker's logs (at most 50 lines per request). An **uncaught** error is logged with its stack and answered with a bare `500`.\n\n**A caught error leaves no trace.** If a route catches an exception and returns its own sanitized response, such as `502 \"The data provider is unavailable\"`, the log gets only the HTTP line. **Log the error before you sanitize it:**\n\n```ts\ntry {\n  return c.json(await loadData(createCargoApi(c.env)));\n} catch (err) {\n  console.error(err);                        // stack goes to the logs; the response stays clean\n  return c.json({ error: \"The data provider is unavailable.\" }, 502);\n}\n```\n\nAt CLI 1.0.96 the logs are readable in the web app or through the API: `POST /v1/hosting/logs/list` with `{\"workerUuid\":\"<uuid>\",\"levels\":[\"error\"],\"limit\":50}`, or `api.hosting.log.list(…)` from TypeScript. It also filters on `runUuid`, `search`, and `occurredAfter`/`occurredBefore`. The CLI has no logs command yet.\n\n## Deployments\n\nA deployment belongs to exactly one app **or** one worker (`--app-uuid` and `--worker-uuid` are mutually exclusive).\n\n```bash\n# List / inspect\ncargo-ai hosting deployment list --app-uuid <uuid>          # or --worker-uuid <uuid>\ncargo-ai hosting deployment get <deployment-uuid>           # status + metadata\ncargo-ai hosting deployment get-promoted --app-uuid <uuid>  # what's currently live\n\n# Build & upload a local source directory (point at the package root, NOT dist/)\ncargo-ai hosting deployment create --app-uuid <uuid> --source ./my-app\ncargo-ai hosting deployment create --worker-uuid <uuid> --source ./my-worker\n# default ignores: node_modules,dist,build,.git,.next — override with --ignore \"a,b,c\"\n\n# Go live\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n```\n\n## Critical rules\n\n- **`--slug` is unique per workspace**, and the live host is `<slug>-<workspace prefix>.<root>`, with a different root for apps and workers. Use the `url` from `get` rather than composing it (see [URLs](#urls)). A duplicate slug fails at `create` with `duplicateSlug`.\n- **An app calling a worker is cross-origin.** The worker must send CORS headers for the app's origin. No same-origin mount exists.\n- **`CARGO_API_TOKEN` is yours to provide.** It is never injected, and `createCargoApi` throws without it. Set it as a secret (workspace or worker env var) **before** the deploy that needs it.\n- **Env var changes need a new deploy + promote.** Values are bound at promote and non-secrets are compiled into the bundle, so editing a variable changes nothing until the next deployment is live.\n- **Log before you sanitize.** Only uncaught errors reach the logs with a stack. A `catch` that returns a friendly message must `console.error(err)` first, or the cause is gone.\n- **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.\n- **`--source` is the package root, not `dist/`.** The build runs in a Cargo sandbox: `npm ci --ignore-scripts` then the app's `build` script (or the framework default) for apps, entrypoint bundling for workers. Shipping a pre-built `dist/` will not work.\n- **App env vars are public and never secret.** They are compiled into the bundle, and `isSecret` is rejected. Put credentials in a worker.\n- **Cargo-owned hosts are `noindex`.** A public site needs a custom domain (API only at 1.0.96) and prerendered HTML to be indexed.\n- **Builds are async** — poll `deployment get` until terminal before promoting (see below).\n- **`--app-uuid` / `--worker-uuid` are mutually exclusive** on `deployment create`, `deployment list`, and `deployment get-promoted`. Pass exactly one.\n- **`remove` cascades** — removing an app or worker also removes all of its deployments.\n- **`update --folder-uuid null`** (literal string `null`) moves a resource back to the workspace root.\n- **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).\n\n## Async polling\n\n`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:\n\n```bash\ncargo-ai hosting deployment get <deployment-uuid>   # poll ~2–5s until status is terminal\n```\n\nTerminal 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).\n\n## Help\n\nEvery command supports `--help`:\n\n```bash\ncargo-ai hosting app create --help\ncargo-ai hosting deployment create --help\n```\n\nFile v1.1.0:_meta.json\n\n{\n  \"ownerId\": \"kn7by8t6yt9yghbxtxz6hv0bts87k6bq\",\n  \"slug\": \"cargo-hosting\",\n  \"version\": \"1.1.0\",\n  \"publishedAt\": 1790028239091\n}\n\nFile v1.1.0:references/examples/apps.md\n\n# App examples\n\nApps are static front ends (Vite single-page apps by default; other frameworks are detected, see `SKILL.md` → App builds) served on `https://<slug>-<workspace prefix>.app.getcargo.run` in production (read the exact host from `url`), scaffolded from `@cargo-ai/app-sdk`.\n\n## Scaffold → create → deploy → promote (end to end)\n\n```bash\n# 1. See what templates exist, then scaffold a local project\ncargo-ai hosting app init ./territories --list-templates\ncargo-ai hosting app init ./territories --template territories-overview --name \"Territories\"\n\n# 2. Create the workspace slot. --slug is unique per workspace; the host adds a workspace suffix.\ncargo-ai hosting app create --name \"Territories\" --slug territories\n# → { \"uuid\": \"<app-uuid>\", \"slug\": \"territories\", \"url\": \"https://territories-1a2b3c4d.app.getcargo.run\", ... }\n\n# 3. (optional) Develop locally — write the .env.local the app needs, then run Vite\ncargo-ai hosting app env <app-uuid> > ./territories/.env.local\ncd ./territories && npm install && npm run dev\n\n# 4. Build & upload (source = package root, not dist/). The backend runs `npm ci --ignore-scripts`,\n#    then the app's `build` script (or the framework default, `vite build` here).\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./territories\n# → { \"uuid\": \"<deployment-uuid>\", \"status\": \"...\", ... }\n\n# 5. Poll until the build is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n\n# 6. Promote to make it live at the app's `url`\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n\n# 7. Confirm what's live\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\n```\n\n## List and inspect\n\n```bash\ncargo-ai hosting app list                       # all apps in the workspace\ncargo-ai hosting app list --folder-uuid <uuid>  # only apps in one folder\ncargo-ai hosting app get <app-uuid>             # one app's details + live URL\n```\n\n## Local development env\n\n`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.\n\n```bash\n# Default API URL (https://api.getcargo.io)\ncargo-ai hosting app env <app-uuid> > ./my-app/.env.local\n\n# Point at a different API (e.g. a staging environment)\ncargo-ai hosting app env <app-uuid> --api-url https://api.staging.getcargo.io > ./my-app/.env.local\n```\n\n## A public, indexable site\n\n```bash\ncargo-ai hosting app init ./site --template public-site --name \"Example\"\n# edit the www.example.com canonicals, robots.txt and sitemap.xml to your real domain FIRST\ncargo-ai hosting app create --name \"Example\" --slug site\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./site   # runs the template's prerendering build script\n# poll, promote, then attach a custom domain (API) — the default host is noindex\n```\n\nThe template's `build` script prerenders each route to `<route>.html`. Link pages by those `.html` paths, because extension-less paths fall back to the SPA shell. See `SKILL.md` → Custom domains and search indexing for the domain attach and the checklist.\n\n## Rename, move, remove\n\n```bash\n# Rename\ncargo-ai hosting app update --uuid <app-uuid> --name \"Renamed App\"\n\n# Move into a folder (folders are managed by cargo-workspace-management)\ncargo-ai workspaceManagement folder list                          # find the folder UUID\ncargo-ai hosting app update --uuid <app-uuid> --folder-uuid <folder-uuid>\n\n# Move back to the workspace root (literal string \"null\")\ncargo-ai hosting app update --uuid <app-uuid> --folder-uuid null\n\n# Remove (also removes every deployment of this app)\ncargo-ai hosting app remove <app-uuid>\n```\n\n## Ship a new version of an existing app\n\nThe app slot and slug stay put; you just create and promote a fresh deployment.\n\n```bash\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app\n# poll deployment get <new-deployment-uuid> until terminal\ncargo-ai hosting deployment promote --uuid <new-deployment-uuid>\n```\n\nRoll 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.\n\nFile v1.1.0:references/examples/deployments.md\n\n# Deployment examples\n\nA deployment is one build+upload of a local source directory to an app or worker. Two facts drive everything below:\n\n1. A deployment belongs to **exactly one** app or worker — `--app-uuid` and `--worker-uuid` are mutually exclusive.\n2. **Building is not promoting.** `deployment create` builds; the live URL only moves when you `deployment promote`.\n\n## Create a deployment\n\n```bash\n# App: backend runs `npm ci --ignore-scripts` then the app's `build` script (or the framework default) in a sandbox\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app\n\n# Worker: backend bundles the entrypoint\ncargo-ai hosting deployment create --worker-uuid <worker-uuid> --source ./my-worker\n```\n\n- `--source` is the **package root** (where `package.json` lives), not a pre-built `dist/`. The build happens server-side.\n- Default ignore list: `node_modules,dist,build,.git,.next`. Override the whole list with `--ignore`:\n\n```bash\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app \\\n  --ignore \"node_modules,dist,build,.git,.next,coverage,.turbo\"\n```\n\n## Poll the build, then promote\n\n```bash\n# Builds are async — poll until the status field is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n# when terminal (built/succeeded), promote:\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n```\n\nIf 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.\n\n## List deployment history\n\n```bash\ncargo-ai hosting deployment list --app-uuid <app-uuid>       # newest first\ncargo-ai hosting deployment list --worker-uuid <worker-uuid>\n```\n\n## See what's currently live\n\n```bash\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\ncargo-ai hosting deployment get-promoted --worker-uuid <worker-uuid>\n```\n\n## Roll back to a previous deployment\n\nPromotion just points the live URL at a deployment, so rolling back is promoting an older one — no rebuild needed.\n\n```bash\n# 1. Find the deployment you want to go back to\ncargo-ai hosting deployment list --app-uuid <app-uuid>\n\n# 2. Promote it\ncargo-ai hosting deployment promote --uuid <older-deployment-uuid>\n\n# 3. Verify\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\n```\n\nFile v1.1.0:references/examples/workers.md\n\n# Worker examples\n\nWorkers 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`.\n\n## Scaffold → create → deploy → promote (end to end)\n\n```bash\n# 1. Scaffold a local worker project\ncargo-ai hosting worker init ./my-api --list-templates\ncargo-ai hosting worker init ./my-api --template blank --name \"My API\"\n\n# 2. Create the workspace slot. --slug is unique per workspace; the host adds a workspace suffix.\ncargo-ai hosting worker create --name \"My API\" --slug my-api\n# → { \"uuid\": \"<worker-uuid>\", \"slug\": \"my-api\", \"url\": \"https://my-api-1a2b3c4d.worker.getcargo.run\", ... }\n\n# 2b. (only if the worker calls the Cargo API) give it a token — see \"Env vars and the API token\" below\n\n# 3. Build & upload (source = package root). The backend bundles the entrypoint.\ncargo-ai hosting deployment create --worker-uuid <worker-uuid> --source ./my-api\n# → { \"uuid\": \"<deployment-uuid>\", \"status\": \"...\", ... }\n\n# 4. Poll until the build is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n\n# 5. Promote to go live\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n\n# 6. Confirm what's live, then hit it\ncargo-ai hosting deployment get-promoted --worker-uuid <worker-uuid>\ncurl \"$(cargo-ai hosting worker get <worker-uuid> | jq -r .url)/openapi.json\"\n```\n\n## List and inspect\n\n```bash\ncargo-ai hosting worker list                       # all workers\ncargo-ai hosting worker list --folder-uuid <uuid>  # only workers in one folder\ncargo-ai hosting worker get <worker-uuid>          # one worker's details + URL\n```\n\n## Templates\n\n```bash\ncargo-ai hosting worker init ./tmp --list-templates\n```\n\n- **`blank`** — edge worker on `@cargo-ai/worker-sdk` with automatic OpenAPI 3.1 spec at `/openapi.json` and Swagger UI at `/docs`.\n- **`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.\n\n## Rename, move, remove\n\n```bash\ncargo-ai hosting worker update --uuid <worker-uuid> --name \"Renamed Worker\"\ncargo-ai hosting worker update --uuid <worker-uuid> --folder-uuid <folder-uuid>\ncargo-ai hosting worker update --uuid <worker-uuid> --folder-uuid null   # back to root\ncargo-ai hosting worker remove <worker-uuid>                            # also removes its deployments\n```\n\n## Env vars and the API token\n\n`createCargoApi(c.env)` needs a `CARGO_API_TOKEN`, and Cargo does not inject one. Mint a token, then store it as a **secret** env var **before** deploying:\n\n```bash\ncargo-ai workspaceManagement token create --name \"worker: my-api\"      # value shown once\nexport CARGO_API_TOKEN=<token value>\n\n# Option A — workspace-wide: every worker (and app) in the workspace inherits it\ncargo-ai workspaceManagement envVar create --key CARGO_API_TOKEN --secret\n\n# Option B — this worker only (overrides a workspace entry of the same key)\ncurl -X POST \"https://api.getcargo.io/v1/hosting/env-vars\" \\\n  -H \"Authorization: Bearer $CARGO_API_TOKEN\" -H \"content-type: application/json\" \\\n  -d \"{\\\"kind\\\":\\\"worker\\\",\\\"workerUuid\\\":\\\"<worker-uuid>\\\",\\\"key\\\":\\\"CARGO_API_TOKEN\\\",\\\"value\\\":\\\"$CARGO_API_TOKEN\\\",\\\"isSecret\\\":true}\"\ncurl \"https://api.getcargo.io/v1/hosting/env-vars?workerUuid=<worker-uuid>\" -H \"Authorization: Bearer $CARGO_API_TOKEN\"\n```\n\nIn a CDK project, Option B is `defineWorker(\"my-api\", { path, env: { CARGO_API_TOKEN: secret(\"CARGO_API_TOKEN\") } })`.\n\nThen deploy and promote. Env vars are bound when a deployment is promoted, so **a variable added after the live deploy does nothing until the next `deployment create` + `promote`.**\n\nThe platform already binds `CARGO_API_URL`, `CARGO_WORKSPACE_UUID` and `CARGO_WORKER_UUID`. Don't set them yourself.\n\n## Develop locally\n\n```bash\ncd ./my-api\nnpm install\nexport CARGO_API_TOKEN=<token value>     # c.env is empty locally; createCargoApi falls back to process.env\nnpm run dev                              # → http://localhost:8787  (docs: /docs, spec: /openapi.json)\n```\n\n`dev.ts` serves the same `src/index.ts` under Node with hot reload and is never deployed. Outbound allowlists and cron triggers only apply once deployed.\n\n## Calling a worker from an app\n\nAn app and a worker live on different root domains (`*.app.getcargo.run` vs `*.worker.getcargo.run`), so the browser treats every call as **cross-origin**. Two pieces are needed.\n\n**1. The worker answers CORS for the app's origin.** `hono` is already installed as a dependency of `@cargo-ai/worker-sdk`:\n\n```ts\nimport { createWorker } from \"@cargo-ai/worker-sdk\";\nimport { cors } from \"hono/cors\";\n\nconst { app, openapi } = createWorker({ title: \"my-api\" });\n\napp.use(\n  \"/api/*\",\n  cors({\n    origin: [\"https://my-app-1a2b3c4d.app.getcargo.run\", \"http://localhost:5173\"],\n    allowHeaders: [\"content-type\", \"authorization\"],\n    allowMethods: [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"OPTIONS\"],\n  }),\n);\n```\n\nRegister it **before** the routes it covers so preflight `OPTIONS` requests are answered. List exact origins, taking the app's from `hosting app get <app-uuid>` → `url`, rather than `*` when the worker holds a workspace token.\n\n**2. The app gets the worker URL from an env var, not a hardcoded global.** An app's build receives every env var with a **public prefix** (`VITE_` for a Vite app; `NEXT_PUBLIC_`, `PUBLIC_` and the others work too), whether workspace-level or app-level (`POST /v1/hosting/env-vars` with `\"kind\":\"app\"`):\n\n```bash\ncargo-ai workspaceManagement envVar create --key VITE_MY_API_URL \\\n  --value \"$(cargo-ai hosting worker get <worker-uuid> | jq -r .url)\"\n```\n\n```ts\nconst res = await fetch(`${import.meta.env.VITE_MY_API_URL}/api/data`);\n```\n\nRedeploy the app after setting it, because the value is baked into the build. App env vars can't be secret. The API rejects `isSecret` for apps, and secret workspace entries never reach an app build, because the bundle is public. That is exactly why the token stays in the worker.\n\n## Logging errors\n\n`createWorker()` ships each request's `console.*` output to the worker's logs, and an uncaught exception is logged with its stack. A route that **catches** and sanitizes must log first:\n\n```ts\nopenapi.get(\"/api/data\", GetData);   // …inside GetData.handle:\ntry {\n  return c.json(await fetchData(createCargoApi(c.env)));\n} catch (err) {\n  console.error(err);                                        // → logs, with stack\n  return c.json({ error: \"The data provider is unavailable.\" }, 502);\n}\n```\n\nRead them in the web app, or `POST /v1/hosting/logs/list` with `{\"workerUuid\":\"<uuid>\",\"levels\":[\"error\"]}`.\n\n## App vs worker — when to use which\n\n- **App** — you want a UI (dashboard, internal tool, data grid). Vite SPA, `app init`, `app env` prints `.env.local` for local dev.\n- **Worker** — you want an HTTP endpoint with no UI (webhook receiver, API, custom integration backend). Edge `fetch` handler, `worker init`, `npm run dev` for local dev, runtime config from `c.env`.\n- **Both** — a UI that needs server-side secrets. Keep the token in the worker, call it from the app, and configure CORS as above.\n\nFile v1.1.0:references/response-shapes.md\n\n# Hosting response shapes\n\nJSON response structures for the `hosting` domain. All commands output JSON to stdout; failures exit non-zero with `{\"errorMessage\": \"...\"}`.\n\n## App (`hosting app get` / items in `hosting app list`)\n\n```json\n{\n  \"uuid\": \"app-uuid\",\n  \"workspaceUuid\": \"...\",\n  \"name\": \"My App\",\n  \"description\": null,\n  \"slug\": \"my-app\",\n  \"url\": \"https://my-app-1a2b3c4d.app.getcargo.run\",\n  \"userUuid\": \"...\",\n  \"folderUuid\": null,\n  \"promotedDeployment\": null,\n  \"chargedUntil\": \"2026-02-01T00:00:00Z\",\n  \"createdAt\": \"2026-01-01T00:00:00Z\",\n  \"updatedAt\": \"2026-01-15T00:00:00Z\",\n  \"deletedAt\": null\n}\n```\n\n**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)).\n\n## Worker (`hosting worker get` / items in `hosting worker list`)\n\nIdentical 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.\n\n## Deployment (`hosting deployment get` / items in `hosting deployment list`)\n\nA deployment is a discriminated union on `kind` (`\"app\"` | `\"worker\"`). Shared fields:\n\n```json\n{\n  \"uuid\": \"deployment-uuid\",\n  \"kind\": \"app\",\n  \"appUuid\": \"app-uuid\",\n  \"workspaceUuid\": \"...\",\n  \"status\": \"success\",\n  \"url\": \"https://deployment-deployment-uuid.app.getcargo.run\",\n  \"sourceS3Path\": \"...\",\n  \"bundleS3Path\": \"...\",\n  \"buildLogS3Filename\": \"...\",\n  \"errorMessage\": null,\n  \"meta\": {},\n  \"userUuid\": \"...\",\n  \"promotedAt\": \"2026-01-01T00:01:30Z\",\n  \"promotedByUserUuid\": \"...\",\n  \"finishedAt\": \"2026-01-01T00:01:10Z\",\n  \"temporalWorkflowId\": \"...\",\n  \"createdAt\": \"2026-01-01T00:00:00Z\",\n  \"updatedAt\": \"2026-01-01T00:01:30Z\"\n}\n```\n\n- **`kind: \"app\"`** carries `appUuid` and an empty `meta` (`{}`).\n- **`kind: \"worker\"`** carries `workerUuid` instead of `appUuid`, and `meta: { \"bundleSha256\": \"...\", \"outboundAllowlist\": [\"...\"] }`.\n\n**Key fields:**\n\n- `uuid` — pass to `deployment promote --uuid`.\n- `url` — this deployment's own preview host (`deployment-<uuid>.<root>`), reachable before promotion. The live URL is the app's/worker's `url`.\n- `appUuid` / `workerUuid` — exactly one is set, matching `kind`.\n- **`status`** — one of `\"pending\"`, `\"building\"`, `\"success\"`, `\"error\"`, `\"cancelled\"`. **Terminal** at `success` / `error` / `cancelled`; only a `success` deployment is worth promoting.\n- `errorMessage` — populated when `status` is `error`; `buildLogS3Filename` points at the build log for diagnosing a failed build.\n- `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).\n- `finishedAt` — when the build reached a terminal state.\n\n## get-promoted (`hosting deployment get-promoted`)\n\nReturns 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.\n\n## env (`hosting app env`)\n\nNot 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`.\n\n## init templates (`hosting app init <dir> --list-templates`)\n\n```json\n[\n  { \"slug\": \"blank\", \"description\": \"...\" },\n  { \"slug\": \"territories-overview\", \"description\": \"...\" }\n]\n```\n\nWorkers list their own templates (`blank`, `custom-integration`) via `hosting worker init <dir> --list-templates`. Note `--list-templates` still requires the `<directory>` positional argument.\n\nFile v1.1.0:references/troubleshooting.md\n\n# Hosting troubleshooting\n\nCommon errors in the `hosting` domain and how to fix them.\n\n## `unknown command 'hosting'`\n\nThe `hosting` domain shipped in a recent CLI. If `cargo-ai hosting --help` errors, bump the CLI: `npm install -g @cargo-ai/cli@latest`.\n\n## Slug already taken / `create` fails with `duplicateSlug`\n\nThe `--slug` must be unique **within your workspace**. The live host adds a workspace suffix (`<slug>-<workspace prefix>.<root>`), so another workspace using the same slug is never the cause. Remove or rename the existing app/worker with that slug, or pick another.\n\n## I deployed but the URL still shows the old version\n\n`deployment create` only builds and uploads — it does **not** change the live URL. Promote the new deployment:\n\n```bash\ncargo-ai hosting deployment get <deployment-uuid>      # confirm the build is terminal/succeeded\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>   # verify what's live\n```\n\n## `deployment create` build fails\n\nThe build runs server-side in a sandbox (`npm ci --ignore-scripts` then the app's `build` script, or the framework default, for apps; entrypoint bundling for workers). A failed build usually means:\n\n- **The app's own `build` script failed.** If `package.json` declares one, Cargo runs it verbatim, including any `tsc` pass, `--mode`, or `prebuild`/`postbuild` hook. Run `npm run build` locally first.\n- **No `index.html` in the output directory.** Output must land in the detected framework's directory (`dist` for Vite/Astro/undetected, `out` for Next.js, `build` for SvelteKit/CRA, `public` for Gatsby, `.output/public` for Nuxt).\n\n- **`--source` points at the wrong directory.** Pass the **package root** (where `package.json` lives), not a pre-built `dist/`.\n- **`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.\n- **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.\n\n- **Worker entrypoint not found** (`Expected one of: src/index.ts, src/index.js, index.ts, index.js.`). The worker build only looks for those four names. Rename a `.mjs`/`.mts`/`.cjs` entrypoint (and the files it imports, if they use those extensions) to `.js`/`.ts`. ES module syntax is fine in `.js` with `\"type\": \"module\"` in `package.json`.\n\nWhen `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`.\n\n## `--app-uuid` and `--worker-uuid` both passed (or neither)\n\nOn `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.\n\n## `folderNotFound` on `--folder-uuid`\n\nThe 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`.\n\n## `app env` writes the wrong API URL\n\nBy 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` command. Run them locally with `npm run dev` and export what they need (see below).\n\n## Worker throws `Missing CARGO_API_TOKEN`\n\n`createCargoApi(c.env)` needs a workspace API token, and Cargo does **not** inject one (it only binds `CARGO_API_URL`, `CARGO_WORKSPACE_UUID`, `CARGO_WORKER_UUID`). Create one and store it as a secret, then **deploy and promote again**:\n\n```bash\ncargo-ai workspaceManagement token create --name \"worker: <slug>\"\nexport CARGO_API_TOKEN=<token value>\ncargo-ai workspaceManagement envVar create --key CARGO_API_TOKEN --secret   # every worker inherits it\n```\n\nTo scope it to one worker, see `SKILL.md` → \"Worker env vars and secrets\". Locally, `export CARGO_API_TOKEN=…` before `npm run dev`.\n\n## I set an env var but the worker doesn't see it\n\nEnv vars are bound when a deployment is **promoted**, and non-secret values are also compiled into the bundle. The running deployment keeps the values it was promoted with. Run `deployment create` + `promote` again. To check which keys exist, list them: `workspaceManagement envVar list`, or `GET /v1/hosting/env-vars?workerUuid=<uuid>` for worker-level entries.\n\nDon't debug this by shipping an endpoint that echoes `Object.keys(c.env)`. The listing above answers the same question without a deploy.\n\n## Worker returns 502/500 but the logs show no cause\n\n`createWorker()` logs an **uncaught** exception with its stack. If your route catches the error and returns a sanitized message, only the HTTP line reaches the logs. Add `console.error(err)` in the `catch` before returning, then redeploy. Everything a request writes through `console.*` is captured (the first 50 lines per request). Read logs in the web app or via `POST /v1/hosting/logs/list` with `{\"workerUuid\":\"<uuid>\",\"levels\":[\"error\"]}`.\n\n## Browser blocks the app's calls to the worker (CORS)\n\nApps and workers are served from different root domains, so every app → worker call is cross-origin and preflighted. Add `hono/cors` middleware on the worker for the app's exact origin (from `hosting app get` → `url`) plus your local dev origin, registered before the routes. Pass the worker URL to the app as a public-prefixed env var (`VITE_…` for a Vite app), not a hardcoded global. Full snippet: [`examples/workers.md`](examples/workers.md#calling-a-worker-from-an-app).\n\n## Build went green but my prerender step didn't run\n\nIf Cargo can't use the declared `build` script (unparseable `package.json`, empty script, non-string entry), it falls back to the framework default without failing. The build log names the reason: `No usable \\`build\\` script (…); running … instead`.\n\n## `secretNotSupportedForApp` / CDK \"must be a plain string\"\n\nApp env vars are compiled into a public bundle, so they cannot be secret. Move the credential to a worker, and have the app call that worker.\n\n## `App environment variables must start with a recognized prefix`\n\nApp keys need a public prefix: `VITE_`, `NEXT_PUBLIC_`, `PUBLIC_`, `NUXT_PUBLIC_`, `GATSBY_` or `REACT_APP_`.\n\n## My public app isn't showing up in search\n\nThe default host and every deployment preview send `X-Robots-Tag: noindex`, so attach a custom domain (`POST /v1/hosting/custom-domains`, then `refresh-status` until `active`). Serve prerendered HTML at `.html` paths and submit the sitemap. Apps on `CargoRefineApp` require a login and can't be indexed at all. Full checklist: `SKILL.md` → Custom domains and search indexing.\n\n## Removing an app/worker took its deployments too\n\nThat'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.\n\n## Still stuck\n\nFile a report so the Cargo team can improve the CLI and these docs:\n\n```bash\ncargo-ai workspaceManagement report create \\\n  --title \"<one-line summary>\" \\\n  --description \"<exact command(s), errorMessage, expected vs actual, UUIDs involved>\"\n```\n\nFile v1.1.0:skill-card.md\n\n## Description:\n\nHelps agents use Cargo CLI hosting to scaffold, create, deploy, promote, configure, and troubleshoot hosted web apps, edge workers, deployments, secrets, custom domains, and search-indexable public sites.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[cargo-ai](https://clawhub.ai/user/cargo-ai)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and engineers use this skill to publish Cargo-hosted static apps and serverless HTTP workers, then manage deployments, environment variables, secrets, logs, custom domains, and troubleshooting workflows.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can guide an agent through creating, promoting, or removing public Cargo-hosted apps and workers.\n\nMitigation: Confirm the target workspace and review deployment, promotion, and removal commands before execution.\n\nRisk: CARGO_API_TOKEN and worker secrets may be exposed or over-scoped if handled as normal app configuration.\n\nMitigation: Treat CARGO_API_TOKEN as a secret, prefer worker-scoped secrets over workspace-wide tokens, and avoid placing credentials in public app environment variables.\n\nRisk: Hosted resources can consume monthly credits while they remain active.\n\nMitigation: Review resource ownership and billing impact before creating resources, and remove apps or workers that should no longer be served.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/cargo-ai/skills/cargo-hosting)\n- [Cargo Skills Homepage](https://github.com/getcargohq/cargo-skills)\n- [App examples](references/examples/apps.md)\n- [Deployment examples](references/examples/deployments.md)\n- [Worker examples](references/examples/workers.md)\n- [Hosting response shapes](references/response-shapes.md)\n- [Hosting troubleshooting](references/troubleshooting.md)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, Code, Configuration]\n\n**Output Format:** [Markdown with inline shell commands, JSON examples, and configuration snippets]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May propose Cargo CLI commands and API calls that create, modify, promote, or remove hosted resources.]\n\n## Skill Version(s):\n\n1.1.0 (source: frontmatter and server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.1.0:skill-metadata.json\n\n{\n  \"$comment\": \"Generated by .github/scripts/skills-metadata.mjs — do not hand-edit. Regenerate with: node .github/scripts/skills-metadata.mjs --write .\",\n  \"name\": \"cargo-hosting\",\n  \"version\": \"1.1.0\",\n  \"documents\": [\n    {\n      \"path\": \"SKILL.md\",\n      \"kind\": \"entrypoint\",\n      \"title\": \"Cargo CLI — Hosting\"\n    },\n    {\n      \"path\": \"references/examples/apps.md\",\n      \"kind\": \"example\",\n      \"title\": \"App examples\"\n    },\n    {\n      \"path\": \"references/examples/deployments.md\",\n      \"kind\": \"example\",\n      \"title\": \"Deployment examples\"\n    },\n    {\n      \"path\": \"references/examples/workers.md\",\n      \"kind\": \"example\",\n      \"title\": \"Worker examples\"\n    },\n    {\n      \"path\": \"references/response-shapes.md\",\n      \"kind\": \"reference\",\n      \"title\": \"Hosting response shapes\"\n    },\n    {\n      \"path\": \"references/troubleshooting.md\",\n      \"kind\": \"reference\",\n      \"title\": \"Hosting troubleshooting\"\n    }\n  ],\n  \"contentHash\": \"54a7b4f5079f9cd3e1d0235ce31e04f11808c4f8c21e761c3224c0ae51aa514c\"\n}\n\nArchive v1.0.2: 9 files, 13257 bytes\n\nFiles: references/examples/apps.md (3246b), references/examples/deployments.md (2276b), references/examples/workers.md (2819b), references/response-shapes.md (3892b), references/troubleshooting.md (3296b), skill-card.md (2773b), skill-metadata.json (1035b), SKILL.md (9391b), _meta.json (132b)\n\nFile v1.0.2:SKILL.md\n\n---\nname: cargo-hosting\ndescription: \"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-project.\"\nversion: \"1.0.2\"\ncompatibility: 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\nhomepage: https://github.com/getcargohq/cargo-skills\nmetadata:\n  author: getcargo\n  openclaw:\n    requires:\n      bins:\n        - cargo-ai\n    install:\n      - kind: node\n        package: \"@cargo-ai/cli@latest\"\n        bins:\n          - cargo-ai\n    homepage: https://github.com/getcargohq/cargo-skills\n---\n\n# Cargo CLI — Hosting\n\n**Cargo Hosting** runs two kinds of workspace-scoped resources, plus the deployments that ship them:\n\n- **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).\n- **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`).\n- **Deployment** — one build+upload of a local source directory to an app or worker. A deployment is **not live until it's promoted**.\n\n> 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.\n\n> See `references/examples/apps.md`, `references/examples/workers.md`, and `references/examples/deployments.md` for end-to-end walkthroughs.\n> See `references/response-shapes.md` for JSON response structures.\n> See `references/troubleshooting.md` for common errors and how to fix them.\n\n## Bootstrap\n\nAlready signed in (`cargo-ai whoami` returns a workspace)? Skip to the next section.\n\n```bash\nnpm install -g @cargo-ai/cli            # no global install? prefix every command with `npx @cargo-ai/cli`\ncargo-ai login --email you@company.com  # emailed code, no browser; creates the account on first use\n                                        # alternatives: --oauth (browser) · --token <api-token> (CI)\ncargo-ai whoami                         # confirm the active workspace before any write\n```\n\nEvery 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.\n\n## The lifecycle\n\nApps and workers follow the same shape — **scaffold → create slot → deploy → promote**:\n\n```\ninit (local scaffold) → create (slot + slug) → deployment create (build+upload) → deployment promote (go live)\n```\n\n1. **Scaffold** a local project from a template — `hosting app init <dir>` / `hosting worker init <dir>`.\n2. **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**.\n3. **(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).\n4. **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`.\n5. **Promote** — `hosting deployment promote --uuid <deploymentUuid>` points the live URL at that build.\n\nDeploys build asynchronously — **poll `hosting deployment get <uuid>`** until the status is terminal before promoting (see [Async polling](#async-polling)).\n\n## Apps\n\n```bash\n# Discover\ncargo-ai hosting app list                          # all apps (filter with --folder-uuid <uuid>)\ncargo-ai hosting app get <uuid>                     # one app's details + URL\n\n# Scaffold locally (Vite + @cargo-ai/app-sdk)\ncargo-ai hosting app init ./my-app --list-templates # see available templates, then:\ncargo-ai hosting app init ./my-app --template blank --name \"My App\"\n\n# Create the slot (slug must be globally unique → it's the subdomain)\ncargo-ai hosting app create --name \"My App\" --slug my-app --folder-uuid <folder-uuid>\n\n# Print .env.local for local development\ncargo-ai hosting app env <app-uuid>\ncargo-ai hosting app env <app-uuid> --api-url https://api.getcargo.io\n\n# Update / remove\ncargo-ai hosting app update --uuid <app-uuid> --name \"Renamed\"\ncargo-ai hosting app update --uuid <app-uuid> --folder-uuid null   # move to workspace root\ncargo-ai hosting app remove <app-uuid>                             # also removes its deployments\n```\n\nTemplates: `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.\n\n## Workers\n\nSame command shape as apps — substitute `worker` for `app`:\n\n```bash\ncargo-ai hosting worker list                        # filter with --folder-uuid <uuid>\ncargo-ai hosting worker get <uuid>\n\n# Scaffold (edge fetch(request, env) handler on @cargo-ai/worker-sdk)\ncargo-ai hosting worker init ./my-worker --list-templates\ncargo-ai hosting worker init ./my-worker --template blank --name \"My Worker\"\n\ncargo-ai hosting worker create --name \"My Worker\" --slug my-worker --folder-uuid <folder-uuid>\ncargo-ai hosting worker update --uuid <worker-uuid> --name \"Renamed\"\ncargo-ai hosting worker remove <worker-uuid>        # also removes its deployments\n```\n\nTemplates: `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.\n\n## Deployments\n\nA deployment belongs to exactly one app **or** one worker (`--app-uuid` and `--worker-uuid` are mutually exclusive).\n\n```bash\n# List / inspect\ncargo-ai hosting deployment list --app-uuid <uuid>          # or --worker-uuid <uuid>\ncargo-ai hosting deployment get <deployment-uuid>           # status + metadata\ncargo-ai hosting deployment get-promoted --app-uuid <uuid>  # what's currently live\n\n# Build & upload a local source directory (point at the package root, NOT dist/)\ncargo-ai hosting deployment create --app-uuid <uuid> --source ./my-app\ncargo-ai hosting deployment create --worker-uuid <uuid> --source ./my-worker\n# default ignores: node_modules,dist,build,.git,.next — override with --ignore \"a,b,c\"\n\n# Go live\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n```\n\n## Critical rules\n\n- **`--slug` must be globally unique within the hosting domain** — it's the live subdomain (`<slug>.cargo.app`). A clash fails at `create`.\n- **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.\n- **`--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.\n- **Builds are async** — poll `deployment get` until terminal before promoting (see below).\n- **`--app-uuid` / `--worker-uuid` are mutually exclusive** on `deployment create`, `deployment list`, and `deployment get-promoted`. Pass exactly one.\n- **`remove` cascades** — removing an app or worker also removes all of its deployments.\n- **`update --folder-uuid null`** (literal string `null`) moves a resource back to the workspace root.\n- **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).\n\n## Async polling\n\n`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:\n\n```bash\ncargo-ai hosting deployment get <deployment-uuid>   # poll ~2–5s until status is terminal\n```\n\nTerminal 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).\n\n## Help\n\nEvery command supports `--help`:\n\n```bash\ncargo-ai hosting app create --help\ncargo-ai hosting deployment create --help\n```\n\nFile v1.0.2:_meta.json\n\n{\n  \"ownerId\": \"kn7by8t6yt9yghbxtxz6hv0bts87k6bq\",\n  \"slug\": \"cargo-hosting\",\n  \"version\": \"1.0.2\",\n  \"publishedAt\": 1789367226938\n}\n\nFile v1.0.2:references/examples/apps.md\n\n# App examples\n\nApps are Vite single-page apps served on `https://<slug>.cargo.app`, scaffolded from `@cargo-ai/app-sdk`.\n\n## Scaffold → create → deploy → promote (end to end)\n\n```bash\n# 1. See what templates exist, then scaffold a local project\ncargo-ai hosting app init ./territories --list-templates\ncargo-ai hosting app init ./territories --template territories-overview --name \"Territories\"\n\n# 2. Create the workspace slot. --slug is the live subdomain → must be globally unique.\ncargo-ai hosting app create --name \"Territories\" --slug territories\n# → { \"uuid\": \"<app-uuid>\", \"slug\": \"territories\", \"url\": \"https://territories.cargo.app\", ... }\n\n# 3. (optional) Develop locally — write the .env.local the app needs, then run Vite\ncargo-ai hosting app env <app-uuid> > ./territories/.env.local\ncd ./territories && npm install && npm run dev\n\n# 4. Build & upload (source = package root, not dist/). The backend runs `npm ci && vite build`.\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./territories\n# → { \"uuid\": \"<deployment-uuid>\", \"status\": \"...\", ... }\n\n# 5. Poll until the build is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n\n# 6. Promote to make it live at https://territories.cargo.app\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n\n# 7. Confirm what's live\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\n```\n\n## List and inspect\n\n```bash\ncargo-ai hosting app list                       # all apps in the workspace\ncargo-ai hosting app list --folder-uuid <uuid>  # only apps in one folder\ncargo-ai hosting app get <app-uuid>             # one app's details + live URL\n```\n\n## Local development env\n\n`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.\n\n```bash\n# Default API URL (https://api.getcargo.io)\ncargo-ai hosting app env <app-uuid> > ./my-app/.env.local\n\n# Point at a different API (e.g. a staging environment)\ncargo-ai hosting app env <app-uuid> --api-url https://api.staging.getcargo.io > ./my-app/.env.local\n```\n\n## Rename, move, remove\n\n```bash\n# Rename\ncargo-ai hosting app update --uuid <app-uuid> --name \"Renamed App\"\n\n# Move into a folder (folders are managed by cargo-workspace-management)\ncargo-ai workspaceManagement folder list                          # find the folder UUID\ncargo-ai hosting app update --uuid <app-uuid> --folder-uuid <folder-uuid>\n\n# Move back to the workspace root (literal string \"null\")\ncargo-ai hosting app update --uuid <app-uuid> --folder-uuid null\n\n# Remove (also removes every deployment of this app)\ncargo-ai hosting app remove <app-uuid>\n```\n\n## Ship a new version of an existing app\n\nThe app slot and slug stay put; you just create and promote a fresh deployment.\n\n```bash\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app\n# poll deployment get <new-deployment-uuid> until terminal\ncargo-ai hosting deployment promote --uuid <new-deployment-uuid>\n```\n\nRoll 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.\n\nFile v1.0.2:references/examples/deployments.md\n\n# Deployment examples\n\nA deployment is one build+upload of a local source directory to an app or worker. Two facts drive everything below:\n\n1. A deployment belongs to **exactly one** app or worker — `--app-uuid` and `--worker-uuid` are mutually exclusive.\n2. **Building is not promoting.** `deployment create` builds; the live URL only moves when you `deployment promote`.\n\n## Create a deployment\n\n```bash\n# App: backend runs `npm ci && vite build` in a sandbox\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app\n\n# Worker: backend bundles the entrypoint\ncargo-ai hosting deployment create --worker-uuid <worker-uuid> --source ./my-worker\n```\n\n- `--source` is the **package root** (where `package.json` lives), not a pre-built `dist/`. The build happens server-side.\n- Default ignore list: `node_modules,dist,build,.git,.next`. Override the whole list with `--ignore`:\n\n```bash\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app \\\n  --ignore \"node_modules,dist,build,.git,.next,coverage,.turbo\"\n```\n\n## Poll the build, then promote\n\n```bash\n# Builds are async — poll until the status field is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n# when terminal (built/succeeded), promote:\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n```\n\nIf 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.\n\n## List deployment history\n\n```bash\ncargo-ai hosting deployment list --app-uuid <app-uuid>       # newest first\ncargo-ai hosting deployment list --worker-uuid <worker-uuid>\n```\n\n## See what's currently live\n\n```bash\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\ncargo-ai hosting deployment get-promoted --worker-uuid <worker-uuid>\n```\n\n## Roll back to a previous deployment\n\nPromotion just points the live URL at a deployment, so rolling back is promoting an older one — no rebuild needed.\n\n```bash\n# 1. Find the deployment you want to go back to\ncargo-ai hosting deployment list --app-uuid <app-uuid>\n\n# 2. Promote it\ncargo-ai hosting deployment promote --uuid <older-deployment-uuid>\n\n# 3. Verify\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\n```\n\nFile v1.0.2:references/examples/workers.md\n\n# Worker examples\n\nWorkers 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`.\n\n## Scaffold → create → deploy → promote (end to end)\n\n```bash\n# 1. Scaffold a local worker project\ncargo-ai hosting worker init ./my-api --list-templates\ncargo-ai hosting worker init ./my-api --template blank --name \"My API\"\n\n# 2. Create the workspace slot. --slug is the live subdomain → must be globally unique.\ncargo-ai hosting worker create --name \"My API\" --slug my-api\n# → { \"uuid\": \"<worker-uuid>\", \"slug\": \"my-api\", \"url\": \"https://my-api.cargo.app\", ... }\n\n# 3. Build & upload (source = package root). The backend bundles the entrypoint.\ncargo-ai hosting deployment create --worker-uuid <worker-uuid> --source ./my-api\n# → { \"uuid\": \"<deployment-uuid>\", \"status\": \"...\", ... }\n\n# 4. Poll until the build is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n\n# 5. Promote to go live\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n\n# 6. Confirm what's live, then hit it\ncargo-ai hosting deployment get-promoted --worker-uuid <worker-uuid>\ncurl https://my-api.cargo.app/openapi.json\n```\n\n## List and inspect\n\n```bash\ncargo-ai hosting worker list                       # all workers\ncargo-ai hosting worker list --folder-uuid <uuid>  # only workers in one folder\ncargo-ai hosting worker get <worker-uuid>          # one worker's details + URL\n```\n\n## Templates\n\n```bash\ncargo-ai hosting worker init ./tmp --list-templates\n```\n\n- **`blank`** — edge worker on `@cargo-ai/worker-sdk` with automatic OpenAPI 3.1 spec at `/openapi.json` and Swagger UI at `/docs`.\n- **`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.\n\n## Rename, move, remove\n\n```bash\ncargo-ai hosting worker update --uuid <worker-uuid> --name \"Renamed Worker\"\ncargo-ai hosting worker update --uuid <worker-uuid> --folder-uuid <folder-uuid>\ncargo-ai hosting worker update --uuid <worker-uuid> --folder-uuid null   # back to root\ncargo-ai hosting worker remove <worker-uuid>                            # also removes its deployments\n```\n\n## App vs worker — when to use which\n\n- **App** — you want a UI on `*.cargo.app` (dashboard, internal tool, data grid). Vite SPA, `app init`, has an `env` subcommand for local dev.\n- **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`.\n\nFile v1.0.2:references/response-shapes.md\n\n# Hosting response shapes\n\nJSON response structures for the `hosting` domain. All commands output JSON to stdout; failures exit non-zero with `{\"errorMessage\": \"...\"}`.\n\n## App (`hosting app get` / items in `hosting app list`)\n\n```json\n{\n  \"uuid\": \"app-uuid\",\n  \"workspaceUuid\": \"...\",\n  \"name\": \"My App\",\n  \"description\": null,\n  \"slug\": \"my-app\",\n  \"url\": \"https://my-app.cargo.app\",\n  \"userUuid\": \"...\",\n  \"folderUuid\": null,\n  \"promotedDeployment\": null,\n  \"chargedUntil\": \"2026-02-01T00:00:00Z\",\n  \"createdAt\": \"2026-01-01T00:00:00Z\",\n  \"updatedAt\": \"2026-01-15T00:00:00Z\",\n  \"deletedAt\": null\n}\n```\n\n**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)).\n\n## Worker (`hosting worker get` / items in `hosting worker list`)\n\nIdentical 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.\n\n## Deployment (`hosting deployment get` / items in `hosting deployment list`)\n\nA deployment is a discriminated union on `kind` (`\"app\"` | `\"worker\"`). Shared fields:\n\n```json\n{\n  \"uuid\": \"deployment-uuid\",\n  \"kind\": \"app\",\n  \"appUuid\": \"app-uuid\",\n  \"workspaceUuid\": \"...\",\n  \"status\": \"success\",\n  \"url\": \"https://my-app.cargo.app\",\n  \"sourceS3Path\": \"...\",\n  \"bundleS3Path\": \"...\",\n  \"buildLogS3Filename\": \"...\",\n  \"errorMessage\": null,\n  \"meta\": {},\n  \"userUuid\": \"...\",\n  \"promotedAt\": \"2026-01-01T00:01:30Z\",\n  \"promotedByUserUuid\": \"...\",\n  \"finishedAt\": \"2026-01-01T00:01:10Z\",\n  \"temporalWorkflowId\": \"...\",\n  \"createdAt\": \"2026-01-01T00:00:00Z\",\n  \"updatedAt\": \"2026-01-01T00:01:30Z\"\n}\n```\n\n- **`kind: \"app\"`** carries `appUuid` and an empty `meta` (`{}`).\n- **`kind: \"worker\"`** carries `workerUuid` instead of `appUuid`, and `meta: { \"bundleSha256\": \"...\", \"outboundAllowlist\": [\"...\"] }`.\n\n**Key fields:**\n\n- `uuid` — pass to `deployment promote --uuid`.\n- `appUuid` / `workerUuid` — exactly one is set, matching `kind`.\n- **`status`** — one of `\"pending\"`, `\"building\"`, `\"success\"`, `\"error\"`, `\"cancelled\"`. **Terminal** at `success` / `error` / `cancelled`; only a `success` deployment is worth promoting.\n- `errorMessage` — populated when `status` is `error`; `buildLogS3Filename` points at the build log for diagnosing a failed build.\n- `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).\n- `finishedAt` — when the build reached a terminal state.\n\n## get-promoted (`hosting deployment get-promoted`)\n\nReturns 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.\n\n## env (`hosting app env`)\n\nNot 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`.\n\n## init templates (`hosting app init <dir> --list-templates`)\n\n```json\n[\n  { \"slug\": \"blank\", \"description\": \"...\" },\n  { \"slug\": \"territories-overview\", \"description\": \"...\" }\n]\n```\n\nWorkers list their own templates (`blank`, `custom-integration`) via `hosting worker init <dir> --list-templates`. Note `--list-templates` still requires the `<directory>` positional argument.\n\nFile v1.0.2:references/troubleshooting.md\n\n# Hosting troubleshooting\n\nCommon errors in the `hosting` domain and how to fix them.\n\n## `unknown command 'hosting'`\n\nThe `hosting` domain shipped in a recent CLI. If `cargo-ai hosting --help` errors, bump the CLI: `npm install -g @cargo-ai/cli@latest`.\n\n## Slug already taken / `create` fails on `--slug`\n\nThe `--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`.\n\n## I deployed but the URL still shows the old version\n\n`deployment create` only builds and uploads — it does **not** change the live URL. Promote the new deployment:\n\n```bash\ncargo-ai hosting deployment get <deployment-uuid>      # confirm the build is terminal/succeeded\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>   # verify what's live\n```\n\n## `deployment create` build fails\n\nThe build runs server-side in a sandbox (`npm ci && vite build` for apps, entrypoint bundling for workers). A failed build usually means:\n\n- **`--source` points at the wrong directory.** Pass the **package root** (where `package.json` lives), not a pre-built `dist/`.\n- **`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.\n- **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.\n\nWhen `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`.\n\n## `--app-uuid` and `--worker-uuid` both passed (or neither)\n\nOn `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.\n\n## `folderNotFound` on `--folder-uuid`\n\nThe 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`.\n\n## `app env` writes the wrong API URL\n\nBy 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.\n\n## Removing an app/worker took its deployments too\n\nThat'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.\n\n## Still stuck\n\nFile a report so the Cargo team can improve the CLI and these docs:\n\n```bash\ncargo-ai workspaceManagement report create \\\n  --title \"<one-line summary>\" \\\n  --description \"<exact command(s), errorMessage, expected vs actual, UUIDs involved>\"\n```\n\nFile v1.0.2:skill-card.md\n\n## Description:\n\nCargo Hosting helps agents put Cargo-hosted Vite single-page apps and serverless edge workers online, including scaffolding, deployment creation, build polling, promotion, inspection, rollback, and removal.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[cargo-ai](https://clawhub.ai/user/cargo-ai)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and engineering agents use this skill to create, deploy, promote, inspect, and remove Cargo-hosted apps and workers for shareable web UIs, dashboards, webhooks, APIs, and integration endpoints.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can upload local source directories to Cargo's build service, which may expose secrets or unintended files.\n\nMitigation: Review the source directory before deployment, exclude .env files and secrets, and use ignore settings deliberately.\n\nRisk: Deployment promotion can publish or change public URLs served under cargo.app.\n\nMitigation: Poll until a deployment reaches a successful terminal state, verify the target app or worker UUID, and promote only the intended deployment.\n\nRisk: Removal commands can delete hosted apps or workers and cascade to their deployments.\n\nMitigation: Confirm the target workspace and resource UUID before remove operations, and inspect currently promoted deployments when availability matters.\n\nRisk: Hosted apps and workers can consume ongoing hosting credits.\n\nMitigation: Track active resources and remove apps or workers that should no longer be served.\n\n## Reference(s):\n\n- [Cargo skills homepage](https://github.com/getcargohq/cargo-skills)\n- [ClawHub skill page](https://clawhub.ai/cargo-ai/skills/cargo-hosting)\n- [App examples](references/examples/apps.md)\n- [Deployment examples](references/examples/deployments.md)\n- [Worker examples](references/examples/workers.md)\n- [Hosting response shapes](references/response-shapes.md)\n- [Hosting troubleshooting](references/troubleshooting.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, code, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with inline shell commands, code snippets, JSON response shapes, and configuration notes.]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands produce JSON on stdout except app env output, and failures return non-zero with an errorMessage object.]\n\n## Skill Version(s):\n\n1.0.2 (source: frontmatter and release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.0.2:skill-metadata.json\n\n{\n  \"$comment\": \"Generated by .github/scripts/skills-metadata.mjs — do not hand-edit. Regenerate with: node .github/scripts/skills-metadata.mjs --write .\",\n  \"name\": \"cargo-hosting\",\n  \"version\": \"1.0.2\",\n  \"documents\": [\n    {\n      \"path\": \"SKILL.md\",\n      \"kind\": \"entrypoint\",\n      \"title\": \"Cargo CLI — Hosting\"\n    },\n    {\n      \"path\": \"references/examples/apps.md\",\n      \"kind\": \"example\",\n      \"title\": \"App examples\"\n    },\n    {\n      \"path\": \"references/examples/deployments.md\",\n      \"kind\": \"example\",\n      \"title\": \"Deployment examples\"\n    },\n    {\n      \"path\": \"references/examples/workers.md\",\n      \"kind\": \"example\",\n      \"title\": \"Worker examples\"\n    },\n    {\n      \"path\": \"references/response-shapes.md\",\n      \"kind\": \"reference\",\n      \"title\": \"Hosting response shapes\"\n    },\n    {\n      \"path\": \"references/troubleshooting.md\",\n      \"kind\": \"reference\",\n      \"title\": \"Hosting troubleshooting\"\n    }\n  ],\n  \"contentHash\": \"ad4c6518a0be45c6a713e9de33e572a226a353c872a769f8dd95707dd5b8c2c0\"\n}\n\nArchive v1.0.1: 9 files, 12652 bytes\n\nFiles: references/examples/apps.md (3246b), references/examples/deployments.md (2276b), references/examples/workers.md (2819b), references/response-shapes.md (3892b), references/troubleshooting.md (3296b), skill-card.md (2378b), skill-metadata.json (1035b), SKILL.md (8503b), _meta.json (132b)\n\nFile v1.0.1:SKILL.md\n\n---\nname: cargo-hosting\ndescription: Build, deploy, and manage Cargo Hosting apps and workers with the Cargo CLI — Vite SPAs served on *.cargo.app and serverless edge HTTP handlers, plus the deployments that ship and promote them. Use when the user wants to scaffold, deploy, promote, or manage a hosted app or worker on Cargo.\nversion: \"1.0.1\"\ncompatibility: 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\nhomepage: https://github.com/getcargohq/cargo-skills\nmetadata:\n  author: getcargo\n  openclaw:\n    requires:\n      bins:\n        - cargo-ai\n    install:\n      - kind: node\n        package: \"@cargo-ai/cli@latest\"\n        bins:\n          - cargo-ai\n    homepage: https://github.com/getcargohq/cargo-skills\n---\n\n# Cargo CLI — Hosting\n\n**Cargo Hosting** runs two kinds of workspace-scoped resources, plus the deployments that ship them:\n\n- **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).\n- **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`).\n- **Deployment** — one build+upload of a local source directory to an app or worker. A deployment is **not live until it's promoted**.\n\n> 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.\n\n> See `references/examples/apps.md`, `references/examples/workers.md`, and `references/examples/deployments.md` for end-to-end walkthroughs.\n> See `references/response-shapes.md` for JSON response structures.\n> See `references/troubleshooting.md` for common errors and how to fix them.\n\n## Prerequisites\n\nSee [`../cargo/references/prerequisites.md`](../cargo/references/prerequisites.md) for install, login (`--oauth` / `--token`), JSON output conventions, and error shapes. Verify the session with `cargo-ai whoami` before running any command below.\n\n## The lifecycle\n\nApps and workers follow the same shape — **scaffold → create slot → deploy → promote**:\n\n```\ninit (local scaffold) → create (slot + slug) → deployment create (build+upload) → deployment promote (go live)\n```\n\n1. **Scaffold** a local project from a template — `hosting app init <dir>` / `hosting worker init <dir>`.\n2. **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**.\n3. **(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).\n4. **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`.\n5. **Promote** — `hosting deployment promote --uuid <deploymentUuid>` points the live URL at that build.\n\nDeploys build asynchronously — **poll `hosting deployment get <uuid>`** until the status is terminal before promoting (see [Async polling](#async-polling)).\n\n## Apps\n\n```bash\n# Discover\ncargo-ai hosting app list                          # all apps (filter with --folder-uuid <uuid>)\ncargo-ai hosting app get <uuid>                     # one app's details + URL\n\n# Scaffold locally (Vite + @cargo-ai/app-sdk)\ncargo-ai hosting app init ./my-app --list-templates # see available templates, then:\ncargo-ai hosting app init ./my-app --template blank --name \"My App\"\n\n# Create the slot (slug must be globally unique → it's the subdomain)\ncargo-ai hosting app create --name \"My App\" --slug my-app --folder-uuid <folder-uuid>\n\n# Print .env.local for local development\ncargo-ai hosting app env <app-uuid>\ncargo-ai hosting app env <app-uuid> --api-url https://api.getcargo.io\n\n# Update / remove\ncargo-ai hosting app update --uuid <app-uuid> --name \"Renamed\"\ncargo-ai hosting app update --uuid <app-uuid> --folder-uuid null   # move to workspace root\ncargo-ai hosting app remove <app-uuid>                             # also removes its deployments\n```\n\nTemplates: `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.\n\n## Workers\n\nSame command shape as apps — substitute `worker` for `app`:\n\n```bash\ncargo-ai hosting worker list                        # filter with --folder-uuid <uuid>\ncargo-ai hosting worker get <uuid>\n\n# Scaffold (edge fetch(request, env) handler on @cargo-ai/worker-sdk)\ncargo-ai hosting worker init ./my-worker --list-templates\ncargo-ai hosting worker init ./my-worker --template blank --name \"My Worker\"\n\ncargo-ai hosting worker create --name \"My Worker\" --slug my-worker --folder-uuid <folder-uuid>\ncargo-ai hosting worker update --uuid <worker-uuid> --name \"Renamed\"\ncargo-ai hosting worker remove <worker-uuid>        # also removes its deployments\n```\n\nTemplates: `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.\n\n## Deployments\n\nA deployment belongs to exactly one app **or** one worker (`--app-uuid` and `--worker-uuid` are mutually exclusive).\n\n```bash\n# List / inspect\ncargo-ai hosting deployment list --app-uuid <uuid>          # or --worker-uuid <uuid>\ncargo-ai hosting deployment get <deployment-uuid>           # status + metadata\ncargo-ai hosting deployment get-promoted --app-uuid <uuid>  # what's currently live\n\n# Build & upload a local source directory (point at the package root, NOT dist/)\ncargo-ai hosting deployment create --app-uuid <uuid> --source ./my-app\ncargo-ai hosting deployment create --worker-uuid <uuid> --source ./my-worker\n# default ignores: node_modules,dist,build,.git,.next — override with --ignore \"a,b,c\"\n\n# Go live\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n```\n\n## Critical rules\n\n- **`--slug` must be globally unique within the hosting domain** — it's the live subdomain (`<slug>.cargo.app`). A clash fails at `create`.\n- **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.\n- **`--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.\n- **Builds are async** — poll `deployment get` until terminal before promoting (see below).\n- **`--app-uuid` / `--worker-uuid` are mutually exclusive** on `deployment create`, `deployment list`, and `deployment get-promoted`. Pass exactly one.\n- **`remove` cascades** — removing an app or worker also removes all of its deployments.\n- **`update --folder-uuid null`** (literal string `null`) moves a resource back to the workspace root.\n- **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).\n\n## Async polling\n\n`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:\n\n```bash\ncargo-ai hosting deployment get <deployment-uuid>   # poll ~2–5s until status is terminal\n```\n\nTerminal 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).\n\n## Help\n\nEvery command supports `--help`:\n\n```bash\ncargo-ai hosting app create --help\ncargo-ai hosting deployment create --help\n```\n\nFile v1.0.1:_meta.json\n\n{\n  \"ownerId\": \"kn7by8t6yt9yghbxtxz6hv0bts87k6bq\",\n  \"slug\": \"cargo-hosting\",\n  \"version\": \"1.0.1\",\n  \"publishedAt\": 1786484671338\n}\n\nFile v1.0.1:references/examples/apps.md\n\n# App examples\n\nApps are Vite single-page apps served on `https://<slug>.cargo.app`, scaffolded from `@cargo-ai/app-sdk`.\n\n## Scaffold → create → deploy → promote (end to end)\n\n```bash\n# 1. See what templates exist, then scaffold a local project\ncargo-ai hosting app init ./territories --list-templates\ncargo-ai hosting app init ./territories --template territories-overview --name \"Territories\"\n\n# 2. Create the workspace slot. --slug is the live subdomain → must be globally unique.\ncargo-ai hosting app create --name \"Territories\" --slug territories\n# → { \"uuid\": \"<app-uuid>\", \"slug\": \"territories\", \"url\": \"https://territories.cargo.app\", ... }\n\n# 3. (optional) Develop locally — write the .env.local the app needs, then run Vite\ncargo-ai hosting app env <app-uuid> > ./territories/.env.local\ncd ./territories && npm install && npm run dev\n\n# 4. Build & upload (source = package root, not dist/). The backend runs `npm ci && vite build`.\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./territories\n# → { \"uuid\": \"<deployment-uuid>\", \"status\": \"...\", ... }\n\n# 5. Poll until the build is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n\n# 6. Promote to make it live at https://territories.cargo.app\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n\n# 7. Confirm what's live\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\n```\n\n## List and inspect\n\n```bash\ncargo-ai hosting app list                       # all apps in the workspace\ncargo-ai hosting app list --folder-uuid <uuid>  # only apps in one folder\ncargo-ai hosting app get <app-uuid>             # one app's details + live URL\n```\n\n## Local development env\n\n`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 r\n\nArchive v1.0.0: 8 files, 12256 bytes\n\nFiles: references/examples/apps.md (3246b), references/examples/deployments.md (2276b), references/examples/workers.md (2819b), references/response-shapes.md (3892b), references/troubleshooting.md (3296b), skill-card.md (2953b), SKILL.md (8455b), _meta.json (132b)","readmeExcerpt":"Skill: cargo-hosting Owner: cargo-ai Summary: Put something on the internet from Cargo — hosted web apps (Vite by default, other static frameworks detected) and serverless edge workers that answer HTTP requests, plus the deployments that build and promote them, the env vars and secrets a worker reads, running a worker locally, and custom domains and search indexing for public sites. Triggers: \"build me a dashboard fo","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"npm install -g @cargo-ai/cli            # no global install? prefix every command with `npx @cargo-ai/cli`\ncargo-ai login --email you@company.com  # emailed code, no browser; creates the account on first use\n                                        # alternatives: --oauth (browser) · --token <api-token> (CI)\ncargo-ai whoami                         # confirm the active workspace before any write"},{"language":"text","snippet":"init (local scaffold) → create (slot + slug) → deployment create (build+upload) → deployment promote (go live)"},{"language":"bash","snippet":"# Discover\ncargo-ai hosting app list                          # all apps (filter with --folder-uuid <uuid>)\ncargo-ai hosting app get <uuid>                     # one app's details + URL\n\n# Scaffold locally (Vite + @cargo-ai/app-sdk)\ncargo-ai hosting app init ./my-app --list-templates # see available templates, then:\ncargo-ai hosting app init ./my-app --template blank --name \"My App\"\n\n# Create the slot (slug unique per workspace; `url` in the response is the live host)\ncargo-ai hosting app create --name \"My App\" --slug my-app --folder-uuid <folder-uuid>\n\n# Print .env.local for local development\ncargo-ai hosting app env <app-uuid>\ncargo-ai hosting app env <app-uuid> --api-url https://api.getcargo.io\n\n# Update / remove\ncargo-ai hosting app update --uuid <app-uuid> --name \"Renamed\"\ncargo-ai hosting app update --uuid <app-uuid> --folder-uuid null   # move to workspace root\ncargo-ai hosting app remove <app-uuid>                             # also removes its deployments"},{"language":"bash","snippet":"curl -X POST \"$CARGO_API_BASE/v1/hosting/custom-domains\" \\\n  -H \"authorization: Bearer $CARGO_API_TOKEN\" -H \"content-type: application/json\" \\\n  -d '{\"kind\":\"app\",\"appUuid\":\"<uuid>\",\"hostname\":\"www.example.com\"}'"},{"language":"bash","snippet":"curl -X POST \"$CARGO_API_BASE/v1/hosting/custom-domains/<domain-uuid>/refresh-status\" \\\n  -H \"authorization: Bearer $CARGO_API_TOKEN\"                                   # repeat until status is \"active\""},{"language":"bash","snippet":"CARGO_API_BASE=$(cargo-ai whoami | jq -r '.baseUrl')   # https://api.getcargo.io in production\ncurl -X POST \"$CARGO_API_BASE/v1/hosting/custom-domains\" \\\n  -H \"authorization: Bearer $CARGO_API_TOKEN\" -H \"content-type: application/json\" \\\n  -d '{\"kind\":\"app\",\"appUuid\":\"<uuid>\",\"hostname\":\"www.example.com\"}'\n# → DNS records to add: certificate validation records + a cnameTarget for the hostname\ncurl -X POST \"$CARGO_API_BASE/v1/hosting/custom-domains/<domain-uuid>/refresh-status\" \\\n  -H \"authorization: Bearer $CARGO_API_TOKEN\"                                   # repeat until status is \"active\""}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: cargo-hosting\ndescription: \"Put something on the internet from Cargo — hosted web apps (Vite by default, other static frameworks detected) and serverless edge workers that answer HTTP requests, plus the deployments that build and promote them, the env vars and secrets a worker reads, running a worker locally, and custom domains and search indexing for public sites. 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\\\", \\\"ship a UI for my team\\\", \\\"give my worker an API token\\\", \\\"set a secret on the worker\\\", \\\"Missing CARGO_API_TOKEN\\\", \\\"my app cannot call my worker\\\", \\\"run the worker locally\\\", \\\"put it on my own domain\\\", \\\"make the site indexable by Google\\\". Skip when: the app or worker should be declared as committed workspace code — use cargo-project.\"\nversion: \"1.1.1\"\ncompatibility: 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\nhomepage: https://github.com/getcargohq/cargo-skills\nmetadata:\n  author: getcargo\n  openclaw:\n    requires:\n      bins:\n        - cargo-ai\n    install:\n      - kind: node\n        package: \"@cargo-ai/cli@latest\"\n        bins:\n          - cargo-ai\n    homepage: https://github.com/getcargohq/cargo-skills\n---\n\n# Cargo CLI — Hosting\n\n**Cargo Hosting** runs two kinds of workspace-scoped resources, plus the deployments that ship them:\n\n- **App** — a static front end (a Vite single-page app by default; Next.js static export, Astro, SvelteKit, Nuxt, Gatsby and Create React App are detected too) served on its own subdomain (see [URLs](#urls)). The templates are built on `@cargo-ai/app-sdk` (Vite + refine + shadcn primitives, with `getCargoEnv()` / `useCargoApi()` wired to the workspace).\n- **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`).\n- **Deployment** — one build+upload of a local source directory to an app or worker. A deployment is **not live until it's promoted**.\n\n> 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.\n\n> See `references/examples/apps.md`, `references/examples/workers.md`, and `references/examples/deployments.md` for end-to-end walkthroughs.\n> See `references/response-shapes.md` for JSON response structures.\n> See `references/troubleshooting.md` for common errors and how to fix them.\n\n## Bootstrap\n\nAlready signed in (`cargo-ai whoami` returns a workspace)? Skip to the next section.\n\n```bash\nnpm install -g @cargo-ai/cli            # no global install? prefix every command with `npx @cargo-ai/cli`\ncargo-ai login --email you@company.com  # emailed code, no browser; creates the account on first use\n"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7by8t6yt9yghbxtxz6hv0bts87k6bq\",\n  \"slug\": \"cargo-hosting\",\n  \"version\": \"1.1.1\",\n  \"publishedAt\": 1790272603670\n}"},{"path":"references/examples/apps.md","content":"# App examples\n\nApps are static front ends (Vite single-page apps by default; other frameworks are detected, see `SKILL.md` → App builds) served on `https://<slug>-<workspace prefix>.app.getcargo.run` in production (read the exact host from `url`), scaffolded from `@cargo-ai/app-sdk`.\n\n## Scaffold → create → deploy → promote (end to end)\n\n```bash\n# 1. See what templates exist, then scaffold a local project\ncargo-ai hosting app init ./territories --list-templates\ncargo-ai hosting app init ./territories --template territories-overview --name \"Territories\"\n\n# 2. Create the workspace slot. --slug is unique per workspace; the host adds a workspace suffix.\ncargo-ai hosting app create --name \"Territories\" --slug territories\n# → { \"uuid\": \"<app-uuid>\", \"slug\": \"territories\", \"url\": \"https://territories-1a2b3c4d.app.getcargo.run\", ... }\n\n# 3. (optional) Develop locally — write the .env.local the app needs, then run Vite\ncargo-ai hosting app env <app-uuid> > ./territories/.env.local\ncd ./territories && npm install && npm run dev\n\n# 4. Build & upload (source = package root, not dist/). The backend runs `npm ci --ignore-scripts`,\n#    then the app's `build` script (or the framework default, `vite build` here).\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./territories\n# → { \"uuid\": \"<deployment-uuid>\", \"status\": \"...\", ... }\n\n# 5. Poll until the build is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n\n# 6. Promote to make it live at the app's `url`\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n\n# 7. Confirm what's live\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\n```\n\n## List and inspect\n\n```bash\ncargo-ai hosting app list                       # all apps in the workspace\ncargo-ai hosting app list --folder-uuid <uuid>  # only apps in one folder\ncargo-ai hosting app get <app-uuid>             # one app's details + live URL\n```\n\n## Local development env\n\n`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.\n\n```bash\n# Default API URL (https://api.getcargo.io)\ncargo-ai hosting app env <app-uuid> > ./my-app/.env.local\n\n# Point at a different API (e.g. a staging environment)\ncargo-ai hosting app env <app-uuid> --api-url https://api.staging.getcargo.io > ./my-app/.env.local\n```\n\n## A public, indexable site\n\n```bash\ncargo-ai hosting app init ./site --template public-site --name \"Example\"\n# edit the www.example.com canonicals, robots.txt and sitemap.xml to your real domain FIRST\ncargo-ai hosting app create --name \"Example\" --slug site\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./site   # runs the template's prerendering build script\n# poll, promote, then attach a custom domain (API) — the default host is noindex\n```\n\nThe template's `build` script prerenders each route to `<route>.html`. Link pages by those `.html` paths, because extension"},{"path":"references/examples/deployments.md","content":"# Deployment examples\n\nA deployment is one build+upload of a local source directory to an app or worker. Two facts drive everything below:\n\n1. A deployment belongs to **exactly one** app or worker — `--app-uuid` and `--worker-uuid` are mutually exclusive.\n2. **Building is not promoting.** `deployment create` builds; the live URL only moves when you `deployment promote`.\n\n## Create a deployment\n\n```bash\n# App: backend runs `npm ci --ignore-scripts` then the app's `build` script (or the framework default) in a sandbox\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app\n\n# Worker: backend bundles the entrypoint\ncargo-ai hosting deployment create --worker-uuid <worker-uuid> --source ./my-worker\n```\n\n- `--source` is the **package root** (where `package.json` lives), not a pre-built `dist/`. The build happens server-side.\n- Default ignore list: `node_modules,dist,build,.git,.next`. Override the whole list with `--ignore`:\n\n```bash\ncargo-ai hosting deployment create --app-uuid <app-uuid> --source ./my-app \\\n  --ignore \"node_modules,dist,build,.git,.next,coverage,.turbo\"\n```\n\n## Poll the build, then promote\n\n```bash\n# Builds are async — poll until the status field is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n# when terminal (built/succeeded), promote:\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n```\n\nIf 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.\n\n## List deployment history\n\n```bash\ncargo-ai hosting deployment list --app-uuid <app-uuid>       # newest first\ncargo-ai hosting deployment list --worker-uuid <worker-uuid>\n```\n\n## See what's currently live\n\n```bash\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\ncargo-ai hosting deployment get-promoted --worker-uuid <worker-uuid>\n```\n\n## Roll back to a previous deployment\n\nPromotion just points the live URL at a deployment, so rolling back is promoting an older one — no rebuild needed.\n\n```bash\n# 1. Find the deployment you want to go back to\ncargo-ai hosting deployment list --app-uuid <app-uuid>\n\n# 2. Promote it\ncargo-ai hosting deployment promote --uuid <older-deployment-uuid>\n\n# 3. Verify\ncargo-ai hosting deployment get-promoted --app-uuid <app-uuid>\n```"},{"path":"references/examples/workers.md","content":"# Worker examples\n\nWorkers 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`.\n\n## Scaffold → create → deploy → promote (end to end)\n\n```bash\n# 1. Scaffold a local worker project\ncargo-ai hosting worker init ./my-api --list-templates\ncargo-ai hosting worker init ./my-api --template blank --name \"My API\"\n\n# 2. Create the workspace slot. --slug is unique per workspace; the host adds a workspace suffix.\ncargo-ai hosting worker create --name \"My API\" --slug my-api\n# → { \"uuid\": \"<worker-uuid>\", \"slug\": \"my-api\", \"url\": \"https://my-api-1a2b3c4d.worker.getcargo.run\", ... }\n\n# 2b. (only if the worker calls the Cargo API) give it a token — see \"Env vars and the API token\" below\n\n# 3. Build & upload (source = package root). The backend bundles the entrypoint.\ncargo-ai hosting deployment create --worker-uuid <worker-uuid> --source ./my-api\n# → { \"uuid\": \"<deployment-uuid>\", \"status\": \"...\", ... }\n\n# 4. Poll until the build is terminal\ncargo-ai hosting deployment get <deployment-uuid>\n\n# 5. Promote to go live\ncargo-ai hosting deployment promote --uuid <deployment-uuid>\n\n# 6. Confirm what's live, then hit it\ncargo-ai hosting deployment get-promoted --worker-uuid <worker-uuid>\ncurl \"$(cargo-ai hosting worker get <worker-uuid> | jq -r .url)/openapi.json\"\n```\n\n## List and inspect\n\n```bash\ncargo-ai hosting worker list                       # all workers\ncargo-ai hosting worker list --folder-uuid <uuid>  # only workers in one folder\ncargo-ai hosting worker get <worker-uuid>          # one worker's details + URL\n```\n\n## Templates\n\n```bash\ncargo-ai hosting worker init ./tmp --list-templates\n```\n\n- **`blank`** — edge worker on `@cargo-ai/worker-sdk` with automatic OpenAPI 3.1 spec at `/openapi.json` and Swagger UI at `/docs`.\n- **`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.\n\n## Rename, move, remove\n\n```bash\ncargo-ai hosting worker update --uuid <worker-uuid> --name \"Renamed Worker\"\ncargo-ai hosting worker update --uuid <worker-uuid> --folder-uuid <folder-uuid>\ncargo-ai hosting worker update --uuid <worker-uuid> --folder-uuid null   # back to root\ncargo-ai hosting worker remove <worker-uuid>                            # also removes its deployments\n```\n\n## Env vars and the API token\n\n`createCargoApi(c.env)` needs a `CARGO_API_TOKEN`, and Cargo does not inject one. Mint a token, then store it as a **secret** env var **before** deploying:\n\n```bash\ncargo-ai workspaceManagement token create --name \"worker: my-api\"      # value shown once\nexport CARGO_API_TOKEN=<token value>\n\n# Option A — workspace-wide: every worker (and app) in the workspace inherits it\ncargo-ai workspaceManagement envVar crea"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":2005,"uniquenessScore":31,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T18:49:48.704Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T18:49:48.704Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T21:51:06.681Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}