A cloud build fetches everything itself, including the
FROM base image and anything RUN downloads, so those sources must be publicly reachable. There is no build-secret or private-registry-credential support yet; if your base image is private, contact support.
A complete example lives in agent37-platform/custom-agent-image: a working agent app (auth, chat, files, integrations) whose agents run an image it builds itself from one Dockerfile and one skill folder. Click Use this template, edit the Dockerfile, run npm run release:agent. Smaller ready-to-build recipes live in the Agent37 Cookbook, like hermes-vnc-desktop, a live desktop view of the agent’s browser.
This page is the walkthrough; Templates → build on the Hermes base image is the reference for the contract.
When you register a template, Agent37 copies your image once into private storage and pins it by digest. That snapshot is what every instance runs, so registering takes up to a few minutes for a large image. Re-pushing the same tag later does nothing: publish a new tag and update the template, or re-run the cloud build. Your image is stored privately and never republished.
1. Choose a starting image
To customize Hermes, build onghcr.io/agent37-platform/hermes-base. It includes Hermes, the gateway, Chromium, and the standard toolchain. This example adds a CLI:
/usr/local/bin and everything else into /usr/local or /opt, never /home/node or /home/linuxbrew, which are masked at runtime. Keep the base ENTRYPOINT. See the full contract.
Skills don’t belong in the image. Hermes reads them from An app that provisions agents does this once, right after create. The skill then persists across restarts and updates.
~/.hermes/skills, which lives on the instance’s persistent volume, so anything the image writes there is masked. Install them into a running instance instead, over exec or the files API:curl
0.0.0.0 and note its listening port; you will pass that as default_port when you register the template. An image with no HTTP service can omit default_port and be driven through exec, but it still needs a long-running ENTRYPOINT or CMD.
2. Verify it locally (optional)
You don’t need Docker to publish; the cloud build does the real build. If you have Docker, a local build is still the fastest way to test before publishing. Plaindocker build stores the amd64 result in your local Docker, including on an Apple Silicon Mac:
linux/amd64 build is also the artifact you push.
3. Register the image
You have two ways to get the image to Agent37. Either way the resulting image is capped at 8 GB decimal (8,000,000,000 bytes), and either way the platform copies it once into private storage at registration.
Registration is synchronous and can take a few minutes for a large image. The returned
image_digest identifies the immutable private copy every instance runs. Re-pushing a mutable source tag does not change that copy.Build it in the cloud
Use this path when the image isn’t in a public registry, or doesn’t exist yet. You upload a small build context (theDockerfile and the files it COPYs), and Agent37 builds the image on its own infrastructure:
- Packs the directory (default
.; it must haveDockerfileat its root) into a gzipped context, excluding.gitand your.dockerignorepatterns (plain patterns only;!negations are ignored). The context is capped at 100 MB; it holds the Dockerfile’s inputs, not the image, so it stays small. - Everything else in the folder ships with the context, a stray
.envor key file included, and aCOPY . .bakes it into the image. Check the folder, or add a.dockerignore, before you build. - Builds the image on Agent37’s infrastructure and streams the live build log to your terminal. On failure the command exits non-zero with the failing step visible.
- Publishes the result as the workspace template.
--namedefaults to the folder name;--default-port <port>sets the template’s default port. Re-building an existing name publishes a new template revision; existing instances never change. - Ctrl-C does not cancel the build; it continues server-side and still publishes on success.
FROM base image and anything RUN downloads, must be publicly reachable; there is no build-secret or private-registry-credential support yet. A template published this way has an image_digest but no image_ref, because there is no public registry reference.
To script the same flow without the CLI, see the raw contract in
Templates → build an image in the cloud.
Import a public registry image
Push the image to any public OCI registry, then register its fully qualified reference. For example:ubuntu-latest runner is already linux/amd64, and the built-in GITHUB_TOKEN can push to ghcr.io/<owner>/<repo> with permissions: packages: write. Tag the image with the commit sha and register that, never latest.
Register a specific tag, not latest:
curl
4. Create an instance
Register once, then create instances from the template name:curl
curl
If the instance comes up
failed instead of running, read its logs. An entrypoint that exits, a missing binary, or a service that never listens on default_port are the usual causes. exec cannot help until the container is running.5. Give it a model
hermes-base is clean: it boots with no LLM provider wired. That does not mean the instance has
no model available. Every instance, including one running an image you built from scratch, gets
a working OpenAI-compatible endpoint and a Composio MCP server in its environment, as
AGENT37_MANAGED_TOKEN, AGENT37_LLM_PROXY_URL, and AGENT37_COMPOSIO_MCP_URL. Pointing your
agent at those is the
shortest path to a running agent, costs no setup, and meters to the instance
budget. Managed services in your image is
the reference, and pi-agent-image is a
complete image that does it in two config files with no credentials in either.
Bring your own model instead
To run an instance on your own model, point Hermes at any OpenAI-compatible endpoint, your own proxy or a provider directly, by writing~/.hermes/config.yaml on the instance:
GET /v1/models (to resolve the model id) and POST /v1/chat/completions (the turn). Anything that speaks them works: a provider directly, or a small proxy of your own that forwards to one with your key.
Write the config over exec or the instance terminal; it lives on the persistent volume, so it survives restarts. Then send a message and the agent runs on your model.
Want this as a finished app rather than a config file? Use your own model is a forkable kit that does exactly this per agent: your key behind a proxy, a revocable token per instance, and per-agent spend caps.
Keep it current
Your image freezes its base; rebuilding is how it picks up platform updates. Each template revision is an immutable snapshot, so a new build takes effect only after the template changes: re-run the cloud build under the same name, or publish a new registry tag and PATCHimage_ref. Every successful build and every changed image_ref increments the template’s automatic revision; a re-build counts even when its digest matches the previous image. PATCHing the same image_ref string deliberately reuses the existing snapshot and revision.
Existing instances keep their installed template_revision. Update each instance to recreate it from the template’s current revision. Anything on the persistent volume (~/.hermes/skills, ~/.hermes/config.yaml, the agent’s files) survives that update untouched, so a changed skill needs the same exec write again, not a rebuild.