> ## Documentation Index
> Fetch the complete documentation index at: https://docs.murmur.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# VM Environment

> What ships on agent VMs — base OS, preinstalled tools, environment variables — and how to customize the runtime with recipes and overlays.

Agent VMs come pre-configured with development tools and Claude Code. You can customize the environment with startup scripts or custom baked images. This page explains what is available out of the box and how to extend it. For per-repo setup that runs after cloning — dependency installs, code generation — see [Repo Hooks](/configuration/repo-hooks).

## Pre-installed tools

Every agent VM starts from a base image built on **Debian 12 (Bookworm)** with the following tools pre-installed:

| Tool                 | Purpose                                                        |
| -------------------- | -------------------------------------------------------------- |
| **Git**              | Version control — cloning repos, creating branches, committing |
| **Node.js**          | JavaScript runtime — required by Claude Code                   |
| **Claude Code**      | The AI coding agent that runs on the VM                        |
| **gh**               | GitHub CLI — PR creation, issue management, CI checks          |
| **jq**               | JSON processing — parsing API responses, config files          |
| **curl**             | HTTP client — downloading files, calling APIs                  |
| **Python 3**         | Available for scripting and tooling                            |
| **Build essentials** | gcc, make, and common build tools                              |

The base image is maintained by the Murmur platform and updated regularly with security patches.

## Startup scripts

Startup scripts run **before the agent session starts**, making them the right place for environment customization that needs to happen on every boot.

Configure a startup script in your environment resource:

```yaml theme={null}
# Set via: murmur set environment my-env
name: my-env
substrate: gce
machine_type_ref: default
disk_size_gb: 50
startup_script: |
  #!/bin/bash
  set -e
  
  # Install additional packages
  apt-get update && apt-get install -y postgresql-client redis-tools
  
  # Install project-specific tools
  npm install -g pnpm@latest
  
  # Write configuration files
  cat > /home/user/.npmrc << 'EOF'
  registry=https://npm.example.com/
  EOF
  
  # Clone additional repos or download data
  curl -sL https://example.com/fixtures.tar.gz | tar xz -C /tmp/
```

### What startup scripts are good for

* Installing packages with `apt-get`
* Installing language-specific tools (`pip install`, `npm install -g`, `go install`)
* Writing configuration files (`.npmrc`, `.env`, tool configs)
* Downloading test fixtures or seed data
* Running database migrations or setup scripts
* Setting up SSH keys for private package registries

### Execution details

* Scripts run as root before the agent session starts
* The working directory is `/`
* The agent's repos have already been cloned when the script runs
* Scripts must exit 0; a non-zero exit fails the provisioning
* stdout and stderr are captured in provisioning logs

## Custom images

For larger or more complex environments, **bake a custom image** instead of relying on startup scripts. Custom images use recipes and `murmur bake` to produce VM images with your toolchain pre-installed.

### Recipes

A recipe defines how to build a custom image:

```yaml theme={null}
# Set via: murmur set recipe my-recipe
name: my-recipe
base_image_gce_ref: default  # Start from the platform base image
provisioning_script: |
  #!/bin/bash
  set -e
  
  # Install Go
  wget -q https://go.dev/dl/go1.22.0.linux-amd64.tar.gz
  tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz
  export PATH=$PATH:/usr/local/go/bin
  
  # Install Docker
  curl -fsSL https://get.docker.com | sh
  
  # Install CUDA toolkit (for GPU workloads)
  # apt-get install -y nvidia-cuda-toolkit
  
  # Pre-install project dependencies
  cd /tmp && git clone https://github.com/org/repo.git
  cd repo && go mod download
  rm -rf /tmp/repo
provisioning_timeout: 30m
secret_allowlist:
  - npm-token  # Secrets needed during image build
```

### Baking an image

```bash theme={null}
murmur bake my-recipe
```

This starts an image build process. You can monitor progress with:

```bash theme={null}
murmur bake status my-recipe
```

Once the bake completes, reference the resulting image in your workspace configuration. The image is stored in your tenant's image registry and used for all VMs in the workspace.

### When the image is used

Custom images replace the base image entirely. When a VM boots with a custom image, it already has all your tools installed — no startup script delay.

## Environment variables on VMs

Agent VMs have several environment variables available:

| Variable          | Description                                                                                                     |
| ----------------- | --------------------------------------------------------------------------------------------------------------- |
| `ANTHROPIC_MODEL` | The model configured for this agent (e.g. `claude-sonnet-4-20250514`)                                           |
| `GH_TOKEN`        | GitHub token for repo operations (PR creation, cloning, API calls)                                              |
| `MURMUR_SECRET_*` | Tenant secrets injected as environment variables. A secret named `npm-token` becomes `MURMUR_SECRET_NPM_TOKEN`. |
| `MURMUR_AGENT_ID` | The unique identifier for this agent session                                                                    |
| `HOME`            | Home directory for the agent user                                                                               |

### Tenant secrets

Secrets stored in the catalog are decrypted and injected as environment variables with the `MURMUR_SECRET_` prefix:

```bash theme={null}
# If you have a catalog secret named "npm-token":
echo $MURMUR_SECRET_NPM_TOKEN
# → your-secret-value
```

Secrets are decrypted from KMS in memory only — they are never written to disk. See [Encryption](/security/encryption) for details on how secrets are protected.

## Claude Code configuration

The Claude Code `settings.json` is written at VM boot time by the Murmur control plane. It configures:

* **Model selection** — set from the workspace config or per-agent override
* **Fast mode** — enabled if `fast_mode: true` in the workspace config
* **MCP server** — the `murmur` MCP server entry, enabling agent orchestration tools
* **Permissions** — tool permissions appropriate for autonomous operation

```json theme={null}
{
  "model": "claude-sonnet-4-20250514",
  "mcpServers": {
    "murmur": {
      "command": "murmur",
      "args": ["mcp"],
      "env": {}
    }
  },
  "permissions": {
    "allow": [
      "Bash(*)",
      "Read(*)",
      "Write(*)",
      "Edit(*)",
      "Glob(*)",
      "Grep(*)",
      "mcp__murmur__*"
    ]
  }
}
```

Agents should not modify `settings.json` directly. To customize Claude Code behavior, use `append_system_prompt` in the spawn configuration or define an agent persona.

## Scripts vs. baked images

Use this decision table to choose between startup scripts and custom images:

| Criteria            | Startup script                                      | Custom image                                      |
| ------------------- | --------------------------------------------------- | ------------------------------------------------- |
| **Install time**    | Runs on every boot (adds to startup latency)        | Pre-installed (no boot delay)                     |
| **Install size**    | Small packages, quick installs                      | Large toolchains (Go, Rust, Docker, CUDA)         |
| **Iteration speed** | Change the script, next spawn uses it               | Requires `murmur bake` (minutes to build)         |
| **Complexity**      | Simple apt-get, npm, pip installs                   | Complex multi-step installations                  |
| **Reproducibility** | Depends on external package registries at boot time | Fully baked, no external dependencies at boot     |
| **Use case**        | Development, rapid iteration, light customization   | Production, stable environments, heavy toolchains |

### Rules of thumb

* If the install takes **under 30 seconds**, use a startup script.
* If the install takes **over 2 minutes**, bake it into an image.
* If you are **iterating frequently** on the environment, start with a startup script and bake once it stabilizes.
* If you need **GPU drivers or CUDA**, always use a custom image — these installations are too large and slow for startup scripts.

<Tip>
  You can combine both approaches: use a custom image for the heavy base (Go, Docker, etc.) and a startup script for lightweight, frequently-changing configuration (writing config files, setting env vars).
</Tip>
