Deploying with an agent
Read this first when an autonomous coding agent needs the deploy flow for a Cloudbed capsule.
Fast path
Fresh project:
npx cloudbed new my-app --template todo
cd my-app
npx cloudbed deploy --json
Existing project:
cd existing-app
npx cloudbed init . --template todo --json
npx cloudbed deploy --json
cloudbed init [dir] [--template todo|guestbook] scaffolds into an existing
directory, including a non-empty one. It never overwrites files, merges the
cloudbed dependency into an existing package.json, and supports --json.
With no auth, cloudbed deploy --json creates an anonymous deploy. No account is
required. The response includes a live URL.
{
"deployId": "dep_...",
"url": "https://example.cloudbed.app",
"name": "todo",
"mode": "anonymous",
"claimed": false,
"createdAt": "2026-07-02T00:00:00.000Z",
"updatedAt": "2026-07-02T00:00:00.000Z",
"expiresAt": "2026-07-09T00:00:00.000Z",
"claimToken": "cb_claim_...",
"claimUrl": "https://dashboard.cloudbed.dev/claim?token=...",
"inspectToken": "cb_inspect_..."
}
Save these fields:
| Field | Why |
|---|---|
claimToken |
One-time secret returned only on anonymous create. Needed to claim the deploy. |
inspectToken |
Secret returned only on create. Needed by cloudbed inspect and private inspect routes. |
deployId |
Stable deploy id. Needed to update, inspect by id, or recover from lost local context. |
url |
Live app URL. Use it for verification and handoff. |
The CLI auto-persists deploy state to .cloudbed/deploy.json with api,
deployId, claimToken, and inspectToken. Keep .cloudbed/ gitignored. If a
deploy is owned or claimed, the CLI writes cloudbed.json; commit that file so
future deploys from the directory update the same app.
Auth for agents
Use CLOUDBED_TOKEN for non-interactive auth. It is a bearer token, checked
before ~/.cloudbed/auth.json, and works for deploy, claim, whoami,
token, domains, and inspect.
export CLOUDBED_TOKEN="cb_..."
cloudbed whoami --json
To validate and persist a token for later commands:
cloudbed login --token "$CLOUDBED_TOKEN"
To mint tokens for automation:
cloudbed token create --name agent-ci --json
cloudbed token create --name agent-deploy --deploy --json
--deploy scopes the token to the current directory's deploy. The token value is
shown once; store it as a secret.
| Mode | What works | What is blocked |
|---|---|---|
| Anonymous | Live URL with no account; redeploy from the same local state. | No outbound fetch, no server env, expires 7 days after the last update. |
| Claimed/owned | No expiry, outbound fetch, .env.cloudbed.server sync on deploy, owner operations. |
Requires owner credentials. |
State files
| File | Commit? | Contents | Agent rule |
|---|---|---|---|
cloudbed.json |
Yes | Committed deploy binding, including deployId. |
Keep it when the project should update the same owned deploy. |
.cloudbed/deploy.json |
No | Local deploy secrets: api, deployId, claimToken, inspectToken. |
Treat as secret; require .cloudbed/ in .gitignore. |
~/.cloudbed/auth.json |
No | User/API login profiles by API origin. | Prefer CLOUDBED_TOKEN in automation; login --token writes here. |
Error handling
Run commands with --json. On failure, JSON commands print an error envelope to
stderr and exit nonzero:
{"error":{"code":"invalid_artifact","message":"artifact.format must be \"cloudbed.capsule.v1\"."}}
Branch on error.code, not the message.
| Code | Meaning | Agent action |
|---|---|---|
unknown_op |
Protocol operation is not recognized. | Fix the client/protocol version or operation name; do not retry unchanged. |
unknown_query |
Query name is not in the deployed artifact. | Inspect the manifest, fix the query name, or redeploy the server. |
unknown_mutation |
Mutation name is not in the deployed artifact. | Inspect the manifest, fix the mutation name, or redeploy the server. |
unknown_endpoint |
HTTP endpoint is not in the deployed artifact. | Fix the method/path or redeploy with that endpoint. |
handler_error |
Capsule server code threw during a query, mutation, or endpoint. | Inspect logs, fix server code, redeploy. |
quota_exceeded |
A deploy quota was exceeded. | Claim if anonymous, reduce usage/data, or wait for daily counters; avoid tight retries. |
rate_limited |
A platform rate limit was hit. | Back off, wait, reuse an existing deploy, or use account auth. |
invalid_message |
Command input, request body, or protocol message is malformed. | Fix arguments or JSON shape; do not retry unchanged. |
invalid_artifact |
Deploy artifact or env payload is invalid. | Rebuild, fix schema/bundles/endpoint paths, then deploy again. |
not_found |
Deploy, route, token, domain, or session was not found. | Check ids and local state; recreate or redeploy if stale. |
unauthorized |
Bearer, claim, or inspect credential is missing or invalid. | Set CLOUDBED_TOKEN, login, refresh the token, or restore .cloudbed/deploy.json. |
forbidden |
The credential is valid but not allowed for the operation. | Claim the deploy, use owner credentials, or stop the unsupported action. |
payload_too_large |
Bundle, env, request body, or row value is too large. | Shrink the payload/env/data and redeploy. |
internal |
Platform or auth service failed internally. | Retry with backoff; report if it persists. |
not_configured |
The platform lacks configuration for the requested feature. | Skip that feature or target a configured platform. |
upstream_error |
An upstream provider failed or rejected the request. | Retry with backoff; verify DNS/provider inputs. |
Limits
Storage and handler caps apply to every deploy. Daily counters apply only to anonymous deploys and disappear on claim.
| Limit | Value |
|---|---|
| Deploy payload (bundled server + client + optional SSR) | 4 MB |
| State size | 1 MB |
| State rows | 16,384 |
| Serialized row size | 64 KB |
| Rows returned per query | 1,000 |
| HTTP endpoint request body | 2 MB |
| Handler wall-clock time | 10 s |
| Log retention | 1,000 entries / 256 KB |
| Endpoint requests / day (anonymous only) | 10,000 |
| Mutations / day (anonymous only) | 1,000 |
| Anonymous deploys per IP / day | 50 |
| Server env (claimed only) | 64 keys, 16 KB per value, 64 KB total |
Verify it worked
deploy_json="$(cloudbed deploy --json)"
url="$(node -e 'console.log(JSON.parse(process.argv[1]).url)' "$deploy_json")"
curl -fsS "$url"
cloudbed inspect --json
For capsule({ ssr: true }) apps, curl -fsS "$url" includes the rendered app
markup and the embedded __cloudbed_state__ snapshot. For CSR apps it still
returns the boot shell, so use the inspect manifest and app-specific HTTP or WS
checks for deeper verification.
cloudbed logs --json shows what the server code actually did (ctx.log
entries; add --follow to stream while you exercise the app). If the new
deploy is broken, cloudbed releases --json + cloudbed rollback restore the
previous release in one command — then fix and redeploy.