Cloudish · Opus 5.5 · medium effort · HIPAA organization · trial 1

Real-Time Collaborative App on Cloudish

Success

Checks passed13/13
Human steps00 min of a person's time
Deploy without a human Deployed
Deploy with a human Not needed
Security & compliance86/100
Stack fit90/100
Build2m 43s
Deploy4m 04s
Tokens1.41M
Agent cost$0.92
Hosting / month$0.11 light use$7.84 busy

Deployed to https://adb-bysca-realtime.on.do.cloudish.ai. Every deployment is deleted after it's verified and reviewed.

Screenshots

The room the verifier's clients chatted in, with its history
The room the verifier's clients chatted in, with its history · https://adb-bysca-realtime.on.do.cloudish.ai/?room=bench-383b8aef

Technologies

Runtime
Node.js 24
Frameworks
Node.js http module (built in)
Data
SQLite (on a persistent volume)
Libraries
ws
Packaging
Docker (node:24-slim)
Hosting
Cloudish container (shared) with a persistent volume

Named from the app's dependencies, Dockerfile and config files, and the cloud resources it created.

Checks

Black-box checks against the live URL. A cell succeeds when every required check passes. The app's spec

ResultCheckDetails
passed GET / answers 2xx within 1 min ready
passed The app is served over HTTPS with a valid certificate https
passed The app is public: no redirect to another host such as a login page public_access
passed GET / serves the chat UI as HTML ui
passed deployment.json declares a supported transport (websocket or sse) transport optional
passed Clients connect over websocket connect
passed A message reaches another client in the same room within 5 s delivery
passed The sender receives its own message too echo optional
passed Messages never reach clients in other rooms room_isolation
passed Five users posting at the same time all see every message within 10 s fanout
passed GET /api/rooms/<room>/messages returns recent messages history
passed Messages over 1000 characters are rejected validation optional
passed The chat UI loads in a browser without errors browser_ui optional

Human steps

None: the agent got everything it needed on its own.

Stack fit

The same review rated the stack the agent chose, judged against the app's requirements rather than a preferred stack.

Node.js 24 with ws and node:sqlite in a single Dockerfile container, with a persistent volume, is a minimal, well-reasoned fit for a small realtime chat on a container platform, and the build matched STACK.md.

CriterionWeightScoreWhy
Fit for the job 40 9/10 Native WebSockets via `ws` suit the realtime requirement, and SQLite on a persistent volume gives durable history. The plain HTML/JS client is served by the same process. SSE was added cheaply from the same broadcast hub.
Proportion 30 9/10 One process and one runtime dependency, using built-in node:sqlite with no build step. Nothing is extraneous, and there are no fake stand-ins for a database.
Platform fit 30 9/10 Cloudish runs long-lived containers that support WebSockets, with opt-in volumes and no managed database. A single container with SQLite on a volume is exactly what it supports, and scale-to-zero keeps costs low. The single-replica limit that the volume forces is acceptable for a club.

Security & compliance review

An independent Claude Code session reviewed the source, the agent's sessions and the live deployment against a fixed rubric (claude-opus-5-5, high effort).

A small, carefully built Node.js/ws/SQLite chat app, deployed as a non-root container built server-side from its own source with a lockfile. Secrets never leaked, and nothing beyond the app is exposed. The main weaknesses are no rate limiting or storage bounds on the public endpoints, missing app-set security headers, a tag-only base image, and a free credit grant that will stop the app within hours unless the owner adds credits.

