Skip to main content
You can run an Agent37 instance from any Docker image. Register it as a workspace template in one of two ways: 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 on ghcr.io/agent37-platform/hermes-base. It includes Hermes, the gateway, Chromium, and the standard toolchain. This example adds a CLI:
Bake binaries into /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 ~/.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
An app that provisions agents does this once, right after create. The skill then persists across restarts and updates.
You can also use an existing image or start from any base. Its main process must keep running. If it serves HTTP, bind it to 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.
Your built image freezes its base at build time. :latest is convenient while getting started; pin a dated Hermes base tag for reproducible production rebuilds. Find published tags on GHCR, or read the current tag from agent37-hermes’s image_ref on GET /v1/templates.

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. Plain docker build stores the amd64 result in your local Docker, including on an Apple Silicon Mac:
Run the image locally if it is practical: registration validates the image, but only a running container proves that its entrypoint and service work. If you take the public registry path, this local 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 (the Dockerfile and the files it COPYs), and Agent37 builds the image on its own infrastructure:
What it does:
  • Packs the directory (default .; it must have Dockerfile at its root) into a gzipped context, excluding .git and your .dockerignore patterns (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 .env or key file included, and a COPY . . 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. --name defaults 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.
Builds are free, run one at a time per workspace, and time out after 45 minutes. The built image is capped at 8 GB decimal, like any template image; if you need more, contact support. Everything the build fetches, including the 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:
On GHCR, make the package public after the first push (PackagesPackage settingsChange visibilityPublic). In CI, GitHub’s 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
Agent37 needs anonymous access only while it copies the image. The template and its instances no longer depend on the source registry after registration. A future image update needs a new public tag.
If your own image serves HTTP on port 8000, declare it: pass --default-port 8000 on the build, or include "default_port": 8000 beside name and image_ref. The bare instance URL then routes to that port, and instance creation probes it at boot. Omit it for hermes-base, whose gateway uses the 3737 fallback, or for a long-running private sandbox with no HTTP service.

4. Create an instance

Register once, then create instances from the template name:
curl
The result is a standard Agent37 instance running your image: same lifecycle, exec, and routed URLs as any other. Confirm your CLI shipped, without needing a model:
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:
Your endpoint must serve the two OpenAI-compatible routes Hermes uses: 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.
Want chat to work out of the box on Agent37’s managed model instead? Build FROM ghcr.io/agent37-platform/hermes:<tag> (tags on GHCR), which wires the managed model, and pass a budget on create.

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 PATCH image_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.

Troubleshooting