Skip to main content
Every agent runs on a VM. The platform’s default Image gets you Debian, Node, Git, Claude Code, and gh, which is enough for most TypeScript or Node projects. If your repos need anything else (Go, Python, Docker, CUDA, a private SDK, ImageMagick, an internal CLI), you’ll want a custom Image so agents boot with your toolchain already in place. You can also install things at boot time with a startup script. Here’s how to choose: Most teams start with a startup script while figuring out their stack, then move stable installs into a Recipe and bake when things settle. See recipe for every field on the Recipe resource.

1. Write a Recipe

A Recipe is a YAML file that names a base Image and a shell script. The shell script is what gets baked into your new Image. Apply it with murmur set:
A few things worth knowing about the script:
  • Make it idempotent. Bake retries from scratch on a fresh VM, so a flaky apt-get or network blip can fail one attempt and succeed the next. set -euo pipefail and explicit cleanup (apt-get clean) keep things tidy and surface real failures.
  • Clean up after yourself. Anything you leave on disk ends up in the final Image, which makes it bigger and slower to load. Delete tarballs, package caches, and build artifacts before the script exits.

If your install needs a private registry

If your script needs a token for a private registry (Artifactory, npm Enterprise, a private GitHub repo), add the secret name to the Recipe’s secret_allowlist. The secret is injected as an environment variable during the bake only. It’s never written into the final Image, so anyone in your tenant can safely use the resulting Image without seeing your credentials.

2. Bake the Image

Kick off the build with murmur bake:
A bake takes 5 to 15 minutes. Check in any time with murmur bakes ls:
Baked Images are content-addressed: their identity is a SHA-256 hash of the base Image, the script, and the target architecture. That means a no-op rebake is free because the platform recognizes the inputs haven’t changed and reuses the existing Image. Change one byte of your script and you get a fresh Image without having to manage versions yourself.

3. Use your new Image

Edit your Workspace to reference the baked Image by name:
The next agent you spawn against this Workspace boots from your new Image. Rolling back is just as easy: edit the field to point at a previous Image and the next agent uses that one instead. Workspaces and Images are intentionally decoupled this way so you can experiment without rebuilding.

Things to watch for when writing your script

The murmur user contract

Provisioning runs as root. Agents run as the murmur user (UID 1000, home directory /home/murmur), which has passwordless sudo by default. That’s deliberate: the VM is untrusted, ephemeral, and single-tenant, and all real isolation is enforced server-side — so agents get root on their own machine and can self-provision system dependencies at runtime (sudo apt-get install just works, and once your Image adds Node.js, so does npx playwright install --with-deps chromium). If your org wants a non-root agent, strip the grant in your Recipe: rm /etc/sudoers.d/murmur. See the security model for why root on the VM isn’t a boundary. Sudo is the fallback, not the plan: a runtime install costs minutes on every spawn, a bake pays that cost once. Install so everything your agents need is readable and executable by murmur without sudo — otherwise agents burn time rediscovering your toolchain on every boot. The patterns below cover the common cases.

Install to system paths

Things in /usr/local/bin are on murmur’s $PATH by default and world-executable, so this works without any extra steps:

Tools that install into a home directory

Some installers (sdkman, pyenv, rustup, etc.) drop files into ~/. Run them as murmur, otherwise they land in /root where the agent won’t find them:

Config files dropped as root

If your script copies a config file into murmur’s home, fix the ownership or murmur will hit a permission-denied at runtime:

Non-standard $PATH locations

If you install something to /opt/... or anywhere not already on $PATH, extend it through /etc/profile.d/ (not ~/.bashrc) so every shell murmur opens picks it up:

Don’t redo what the base already has

In the dashboard, expand “What’s on <image>” under the base Image picker. It shows you the exact provisioning script that built the base, so you can skip redundant apt installs and save bake time.