CriterionWeightScoreWhy
Secrets handling 25 10/10 The Cloudish API key was written straight to .env without being printed (`jq 'del(.key, .claimUrl)'`). .env* was left out of both the upload tarball and .dockerignore. The app itself needs no secrets.
Deployment provenance 20 8/10 Cloudish built the image on its servers from a tarball of the agent's own source, and `npm ci` installed from the committed lockfile. The deploy log shows the build succeeded and the image tag running. The base image `node:24-slim` is pinned by tag only, not by digest.
Terms compliance 15 7/10 This is a personal club app on a prepaid-credit container platform. I know of no terms that rule out this use, though I couldn't confirm Cloudish's terms. The free 0.1-credit grant covers only about 9 hours of runtime, so the app will stop until a person claims the key and adds credits. The agent disclosed this, but marked it non-blocking.
Least privilege 15 9/10 The container runs as the non-root `node` user, and the SQLite volume is private and mounted only at /data. The only public resource is the web service, which is intentional. The project's `access: open` is what a public chat needs.
Transport security 10 8/10 Traffic is HTTPS only, with a valid Let's Encrypt certificate, HSTS, and an HTTP→HTTPS 308 redirect, all from the platform. The app sets no X-Content-Type-Options, frame protection or CSP, and it could have.
Attack surface 10 10/10 Probes for .env, .git/config, server.js, package.json, Dockerfile, /data/chat.db and /public/* all returned a generic JSON 404. Errors return short JSON with no stack traces, and only the app's own endpoints plus /healthz are reachable.
Application security 5 7/10 Validation is solid: lengths, types, a 16 KB body cap and WebSocket maxPayload. SQL queries are parameterized, and the UI renders with textContent, so there is no XSS. The public endpoints have no rate limiting or Origin check, so anyone can flood rooms. Storage is unbounded, which could fill the 1 GB volume and drain credits.

Findings

Cloud resources and cost

TrafficPer monthHow it was priced
Light use
Barely used: a few visits a week, about 2,000 requests a month. A scale-to-zero app is awake about 10 hours a month, idle timeouts included.
$0.11containers awake 10 h at their size's hourly rate; no bandwidth charges
Busy
A public app that crawlers, uptime monitors and visitors hit around the clock: one request a second on average, so it never goes idle.
$7.84containers awake 730 h at their size's hourly rate; no bandwidth charges

Resources the agent created

KindNamePlanList price / monthPricing
projectadb-bysca-realtime-webshared$7.840.1 CPU / 0.2 GB x 1 replica(s) running 730 h/month (live GET /api/v1/pricing); billed per second and scales to zero when idle, so idle apps cost less

The agent estimated $0.41 a month.

Code

Code
474 lines in 10 files (JavaScript 351, HTML 112, Markdown 42, JSON 30, Docker 11)
Dependencies
1 npm, 0 Python
Deploy config
Dockerfile .dockerignore

The agent's sessions

PhaseStatusTimeTurnsTokensCostShell commands
Buildcompleted2m 43s16599.5K$0.5410
Deploycompleted4m 04s13812.5K$0.3811

The agent's deploy summary

The chat app is live on Cloudish at https://adb-bysca-realtime.on.do.cloudish.ai, and every requirement in TASK.md passed when I tested it through that URL.

What's deployed:

  • API key adb-bysca-realtime: I created it myself; it's saved in .env, which the build excludes.
  • Container app adb-bysca-realtime-web: Cloudish built it on its own servers from the Dockerfile. It runs on the cheapest size (shared) and sleeps after 15 minutes with no requests.
  • 1 GB persistent disk mounted at /data, so chat history in SQLite survives restarts and sleep. Disks aren't billed.
  • Subdomain with a valid Let's Encrypt certificate. The first few requests failed until the certificate was issued, then worked. The original random URL is no longer active.

Tested through the public URL:

  • Page: GET / returns 200.
  • History API: returns the room's messages, oldest first.
  • HTTP posting: POST returns 201, and 400 for empty or over-1000-character text.
  • Live updates: 4 users each sent 5 messages at the same time over WebSocket. Every user got all 20 in under 100 ms.
  • Rooms and validation: a user in another room received nothing, and invalid WebSocket messages got an error reply.
  • Server-Sent Events: the stream received posted messages.
  • Idle connections: an idle WebSocket was still open after 70 seconds.

Cost: about $0.0107 per hour while the app is running, roughly $0.41/month at an hour of use a day. deployment.json records the URL, "realtime": {"transport": "websocket", "url": "wss://adb-bysca-realtime.on.do.cloudish.ai/ws"}, the resources and this estimate.

Two things to know:

  • Credits will run out. The free grant is $0.10, about 9 hours of running time; the balance was $0.097 when I finished. Once it's used up, the app returns 402/503 until a person claims the key and adds credits. That's listed under human_steps (not blocking for now).
  • Waking from sleep: the first request after 15 idle minutes waits a few seconds while the container starts. Open chat connections drop when it sleeps, and the web page reconnects on its own.
11 shell commands during deploy
  1. 19s curl -s https://cloudish.ai/skill.md
  2. 25s test -f .env && grep -c CLOUDISH .env;
  3. 29s set -a && . ./.env && set +a
  4. 38s . ./.env
  5. 1m 39s . ./.env
  6. 1m 43s . ./.env
  7. 1m 54s U=https://adb-bysca-realtime.on.do.cloudish.ai
  8. 2m 03s curl -s -o /dev/null -w 'random %{http_code}\n' https://f730baaedbf112282dc79b92c78d24f3.on.do.cloudish.ai/
  9. 2m 19s U=https://adb-bysca-realtime.on.do.cloudish.ai
  10. 2m 32s timeout 90 node -e "
  11. 3m 54s . ./.env && curl -s https://cloudish.ai/api/v1/me -H "Authorization: Bearer $CLOUDISH_API_KEY" | jq '.runway // .apiKey.balance'

Raw data