Contract
What ClaudeToHost accepts
Three shapes of project, and one explicit contract for the two that have to run. Nothing here is a convention you have to guess: if your project does not match, you are told which rule it missed.
Static site
Nothing runs, so there is nothing to declare. Drop the build output — not the project — and it is served as-is.
A single top-level folder is stripped automatically, so zipping dist/ and zipping its contents both work. Vite and Astro build to dist/; a Next.js static export lands in out/.
Projects that run: claudetohost.yaml
A service or a worker needs two files at the root of what you drop: a Dockerfile, and this manifest. It declares how to run the thing — and, for env vars, only their NAMES.
Why a worker has no port
A Discord bot or a queue consumer is not a website. Declaring a port on one is rejected rather than ignored: a worker gets a deployment and nothing else — no service, no ingress, no public surface it never asked for.
Why env is names, not values
A mapping of KEY to value is refused outright. Values are supplied later from the site's page and land in a Kubernetes Secret in your own namespace; they never enter the manifest, the repository, or the deployment record.
Dockerfile requirements
- A non-root final
USERis mandatory. Not a suggestion — a build whose lastUSERis root, or absent, is refused. It is also why a web port must be ≥ 1024: a non-root process cannot bind lower. - Multi-stage where it makes sense: build in one stage, copy the artifact into a slim runtime. A single-stage image is a warning, not a refusal.
- Logs to stdout/stderr. Anything written to a file inside the container is invisible and lost on restart.
- No interactive shell as the entrypoint — the image has to start on its own.
- No secrets in the image or the repo. Files are scanned for key-shaped strings and a match fails the upload with the offending line.
ADD <url>is refused: an opaque network fetch at build time is not reproducible.
Limits
- Archive
- 40 MB, 5000 files
- Formats
- .zip · .tar.gz
- Per site
- 1 replica · 1 vCPU · 512 MiB
- Refused outright
- symlinks · paths escaping the archive