⏳ This skill is pending AI review.
Scores will appear once the review pipeline completes.
cloudish
Cloudish deploys apps as long-lived containers with a public URL, such as websites, APIs, bots, workers and MCP servers. It builds server-side from a Dockerfile or source folder (no local Docker daemon), or runs an existing image, with an optional persistent volume. An AI agent creates its own API key with one call and no signup; credits are prepaid and metered per second, so spend never exceeds the key's balance. Use when a task involves deploying, hosting or putting an app online, and whenever a task names Cloudish.
Choose how to use this skill
You do not need every option. Choose the path your AI client supports. The stable page stays the same; versioned files are immutable.
1. Native installer
This listing has no registered native installer command. Use the complete package or source fallback below, depending on what your client supports.
Do not guess an installer command or replace an existing version without reviewing the diff.
2. Complete package recommended
Download the ZIP when available. It includes SKILL.md plus the references, security notes and version metadata.
No complete ProSkills package is published for this listing yet.3. Prompt-only
Copy the prompt above when the agent can read the stable page or when you want to adopt the workflow without installing a skill.
Need only the instruction file?
Download SKILL.md only if your client requires a single file. The complete ZIP is safer for a full installation because it preserves the references and release context.
No path installs or executes anything by itself. Your agent still needs access to the project files. Before updating, compare the installed version and review the diff.
// RATINGS
Not yet listed on ClawHub or SkillsMP
// README
Cloudish lets an agent create its own API key with one unauthenticated call, build any Dockerfile or source folder server-side, and run it as a long-lived container with an optional persistent volume, paid from prepaid credits the key can never exceed. No browser, no card, no local Docker.
Skills
| Skill | What it does |
|---|---|
cloudish | Prepares a project, deploys it to Cloudish, and reports the live URL. |
The skill is a copy of https://cloudish.ai/skill.md and the docs it links to (credits, instances, replicas, container isolation, changelog), bundled so the agent reads them locally. It never fetches instructions at runtime; new versions ship as new releases of this plugin.
What it runs and sends
The plugin contains instructions only: no MCP server, hooks, scripts, or
binaries. When you ask it to deploy, the agent uses curl and tar to call
the Cloudish API at https://cloudish.ai, and to check that your deployed app
answers at its own URL (https://<name>.cloudish.app/, or your own domain):
- Sends a
.tar.gzof the project folder (excluding.gitand.env*) to Cloudish to be built and hosted, plus the project name, port, how it should run (always on, or sleeping when idle), and any env vars or secrets you ask it to set. - Creates a Cloudish API key with an unauthenticated call when the
project doesn't have one yet. The key is used only to authenticate API calls
to
cloudish.ai, and is never printed to chat. - Reuses that key on later runs instead of minting another, so the project keeps the same Cloudish balance. It's a key the skill created on Cloudish, not one of your other credentials. A sub-agent can get its own key, minted and funded by the parent agent's key.
- Reports the agent product and model (for example
claude-code,claude-opus-5-5) when it creates a key, if known, plusskills-repoas the source. All three are optional.
Adding credits happens outside Claude: the agent gives you a one-time
www.cloudish.ai link, and any payment is made on that page in your browser.
If your app signs its users in with Cloudish, that sign-in runs between your
deployed app and www.cloudish.ai, not through the agent.
The bundled docs are generated from the ones served at cloudish.ai, with links between them pointing at the local files.
Your deployed code and data are handled under Cloudish's privacy policy and terms.
Install
Claude Code
/plugin marketplace add cloudishai/skills
/plugin install cloudish@cloudishai
Any agent that reads SKILL.md (Claude Code, Codex, Cursor, …) — copy
the skills/cloudish folder into your agent's skills
directory.
Then ask your agent: "Deploy this app to Cloudish."
In the Claude apps and Cowork, the agent runs in a sandbox: when asked,
allow outbound network access to cloudish.ai (the API) and cloudish.app
(where your deployed apps are served). Keys don't carry over between chats
there, so claim yours (the agent can give you a link) to keep your projects
and credits with your account.
Layout
skills/cloudish/SKILL.md the skill (copy of cloudish.ai/skill.md)
skills/cloudish/*.md the docs it links to, bundled
.claude-plugin/ Claude Code plugin + marketplace manifests
plugin.json OpenAI / Agent Plugins manifest
assets/ icon
License
// HOW IT'S BUILT
// FILES
7 files shipped with this skill. Inline text is the catalog copy. The upstream link is the source repository.
skills/cloudish/SKILL.md23 KB7f530a814f9cupstream ↗
--- name: cloudish description: Cloudish deploys apps as long-lived containers with a public URL, such as websites, APIs, bots, workers and MCP servers. It builds server-side from a Dockerfile or source folder (no local Docker daemon), or runs an existing image, with an optional persistent volume. An AI agent creates its own API key with one call and no signup; credits are prepaid and metered per second, so spend never exceeds the key's balance. Use when a task involves deploying, hosting or putting an app online, and whenever a task names Cloudish. --- # Deploy container apps on Cloudish Last updated 2026-11-06 ([changelog](changelog.md)). Cloudish is an agent-first, API-key/credit, container-deployment platform: it builds images server-side, so no local Docker or `docker build` is needed — a local build is CPU/memory-heavy and often more than the machine you're on can spare, and there's no registry to manage either way. Cloudish hosts a private registry and runs the resulting containers with attached storage. Everything from getting a key to deploying takes only the calls below: nothing to install, no account to create. Never print API keys or secrets into chat, source code or logs. Never report a deploy as succeeded until you've verified it: the build reached `succeeded`, and the app's logs (section 7) show it started and is listening. Try its URL too if you can reach it, but some environments reach cloudish.ai but not the apps' own domain, so a URL you can't open isn't a failure by itself. ## 0. Get an API key Creating a key itself needs no credential — every other call below authenticates with the key it returns (`Authorization: Bearer $CLOUDISH_API_KEY`). New keys include 0.1 credits to start, subject to availability. Mint new keys or delegate credits from one you have, as fits: a sub-agent or container that needs its own credential gets a key under yours, funded by transfer (credits.md). ```bash curl -X POST https://cloudish.ai/api/v1/keys -H "content-type: application/json" \ -d '{"alias": "<alias>", "agent": "<agent>", "model": "<model>", "ref": "skills-repo"}' ``` The key comes back in the response: ```json { "apiKey": { "alias": "my-app", "balance": 0.1, ... }, "key": "cld_****", "claimUrl": "https://..." } ``` `key` authenticates every call below (`Authorization: Bearer $CLOUDISH_API_KEY`). If you already have a key for this work (from an earlier run, or one your environment provides), reuse it instead of minting another. Claiming is optional: `claimUrl` attaches this key to the Cloudish account of whoever opens it and signs in, for a dashboard and adding credits. It works once and expires in 30 minutes; `GET /api/v1/credits/claim` returns a new one (section 9). `alias` is optional: a short name for what you're deploying (e.g. `todo-app`) makes a good one, or leave it out for a random one. You get that name if it's free, or a close variant (e.g. `my-app-otter`) if not, and it can be renamed later (`PATCH /api/v1/me`). Use the `apiKey.alias` that comes back, the `{alias}` in every project path below. `agent`, `model` and `ref` are all optional; leave out any you don't know. `agent` is the product you run in (`claude-code`, `claude`, `chatgpt`, `codex`, `cursor`, `grok`, ...), `model` the model you are (`claude-opus-5-5`, `gpt-5.5`, ...), and `ref` the plugin, directory or link this document came from (`claude-plugin`, `chatgpt-plugin`, `codex-plugin`, `mcp.so`, `producthunt`, ...) — leave it out rather than guess. They only show Cloudish which agents and channels use it. Keep `ref` as shown: it only tells Cloudish which link sent you here. ## 1. Create (or update) a project and deploy it — one call `POST /api/v1/projects` creates the project if it doesn't exist yet (or updates it if it does — same call either way, so a redeploy script can always call this unconditionally), and optionally attaches an image in the same request. Two ways to attach one, mutually exclusive: **An image you already have** — registered immediately: ```bash curl -X POST https://cloudish.ai/api/v1/projects \ -H "Authorization: Bearer $CLOUDISH_API_KEY" -H "content-type: application/json" \ -d '{"name": "my-app", "image": "ghcr.io/acme/my-app:1.0.0", "port": 8080, "alwaysOn": true}' # -> { "project": { "path": "your-alias/my-app", ... }, "app": { "status": "registered", ... }, # "subdomain": { "url": "https://<token>.cloudish.app/", ... } } ``` **Build from source** — upload a tar.gz build context (must contain a `Dockerfile` at its root). The build runs server-side, not on your own machine — send the context as-is rather than running `docker build` locally first. Once it succeeds, the project's docker app is registered automatically — no second call needed. This context is uploaded to Cloudish's own servers, the same as any build-from-source platform — exclude anything secret-shaped from it first (`.env` files, credentials, `.git`) and use section 2's encrypted secrets endpoint for real credentials instead, never a file baked into the context: ```bash tar --exclude='.env*' --exclude='.git' -czf context.tar.gz . curl -X POST https://cloudish.ai/api/v1/projects \ -H "Authorization: Bearer $CLOUDISH_API_KEY" \ -F "name=my-app" -F "port=8080" -F "sleepAfterMinutes=30" -F "[email protected]" # -> { "project": { "path": "your-alias/my-app", ... }, "build": { "id": 123, "status": "running" } } ``` **Choose how it runs** on every deploy, since the right answer depends on the app: - `"alwaysOn": true` runs it around the clock, billed the whole time, and starts it as soon as it's deployed: for a site or API that must answer at once, or a bot or worker that nothing sends requests to. - `"sleepAfterMinutes": 30` (1 to 1440; 15 if you choose neither) puts it to sleep after that long without requests, billed only while awake; the next request wakes it in seconds. Add `"wakeEveryMinutes": 60` (5 to 10080) to also wake it on a schedule: a bot that polls then runs every hour until it sleeps again. Left out on a redeploy, each keeps the app's own. Change them without a redeploy: `PATCH https://cloudish.ai/api/v1/projects/{owner}/{name}` with the same fields. An always-on app's `runway.alwaysOnHoursLeft` says how long its balance keeps it running. `port` defaults to `8080` and must be the port your server listens on, whatever the Dockerfile's `EXPOSE` says: an nginx image listens on `80`, so send `port=80` for one. Get it wrong and requests answer `503` with "nothing accepts connections on port …". The build runs with `cpuCores: 3`/ `memoryGb: 5` by default. If it dies with no error beyond `"Job has reached the specified backoff limit"`, that's usually resource exhaustion rather than a Dockerfile problem — retry with more of both as extra form fields, one of `0.5`, `1`, `2`, `3` cpu cores (`buildCpuCores`) and `1`, `2`, `4`, `5` GB memory (`buildMemoryGb`). Poll until it settles: ```bash curl https://cloudish.ai/api/v1/images/builds/123 -H "Authorization: Bearer $CLOUDISH_API_KEY" # -> { "build": { "status": "running", "logs": "<build output so far>" }, "image": null } ``` Poll only while `status` is `"running"`: that's the only state a build in progress is in, so anything else — `"succeeded"`, `"failed"`, or a response with no status at all — is the end. `build.logs` is the current tail of what the build is doing — it grows on every poll while the build runs, so print only the lines you haven't shown yet. On `"failed"`, show both `build.error` and the tail of `build.logs`. Once `"succeeded"`, the project's docker app is already registered and its subdomain already provisioned — fetch `GET https://cloudish.ai/api/v1/projects/{owner}/{name}` for the resulting `subdomain.url`, no separate subdomain call needed. Other docker-app fields available on either path: `env` (JSON object of non-secret vars), `volumeEnabled`/`volumeSizeGb`/`volumeMountPath` (persistent storage), `cpuCores`/`memoryGb` (container size, distinct from the build's own), `maxBodyMb` (the largest request body the app accepts, 64 MB unless set, at most 1024; a bigger one gets `413` before it reaches the app, so raise it for large uploads). To run many isolated copies of the same app — one sandbox per user, task or agent — see [replicas.md](replicas.md). Left out, a new app gets the default size, `shared`: billed for 0.1 CPU and 0.2 GB, using up to 1 CPU and 1 GB when the machine has them spare, and the first to restart when it runs short. Apps that must not restart, run a database inside the container, or need their full memory all the time (a Next.js server, Streamlit) run better on `small` or larger. Left out on an existing app, its size stays as it is. The response's `app.resources` shows the size an app runs at and its `creditsPerHour`. Sizes and pricing: [instances.md](instances.md). Either way, unless this deployment has no run domain configured, the app is already reachable — a permanent URL is provisioned automatically, returned as `subdomain.url` above. It's `https://<name>.cloudish.app/` and keeps working whichever datacenter serves the app: save and share that one. See section 4 to swap the random URL for a memorable one, rotate it, or turn it off. To take a deployment down, `DELETE /api/v1/projects/{owner}/{name}` stops the container and its billing, and deploying the same name again later starts fresh. A volume is deleted with the project, so its data is gone. ## 2. Environment variables and secrets Non-secret config goes in `env` on the same call as above: ```bash curl -X POST https://cloudish.ai/api/v1/projects \ -H "Authorization: Bearer $CLOUDISH_API_KEY" -H "content-type: application/json" \ -d '{"name": "my-app", "image": "ghcr.io/acme/my-app:1.0.0", "port": 8080, "env": {"LOG_LEVEL": "debug"}}' ``` Anything sensitive — API keys, tokens, passwords — is set separately here, encrypted at rest, and merged into the container's environment automatically. Never put these in `env` above, and never bundle them into the build context in section 1 either: ```bash curl -X PUT https://cloudish.ai/api/v1/projects/YOUR_ALIAS/my-app/secrets \ -H "Authorization: Bearer $CLOUDISH_API_KEY" -H "content-type: application/json" \ -d '{"name": "OPENAI_API_KEY", "value": "sk-..."}' ``` For *human* login, OIDC authentication is available (section 5). Several at once take the same shape as `env`: `-d '{"OPENAI_API_KEY": "sk-...", "STRIPE_KEY": "sk_live_..."}'`. Saving or deleting secrets restarts a running app with the new values; an idle one gets them when it next starts. `GET …/secrets` lists names (never values); `DELETE …/secrets/NAME` removes one. ## 3. Persistent storage Request a volume when creating or updating the app: ```bash curl -X POST https://cloudish.ai/api/v1/projects \ -H "Authorization: Bearer $CLOUDISH_API_KEY" -H "content-type: application/json" \ -d '{"name": "my-app", "image": "ghcr.io/acme/my-app:1.0.0", "port": 8080, "volumeEnabled": true, "volumeSizeGb": 5, "volumeMountPath": "/data"}' ``` `volumeSizeGb` must be one of 1, 5 or 20; `volumeMountPath` defaults to `/data`. A volume can only attach to one container, so an app with one can't run replicas. ## 4. Customize the subdomain, or use your own domains Section 1 already provisioned a permanent URL automatically once the image registered — `subdomain.url` in that response, or `{identifier}` below is a random 32-character lowercase-hex string, unique by construction. This section is for changing it afterwards, not for getting one in the first place. If the app is public-facing and a memorable name matters, set your own instead (non-private projects only): ```bash curl -X PUT https://cloudish.ai/api/v1/projects/YOUR_ALIAS/my-app/subdomain \ -H "Authorization: Bearer $CLOUDISH_API_KEY" -H "content-type: application/json" \ -d '{"label": "anamazingapp"}' # -> { "subdomain": { "url": "https://anamazingapp.cloudish.app/", ... } } ``` `label` must be 1-63 characters: lowercase letters, digits and hyphens, not starting or ending with a hyphen. A `503` on this call means this deployment has no wildcard run domain configured. Names are global: a `409` means another datacenter's app already has this one, so pick another. Leaked the URL? `POST .../subdomain/rotate` issues a fresh one. Want the app unreachable from the outside entirely (API-only)? `DELETE .../subdomain` tears it down; a later redeploy will provision a new one automatically the same way the first did. A request to the subdomain carries the same `Authorization: Bearer $CLOUDISH_API_KEY` as everything else in this doc; an `open` (the default) or `public` project also answers with no credential at all, billed to its owner. This platform doesn't mediate identity for the container itself — no trusted headers, nothing — that's the image's own job to configure if it wants one. A sleeping app (section 1) starts on the next request. ### Your own domains A project can also answer at any number of domains you control. Add each one (`foobar.com`, `www.foobar.com`, ...) to the same project: ```bash curl -X POST https://cloudish.ai/api/v1/projects/YOUR_ALIAS/my-app/domains \ -H "Authorization: Bearer $CLOUDISH_API_KEY" -H "content-type: application/json" \ -d '{"host": "foobar.com"}' # -> { "domain": { "host": "foobar.com", "status": "pending", "redirect": false, # "txtRecord": { "name": "_cloudish-challenge.foobar.com", "value": "cloudish-verify=..." } } } ``` 1. Add the returned TXT record at your DNS provider. It's checked every minute; once it matches, the domain turns `active` and stays that way. It's only checked once, so the record can be removed afterwards. 2. Point the domain at do.cloudish.ai: a `CNAME` for a subdomain like `www`; an apex (`foobar.com`) can't be a CNAME at most providers, so use an `A` record to that host's IP address (`dig +short do.cloudish.ai`), or your provider's CNAME flattening/ALIAS if it has one. The certificate issues once both steps are done. 3. To have one domain send visitors to the other instead of serving the app twice, add it with `"redirect": true` (or `PATCH .../domains/www.foobar.com {"redirect": true}` later). It 308s to the project's primary domain: its oldest active domain that doesn't redirect, or its subdomain if there's none. `GET .../domains` lists them; `DELETE .../domains/{host}` removes one. Each active domain costs 0.01 credits a day. Adding one needs a positive balance; at most 10 can be added per hour and 20 be pending at once. A `409` means another project already holds that host. A request to an out-of-credit project returns `402` (JSON) instead of starting the container — a plain browser page load gets a `503` status page instead — see [credits.md](credits.md) for adding credits, especially across several projects. Ask the platform admin to grant more via `POST /admin/v1/credits/grant`, or, for a sub-agent's key, get a hand from the parent key that minted it — the parent transfers some of its balance to yours by alias, authenticating with its own key, no admin needed: `curl -X POST https://cloudish.ai/api/v1/credits/transfer -H "Authorization: Bearer $PARENT_API_KEY" -H "content-type: application/json" -d '{"to":"<your-alias>","amount":1}'`. ## 5. Building containers — any language, any framework Cloudish doesn't care what's inside the image — it just runs whatever listens on `port` and reverse-proxies to it, adding no CORS headers of its own: set them in your app if a browser on another origin calls it. How containers are isolated: [container.md](container.md). Bring any Dockerfile: - **JavaScript/TypeScript** — Express, Fastify, NestJS, or a Next.js app in standalone/server mode. - **Python** — FastAPI or Django/Flask for an API; Streamlit or Gradio for a quick data app or dashboard (bind to `0.0.0.0` and the port from your own env var, not `localhost`, or the proxy can't reach it). - **Go** — a plain `net/http` server, Gin, or Echo — compiles to a single static binary, which makes for the smallest, fastest-starting images. Anything else that speaks HTTP on one port works the same way — these are just the common cases. ### A database that persists Cloudish has no managed Postgres/MySQL offering. A database running in your own app, with its data on a volume (section 3), is a normal, working setup: the container restarts, the volume keeps the data. - **SQLite** — simplest option for most apps: point your app at a file under the mounted volume (e.g. `$DATA_DIR/app.db`). No extra process. - **Postgres** — add the `postgresql` package to your image. On container start (not at build time), initialize a subdirectory of the mounted volume with `initdb` if it isn't initialized yet, start the server with `pg_ctl`, then idempotently create your role/database if missing (this runs on every boot, so it has to be a no-op after the first). Run schema migrations at startup too, since the database only exists once the container is actually running. Recreate `/var/run/postgresql` before starting — Kubernetes remounts `/var/run` as an empty directory on every container start. Generate any long-lived secret (session signing key, etc.) once and save it onto the same volume, so it survives restarts instead of rotating every redeploy. The data outlives the app: a zero balance stops it (the app's status becomes `out_of_credits`) but the volume, with everything on it, is kept and isn't billed, and the app starts again once credits are added. Deleting the project is what destroys the data (section 1). If you want backups, add admin endpoints to the app that stream a backup (`pg_dump`, or a copy of the SQLite file) for download and accept one back to restore — behind a secret (section 2), since they can read and overwrite the data. To take them automatically, send the same file on a schedule to something you already have — Google Drive, Dropbox, an S3-compatible bucket — or to another app of yours in a different Cloudish datacenter. What Cloudish commits to about that data — what it collects, where it's processed, how long it's kept — is in the privacy policy: https://cloudish.ai/privacy.md. ### Authentication: user sign-in and admin panels (OIDC) If your app needs to know who's visiting it — an end-user login, or a single admin panel — point it at Cloudish's own OpenID Connect provider instead of running your own identity system — a standard discovery document, Authorization Code + PKCE, no client secret to manage: ``` GET https://www.cloudish.ai/.well-known/openid-configuration ``` Many off-the-shelf apps take this directly (e.g. a generic `OIDC_ISSUER`/`OPENID_PROVIDER_URL` setting) with zero code. If you're writing the login flow yourself: redirect a signed-out visitor to `https://www.cloudish.ai/oauth/authorize?client_id=<anything>&redirect_uri=<your subdomain>/callback&response_type=code&code_challenge=<S256 of a random verifier>&code_challenge_method=S256&state=...`, then exchange the `code` your callback receives at `POST https://www.cloudish.ai/oauth/token` (with the PKCE verifier) for an `id_token` carrying `sub`/`email`/`name`. `redirect_uri` must be under your project's subdomain or one of its active custom domains (section 4). Authenticating the visitor is not the same as authorizing them: any Cloudish user can complete this flow, so an admin panel still needs its own allowlist of `email`/`sub` claims and must reject everyone else. The platform adds no trusted headers to the request (section 4) — verify the `id_token` in your app. Build `redirect_uri` from the host the request came in on, not from a fixed URL. An app can answer on more than one hostname (apps created before their URLs moved to `cloudish.app` also keep their older `*.on.<datacenter>.cloudish.ai` one), and a sign-in has to come back to the hostname it started on, where your app set its state cookie. Your app's "Sign out" only ends your app's own session. To also let the visitor sign out of Cloudish (so their next sign-in can pick another account), send them afterwards to `https://www.cloudish.ai/oauth/logout?id_token_hint=<their id_token>&post_logout_redirect_uri=<your subdomain>/&state=...` — Cloudish asks them, then returns them to `post_logout_redirect_uri` (same rule as `redirect_uri`). ## 6. Manage images already in the registry ```bash curl https://cloudish.ai/api/v1/images/registry -H "Authorization: Bearer $CLOUDISH_API_KEY" curl -X DELETE "https://cloudish.ai/api/v1/images/registry/tags?repo=builds/123&tag=v1" \ -H "Authorization: Bearer $CLOUDISH_API_KEY" ``` ## 7. Troubleshoot a deployment Fetch the running container's own stdout/stderr on demand — pulled fresh from the pod on every call, never persisted server-side, so polling it while diagnosing an issue doesn't grow anything: ```bash curl https://cloudish.ai/api/v1/docker/YOUR_ALIAS/my-app/logs -H "Authorization: Bearer $CLOUDISH_API_KEY" # -> { "logs": "--- container logs ---\n...\n--- events ---\n..." } ``` Also includes the previous attempt's output if the container already restarted once, plus recent Kubernetes events (`ImagePullBackOff`, `FailedMount`, ...) — often the actual explanation when a container never gets far enough to write a log line at all. ## 9. Claiming and adding credits Read [credits.md](credits.md) when you perform credit operations — claiming, transfers, or funding more than one project. A key works fine unclaimed — claiming attaches it to a human's own account, which unlocks a dashboard for it (usage, projects, balance) and a way to add credits beyond the free grant. Whether and when that's worth doing is situational: some deployments want a large balance up front, some are fine running on the free grant for a while, some never need more. Bring it up when it's relevant to what you and your human are doing, not on a fixed schedule. Credits are spent only while an app runs: one that sleeps (section 1) costs nothing until it wakes, and an always-on one spends around the clock. More can be added at any time: through the claim link below (for a key already in an account, from that account), or by a transfer from another key. Deploy, `/me` and credits responses carry `runway`: the `balance` and the `creditsPerHour` being spent. `GET /api/v1/credits/claim` (same auth) mints a fresh, single-use link a human can open to attach this key to their own account and add credits to it. Run it yourself and give your human the resulting URL — not the `curl` command for them to run: ```bash curl https://cloudish.ai/api/v1/credits/claim -H "Authorization: Bearer $CLOUDISH_API_KEY" # -> { "url": "https://www.cloudish.ai/claim?challenge=..." } # -> tell your human: "To add credits to <alias>, open: https://www.cloudish.ai/claim?challenge=..." ``` The link works once and expires 30 minutes after it's minted, so mint it at the moment you hand it over (the `claimUrl` from `POST /api/v1/keys` has the same lifetime), and mention that it expires. If your human comes back later, or the page says the link expired, just mint a new one — minting never invalidates an earlier link that's still within its own lifetime. Never hand over `$CLOUDISH_API_KEY` itself — the link alone is what proves the claim, the raw key never needs to leave this session. --- Every change to this document is listed in [changelog.md](changelog.md).skills/cloudish/changelog.md11 KB484ebfe591fdupstream ↗
# Cloudish changelog Every change to the documents agents read (SKILL.md, credits.md, instances.md, replicas.md, container.md and llms.txt) and to API behavior agents rely on. Newest first. SKILL.md's "Last updated" date is the newest entry's. ## 2026-11-06 - SKILL.md section 1's build poll now says to poll **only while `status` is `"running"`**, instead of "stop once `status` is `"succeeded"` or `"failed"`". The old wording listed the two states a loop should end on and said nothing about a response that isn't a build at all — a `401`, a `404`, or a timed-out request has no `status`, which is neither, so a loop written from it never stopped. Naming the one state to keep going on makes every other response the end of the poll. - The source-build deploy example's response shows `"status": "running"`, which is what `POST /api/v1/projects` returns; it said `"pending"`, a state the server does not set. - SKILL.md's database section (now "A database that persists") doesn't frame running the database in your app as a workaround, and says what a zero balance does: the app stops with status `out_of_credits`, the volume and its data are kept and aren't billed, and the app starts again once credits are added. Deleting the project is what destroys the data. - The same section covers backups as an option, not a requirement: the app can expose admin endpoints to download and restore a backup (behind a secret), and automatic backups can go to a service you already have (Google Drive, Dropbox, an S3-compatible bucket) or to another app in a different datacenter. credits.md's "When a key runs out" and container.md's Storage bullet say the same about volumes surviving a zero balance. - SKILL.md's database section ends with where Cloudish's commitments about that data are: the privacy policy, at `/privacy.md`. - llms.txt's Optional list links the legal documents themselves, as text (`/terms.md`, `/privacy.md`), rather than the site's `terms` and `privacy` pages, which render those files. - A `GET` or `HEAD` whose app container can't be reached is sent again after 500ms and once more after 1.5s before answering `502` (`the application is not reachable`). An app with a volume is redeployed with Recreate — its old pod stops before the new one listens — so a page load landing in those few seconds used to get an error it could do nothing about. Other methods, requests whose body is streamed through, and websockets answer as before. Fixes cloudishai/skills#9. The volume and backup notes answer part of cloudishai/skills#10, whose availability and restore questions are still open. ## 2026-11-01 - SKILL.md section 0's example `alias` is `<alias>`, not `<project-name>`: it only labels the key (the `{alias}` half of every project path), so minting one never waits on a project name. The paragraph says you get the name or a close variant, and can rename it later with `PATCH /api/v1/me`. - Section 0 no longer leans on a project that doesn't exist yet at mint time: the alias is "a short name for what you're deploying", and an existing key is one "for this work" rather than "for this project". - SKILL.md section 1 ends with how to take a deployment down: `DELETE /api/v1/projects/{owner}/{name}` stops the container and its billing, and the same name deployed again starts fresh; a volume is deleted with the project, so its data is gone. ## 2026-10-26 - On a datacenter with a GPU, an app can have it: \`"gpu": true\` on deploy, at a flat hourly price while it runs, one GPU app at a time (a \`409\` \`gpu_busy\` while another has it). That datacenter's SKILL.md and instances.md describe it; elsewhere nothing changes. - Each app says how it runs, on deploy (SKILL.md section 1): \`"alwaysOn": true\` keeps it running, billed around the clock, and starts it as soon as it's deployed; otherwise it sleeps after \`sleepAfterMinutes\` without requests (15 unless set) and wakes on the next one, or on a \`wakeEveryMinutes\` schedule, for a bot or worker nothing sends requests to. \`PATCH /api/v1/projects/{owner}/{name}\` changes them without a redeploy. Both deploy examples show a choice, and the agent makes it. - The key-wide \`PATCH /api/v1/me {"settings": {"idleTimeoutSeconds": ...}}\` is no longer documented. It still applies to apps that choose none of these. - An app's \`status\` says why it's down: \`sleeping\`, \`out_of_credits\` (it starts again once its key has credits) or \`stopped\`, and its \`sleep\` how it runs. An always-on app's \`runway\` adds \`alwaysOnHoursLeft\`. - Replicas follow their app's \`sleepAfterMinutes\` (replicas.md), and instances.md and llms.txt describe the choice. ## 2026-10-25 - `PUT /api/v1/projects/{owner}/{name}/secrets` also takes several secrets at once, as a map of names to values like a project's `env`, saved all or none and answered as `{"secrets": [...]}`. One `{"name", "value"}` is unchanged. A body of neither shape gets a 400 naming both. - Saving or deleting secrets restarts a running app with the new values, and leaves an idle one idle. A secret change used to stop the app instead, or reach it only on its next request. - SKILL.md's secrets section says all of this, and how to list (`GET …/secrets`, names only) and delete them. - SKILL.md's description says "An AI agent creates its own API key", not "An agent": "agent" alone can mean a person. ## 2026-10-22 - llms.txt no longer links the website's docs for people, and `GET /api/v1/config` no longer returns a `docs` URL: everything an agent needs is in SKILL.md and its companion documents. ## 2026-10-21 - Minting a key is one `curl` again (SKILL.md section 0), with a sample reply (`"key": "cld_****"`) and what the key is for, with no shell snippet for storing it, and what the reply's `claimUrl` does: whoever opens it and signs in gets the key in their account. Nothing requires claiming. credits.md points there instead of repeating it, and no longer assumes `.env` or `$CLOUDISH_ALIAS`. - The example `alias` is `<project-name>`, not `<project-folder-name>`: a folder's name can say more about the machine than the project. - SKILL.md's intro no longer says Cloudish has no user-facing product (the website has a dashboard): everything from getting a key to deploying takes only the calls it shows, with nothing to install and no account to create. - llms.txt is written for an agent choosing where to deploy: what it needs to finish a deploy with no human (a key, payment, a build, proof it worked, a URL), what runs, what it costs (from the same rates as instances.md), when another platform fits better, and AI Deploy Bench, an open-source benchmark run by Cloudish. It's the only llms.txt: the website serves a copy of it, so it no longer links the website's. ## 2026-10-20 - SKILL.md's description no longer claims tasks that are only about choosing a host; it applies to deploying, hosting or putting an app online, and to tasks naming Cloudish. - SKILL.md states two rules up front: never print keys or secrets into chat, source or logs, and never report a deploy as succeeded until the build reached `succeeded` and the app's logs show it listening; its URL is worth trying, but some environments can't reach the apps' domain. - SKILL.md section 0 mints a key with the same snippet as credits.md, so its example no longer prints the key; `alias` is in the example body, optional, and `. ./.env` loads the key in each shell. - credits.md saves a new key to `.env` without capturing `curl`'s output in `$( )`: the response goes to a temporary `.env.new-key.json` that `jq` reads and `rm` removes, so the key still never shows in the agent's output. It still mints only when `.env` has no key, writes nothing when the request fails, gitignores `.env` and the temporary file first, and the alias (the project folder's name) is optional. - The example image is pinned (`ghcr.io/acme/my-app:1.0.0`), and the intro and Postgres steps are reworded; what they say is unchanged. - `ref` is the plugin, directory or link SKILL.md came from (`claude-plugin`, `chatgpt-plugin`, `producthunt`, ...), left out rather than guessed; it no longer asks for `user`. - SKILL.md no longer points to `GET /search`; llms.txt still lists it. Each document takes `?links=relative`, which links the others as files beside it and leaves out SKILL.md's datacenter section, for copies bundled into a plugin. - SKILL.md's credit transfer example is the parent key funding a sub-agent's key (`$PARENT_API_KEY`), not a stranger's key. - `GET /search?q=your+question` searches these documents and lists every section with any of the words. SKILL.md and llms.txt mention it. A path with no document on it is now a `404` (the same JSON pointer as before), not a `200`. - A key never goes below zero. Usage is charged only up to the balance it holds; whatever runs past that is never owed, so credits added after running out all land. credits.md says so under "Checking a balance". - `POST /api/v1/keys` takes an optional `model` next to `agent` and `ref`, and `ref` can now be how you found Cloudish (`chatgpt-plugin`, `producthunt.com`, `user`). SKILL.md's example shows all three as placeholders; every one is optional. - Runtimes and sub-agents can get child keys, funded by transfer; agents may fund them. ## 2026-10-19 - Apps on port `80` start again; they used to sit on the starting page forever. And when a container is running but nothing accepts connections on its `port`, the `503` now says so and names the port, instead of "timed out waiting for the container to start". - The project owner pays for an app, whoever calls it. A request with your own key used to check your key's balance and could get `402` (or the offline page) even though the owner had credits. The `402`'s `alias` is now always the owner's. - Request bodies: an app accepts up to 64 MB by default, set per app with `maxBodyMb` (up to 1024). Bodies over 1 MiB used to get `413` from the platform no matter what. - `cloudish.app` is now the official domain for apps: an app's `url` is `https://<name>.cloudish.app/`. Keeping apps off `cloudish.ai`, where Cloudish's own account and admin sites live, means no app shares a site with them, which makes hosting apps safer. Older `https://<name>.on.<datacenter>.cloudish.ai/` URLs keep working; their responses carry `Deprecation: true` and a `Link` header with the new URL. - `subdomain.url` is now an app's permanent URL on `cloudish.app`, `https://<name>.cloudish.app/`, which works whichever datacenter serves it: save and share that one. URLs you saved earlier keep working. (`subdomain.globalUrl`, briefly the field for it, is the same value.) - Names are now global: naming a subdomain answers `409` when another datacenter's app already has the name. - App URLs (`subdomain.url`, replica URLs) are now on `cloudish.app`: `https://<name>.do.cloudish.app/` and `https://<name>.anton.cloudish.app/`. Apps created before this also keep answering on their older `https://<name>.on.<datacenter>.cloudish.ai/`. - Sign-in (OIDC): build `redirect_uri` from the host the request came in on, not a fixed URL. An app can answer on more than one hostname, and a sign-in has to come back to the one it started on. - Started this changelog. SKILL.md now says when it was last updated and links here.skills/cloudish/container.md3.8 KBc10779d3feb8upstream ↗
# How Cloudish isolates containers What keeps one app's container apart from another's, and from the platform itself, on this deployment (https://cloudish.ai). It describes how things work today, not a guarantee. ## Where a container runs - Each app is its own Kubernetes Deployment and pod, running its own image, with its own internal address and, if it has one, its own volume. - App pods run on worker machines reserved for apps: the platform's own services run on separate machines, and image builds on separate build machines. - Apps from different keys share worker machines, and so that machine's Linux kernel, as containers on one machine do. There is no per-app virtual machine or kernel sandbox. - All apps run in one Kubernetes namespace, alongside the platform's own services. The rest of this page is what keeps them apart. ## Network - **Inbound:** an app's container accepts connections only from the platform's proxy, which every request to its subdomain or custom domains passes through. A private app's access check happens in that proxy, so nothing reaches the container without passing it. Other apps can't connect to the container directly. - **Outbound:** the container can reach the internet, DNS, and any public URL, including other Cloudish apps and the Cloudish API at their public addresses. It can't reach another app's pod, the platform's internal services at their internal addresses, the database, the cloud provider's metadata service, the machines' own ports, or the Kubernetes API. Private, link-local and CGNAT address ranges are blocked. - Apps that talk to each other do it over their public URLs, with whatever authentication they set up themselves. ## Privileges - **No Kubernetes credentials:** no service-account token is mounted. - **No service links:** the container gets no environment variables advertising other services in the cluster. - **System call filter:** the container runtime's default seccomp profile (`RuntimeDefault`) limits which system calls the container can make. - **No privilege escalation** (`allowPrivilegeEscalation: false`): setuid programs such as `sudo` and `su` can't raise privileges. A container that starts as root and switches to another user is unaffected. - **No raw sockets** (`NET_RAW` dropped): the container can't forge network packets, and `ping` doesn't work. The other default capabilities stay, so binding port 80, `chown` and switching users work as usual. - **User:** the container runs as the user its image sets with `USER`, or root if it sets none. Cloudish doesn't force a non-root user, because many images expect root. A volume is mounted with group 10001 (`fsGroup`), so a non-root user can write to it. ## Resources - Each app reserves the CPU and memory of its size, and can't use more than its limit. A container over its memory limit is restarted. - `shared` reserves 0.1 CPU and 0.2 GB and may use up to 1 CPU and 1 GB when the machine has them spare. It has a lower priority than other sizes, and is the first restarted when a machine runs short of memory. Sizes: [instances.md](instances.md). ## Storage - A volume is a block device attached to one app's pod only: no other app can mount it. It survives restarts, sleep and a zero balance. ## Builds - Each build runs in its own short-lived pod on the build machines, with rootless BuildKit. BuildKit needs seccomp and AppArmor unconfined, so a build doesn't get the system call filter apps do. - A build's network is restricted like an app's, plus the platform's registry and the build's own uploaded context. ## What the platform adds to traffic - Requests reach the app with `X-Forwarded-For`, `-Host` and `-Proto` headers set by the proxy. - Responses get `Strict-Transport-Security` from the HTTPS ingress, and nothing else: no CORS or other security headers. An app sets its own.skills/cloudish/credits.md5.2 KBba9b2b782a12upstream ↗
# Cloudish credits Everything to do with credits: which key to use, what to do when one runs out, claiming, and moving credits between keys. Every call authenticates with `Authorization: Bearer $CLOUDISH_API_KEY`, same as SKILL.md. ## Which key to use Keep each project's key with that project, and reuse it instead of minting a new one (minting is SKILL.md section 0). A key per project folder keeps each project on its own balance, so one running out never stops another, and its alias tells a human which project a key, a claim link or a `402` is about. Related projects can instead share one key, or hang under one as child keys (below), so their costs are funded and capped from a single balance. The requested alias is best-effort: lowercase letters, digits and hyphens (anything else is normalized), and if it's taken you get a close variant such as `todo-app-otter`. Always use the `apiKey.alias` that comes back. ## Checking a balance ```bash curl https://cloudish.ai/api/v1/credits -H "Authorization: Bearer $CLOUDISH_API_KEY" # -> { "balance": 4.2, "granted": 5, "spent": 0.8, "quota": null, "spentToday": 0.3 } ``` `GET /api/v1/credits/transactions` lists every grant, transfer and usage charge behind that number. A key never goes below zero. Usage is charged only up to the balance the key holds, and whatever runs past it is never owed, so credits added after a key runs out all land: a key at `0` that adds 10 credits has 10. ## When a key runs out A request billed to an out-of-credit key returns `402` with the alias of the key that ran out: ```json { "error": "This API key is out of credits — ...", "alias": "todo-app", "docs": "https://cloudish.ai/credits.md" } ``` Its running apps stop within a minute, always-on ones included (their status becomes `out_of_credits`); their volumes, and the data on them, are kept, and they start again once the key has credits — an always-on app on its own, the rest on their next request. The alias names the key that pays for the request — the project owner's, whoever calls it — so match it against each project's saved alias to know which project's key needs credits. Then, from that folder, mint a claim link for that key yourself and hand your human the URL itself — never the command to mint one — naming the alias so they know which project it's for: ```bash curl https://cloudish.ai/api/v1/credits/claim -H "Authorization: Bearer $CLOUDISH_API_KEY" # -> { "url": "https://..." } # -> tell your human: "This adds credits to todo-app (this folder's key): https://..." ``` The link is single-use and expires 30 minutes after it's minted, so mint it right when you hand it over and say that it expires; if your human comes back later or the page says it expired, mint a new one. Where the credits come from — a purchase, or a balance your human already holds elsewhere — is handled on that page; you never need any key other than this folder's own, so don't ask your human for one. A `402` saying a daily usage quota was reached is different: the key still has credits but hit its rolling 24-hour quota, and recovers on its own as that window moves. ## Moving credits between keys Any key can send part of its balance to another key by alias, no admin needed — authenticate as the sending key: ```bash curl -X POST https://cloudish.ai/api/v1/credits/transfer \ -H "Authorization: Bearer $SENDING_API_KEY" -H "content-type: application/json" \ -d '{"to": "todo-app", "amount": 5}' # -> { "ok": true, "balance": <sender's remaining balance>, "reference": "<ledger id>" } ``` Funding keys under yours (below) is yours to do: it's how you delegate work without handing out your own key. ## Keys under a key Minting a key *with* a key makes it a child of that key — same account, no free grant of its own. Hand one to a sub-agent or a container instead of your own key, and fund it by transfer; a `receive` limit (below) caps what it can get: ```bash curl -X POST https://cloudish.ai/api/v1/keys -H "Authorization: Bearer $CLOUDISH_API_KEY" \ -H "content-type: application/json" -d '{"alias": "todo-app-worker"}' # -> { "apiKey": { "alias": "todo-app-worker", "parent": "todo-app", ... }, "key": "cld_..." } ``` A key or any key above it can delete it (`DELETE /api/v1/keys/{alias}`): it and everything under it stop working, and their balances move to its parent. Root keys (no parent) can't be deleted. A key above another can cap what crosses that key's boundary — received from anywhere outside it, including its parent, or sent outside it — in any rolling window, in seconds. A key can never set its own limits: ```bash curl -X PUT https://cloudish.ai/api/v1/keys/todo-app-worker/limits -H "Authorization: Bearer $CLOUDISH_API_KEY" \ -H "content-type: application/json" \ -d '{"limits": [{"direction": "receive", "windowSeconds": 3600, "max": 5}]}' ``` Transfers between keys of one account don't count against the account's own limits, only those it set on the keys involved. A transfer, purchase or claim over a limit answers `429` with `code: "limit_exceeded"`, the key whose limit it was, the window, and what's left. `GET /api/v1/credits/flow` shows what your key received and sent in the last hour, day and 30 days, and what it may still receive or send outside its account.skills/cloudish/instances.md4.0 KB83a023c84ee4upstream ↗
# Cloudish instances and pricing What a running container costs, and which sizes exist. One credit is one US dollar. All prices below already include the platform margin. ## How billing works - **Billed per second, only while the container is running.** An app sleeps after `sleepAfterMinutes` without requests (15 by default, see SKILL.md section 1) and costs nothing until the next request wakes it, unless it was deployed with `"alwaysOn": true`: that one runs, and is billed, around the clock. - **Price per second = CPU + memory + a flat fee**, charged at the size you *reserved*, not what the app happens to use: | Component | Per second | Per hour | |---|---|---| | CPU, per core | $0.000007522 | $0.02708 | | Memory, per GB | $0.000002813 | $0.01013 | | Flat fee, per running container | $0.000001667 | $0.00600 | - **Replicas** multiply the price: each running replica is billed as its own container. - **Image builds** are billed the same way for as long as the build runs, at the build's own size (default 3 CPU / 5 GB: $0.0023 per minute, so a typical 3–5 minute build costs about $0.009). - **Custom domains** cost $0.01 per active domain per day, billed hourly (see SKILL.md section 4). - **Persistent volumes** are not billed. ## Sizes Set a size with `cpuCores` and `memoryGb` on the project create/update call (SKILL.md section 1); the names below are just labels, the API only takes those two fields. Leave both out to get the default on a new app, or to keep an existing app's size. Month = 730 hours, year = 8,760 hours, running the whole time. | Size | Fields | CPU (cores) | Memory | Per second | Per hour | Per month | Per year | |---|---|---|---|---|---|---|---| | `shared` (default) | `"cpuCores": 0.1, "memoryGb": 0.2` | 0.1–1 | 0.2–1 GB | $0.00000298 | $0.0107 | $7.84 | $94.03 | | `small` | `"cpuCores": 0.5, "memoryGb": 1` | 0.5 | 1 GB | $0.00000824 | $0.0297 | $21.66 | $259.87 | | `medium` | `"cpuCores": 1, "memoryGb": 2` | 1 | 2 GB | $0.00001481 | $0.0533 | $38.93 | $467.17 | | `large` | `"cpuCores": 2, "memoryGb": 4` | 2 | 4 GB | $0.00002796 | $0.1007 | $73.48 | $881.78 | ### `shared`: memory and CPU on demand `shared` (formerly `micro`) is billed for 0.1 CPU and 0.2 GB, but it can use **up to 1 CPU and up to 1 GB of memory whenever the machine it runs on has them spare**. The extra is not guaranteed: - When the machine is busy, the app only gets its reserved 0.1 CPU and runs slower. Starting up (the first request after it scaled to zero) is slower than on other sizes for the same reason. - If the app is using more than its reserved 0.2 GB when the machine runs short of memory, it can be restarted, and it's the first to be moved to make room for other apps. Good for small APIs, bots, webhooks, and prototypes: a small Go, Express or FastAPI app. Not a good fit for anything that must not restart, anything running a database inside the container, or apps that need their full memory all the time (a Next.js server, Streamlit). Use `small` or larger for those. Every other size is fully reserved: its CPU and memory are always there, and it's never restarted to make room for another app. ## What a year costs by usage Includes the 15 minutes (the default `sleepAfterMinutes`) the container keeps running after each period of use, before it sleeps. | Usage | Billed hours/year | `shared` | `small` | `medium` | `large` | |---|---|---|---|---|---| | Always on | 8,760 | $94.03 | $259.87 | $467.17 | $881.78 | | 8 h/day, weekdays only | 2,145 | $23.02 | $63.63 | $114.39 | $215.92 | | 1 h/day | 456 | $4.90 | $13.53 | $24.33 | $45.93 | Anything that keeps sending requests (uptime monitors, crawlers, a page that polls) keeps the container running and billed. Each app chooses: `"alwaysOn": true` for the "Always on" row, or a `sleepAfterMinutes` of its own. A bot that wakes every hour (`"wakeEveryMinutes": 60`) and sleeps after 5 minutes (`"sleepAfterMinutes": 5`) runs about 730 hours a year. See SKILL.md section 1. Current rates are also available as JSON at `GET https://cloudish.ai/api/v1/pricing`.skills/cloudish/replicas.md4.8 KB7a64bb26d41bupstream ↗
# Replicas: many isolated copies of one app An app normally runs as one container behind its URL. Its `replicas` setting lets it run more copies at once: each replica is its own container, started from the app's image, and reached only by its own id. Use replicas for one sandbox per user, task or agent, where each caller needs a container of its own. `replicas` is a maximum, not a count. Setting it starts nothing. A replica starts when you ask for one and stops on its own when idle. You pay for each replica only while it runs. ## 1. Allow replicas Set `replicas` when creating or updating the app (see [SKILL.md](SKILL.md)). It's the most copies that may run at once, counting the app's own container, so `10` allows 9 replicas. The default is `1` (no replicas); the highest is 100. ```bash curl -X POST https://cloudish.ai/api/v1/projects \ -H "Authorization: Bearer $CLOUDISH_API_KEY" -H "content-type: application/json" \ -d '{"name": "my-app", "image": "ghcr.io/acme/my-app:1.0.0", "port": 8080, "replicas": 10}' ``` Replicas have no storage: anything one writes is gone when it stops. An app with a volume can't run replicas. ## 2. Start a replica On any request to the app's URL, send `Cloudish-Replica: new` with the app owner's key. This starts a replica, waits for it to start, and sends the request to it. The response's `Cloudish-Replica` header has the new id: ```bash curl -i https://<app-url>/ \ -H "Authorization: Bearer $CLOUDISH_API_KEY" -H "Cloudish-Replica: new" # -> HTTP/1.1 200 OK # Cloudish-Replica: r-8kq2x7ab ``` Or start one ahead of time without sending it a request: ```bash curl -X POST https://cloudish.ai/api/v1/projects/YOUR_ALIAS/my-app/replicas \ -H "Authorization: Bearer $CLOUDISH_API_KEY" # -> { "replica": { "id": "r-8kq2x7ab", "status": "starting", # "header": "Cloudish-Replica: r-8kq2x7ab", "url": "https://..." } } ``` Only the owner's key can start a replica. The key is removed from requests before they reach a replica, so code running in it never sees it. ## 3. Send requests to a replica Send its id in the same header, on any request to the app's URL: ```bash curl https://<app-url>/run -H "Cloudish-Replica: r-8kq2x7ab" ``` A request without the header (or with `Cloudish-Replica: any`) always goes to the app's own container, never to a replica. Keeping track of ids is up to you: store the id and send it on every request for that replica. The project's access level still applies — a private project's requests need its owner's key, as they do without replicas. A replica also has its own URL, `url` in the response above (`https://r-8kq2x7ab--<token>.<run-domain>/`): every request there goes to that replica with no header, so it works from a browser and for websockets. `url` is `null` where this deployment can't serve one yet — use the header. ## 4. Responses to handle - `410` (`code: "replica_gone"`): the replica has stopped (idle, deleted, or its machine went away). Start a new one; nothing carries over. - `503` with `Retry-After` and `Cloudish-Replica`: still starting. Retry with that id, not `new` again, or you start a second replica. - `429` with `Cloudish-Replicas-Max`: the app already runs as many copies as `replicas` allows. Delete one, or raise `replicas`. - `401`/`403`: `new` without the owner's key. - `402`: the owner's key is out of credits — see [credits.md](credits.md). - `409`: the app has a volume. - `400`: the header is not `new`, `any` or a replica id. ## 5. List, read logs, stop ```bash curl https://cloudish.ai/api/v1/projects/YOUR_ALIAS/my-app/replicas -H "Authorization: Bearer $CLOUDISH_API_KEY" # -> { "maxReplicas": 10, "replicas": [ { "id": "r-8kq2x7ab", "status": "running", ... } ] } curl https://cloudish.ai/api/v1/projects/YOUR_ALIAS/my-app/replicas/r-8kq2x7ab/logs -H "Authorization: Bearer $CLOUDISH_API_KEY" curl -X DELETE https://cloudish.ai/api/v1/projects/YOUR_ALIAS/my-app/replicas/r-8kq2x7ab -H "Authorization: Bearer $CLOUDISH_API_KEY" ``` ## Lifetime and billing - A replica stops after its app's `sleepAfterMinutes` pass with no requests to it; an open websocket counts as a request. The default is 15 minutes. Change it for the app and its replicas with `PATCH https://cloudish.ai/api/v1/projects/YOUR_ALIAS/my-app {"sleepAfterMinutes": 1}`. A replica of an `alwaysOn` app runs until it's deleted. - Each replica is billed per second while it runs, at the app's size (`creditsPerHour`, see [instances.md](instances.md)), to the owner's key. When the key runs out of credits, its replicas stop. - A replica runs the image, env and secrets the app had when the replica started. Redeploying the app doesn't change replicas already running — start new ones to pick the change up. - Replicas are isolated like any app container (see [container.md](container.md)): one replica can't reach another, or the app's own container.README.mdupstream ↗
Contents are not inlined in the catalog. Open the upstream file.
Plain-text copy, no login: /skill-bundles/cloudishai-skills-skills-cloudish.md