> ## 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.

# recipe

> Catalog resource that combines a base image with a provisioning script to bake custom VM images preloaded with your toolchain for agents.

A [recipe](/concepts/recipe) is a catalog resource that defines how to build a custom [image](/concepts/images). Each [recipe](/concepts/recipe) pairs one or more base [images](/concepts/images) with a provisioning script that installs tools, languages, and dependencies. A single [recipe](/concepts/recipe) can target multiple cloud substrates — reference an AWS base [image](/concepts/images), a GCE base [image](/concepts/images), or both.

When you [bake](/cli/bake) a [recipe](/concepts/recipe), Murmur runs the provisioning script on a scratch VM built from the base [image](/concepts/images), then snapshots the result as a new [image](/concepts/images).

## Fields

| Name                   | Type      | Required    | Description                                                                                                                                                                                            |
| ---------------------- | --------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `name`                 | string    | yes         | Unique identifier. DNS label format: `[a-z][a-z0-9-]{0,62}`.                                                                                                                                           |
| `base_image_aws_ref`   | string    | conditional | Base [image](/concepts/images) name for AWS bakes. Must reference a catalog [image](/concepts/images) with an AWS source. At least one of `base_image_aws_ref` or `base_image_gce_ref` is required.    |
| `base_image_gce_ref`   | string    | conditional | Base [image](/concepts/images) name for GCE bakes. Must reference a catalog [image](/concepts/images) with a GCE source. At least one of `base_image_aws_ref` or `base_image_gce_ref` is required.     |
| `provisioning_script`  | string    | yes         | Script content that runs on the scratch VM during bake. Max 256 KiB.                                                                                                                                   |
| `provisioning_timeout` | string    | yes         | Maximum execution time for the provisioning script. Go duration format (e.g. `10m`, `30m`). Max `1h`.                                                                                                  |
| `secret_allowlist`     | string\[] | no          | Names of catalog secrets the provisioning script may access during bake. Only these secrets are available on the scratch VM. Each name must match `[A-Z][A-Z0-9_]*` and must not start with `MURMUR_`. |
| `description`          | string    | no          | Human-readable description shown in the dashboard. Max 1024 bytes.                                                                                                                                     |

<Note>
  When both `base_image_aws_ref` and `base_image_gce_ref` are set, the referenced [images](/concepts/images) must have the same architecture. You cannot bake from an `amd64` GCE base and an `arm64` AWS base.
</Note>

## Examples

### GCE-only recipe with a provisioning script

```yaml theme={null}
name: python-toolchain
base_image_gce_ref: murmur-gce-base
provisioning_script: |
  #!/bin/bash
  set -euo pipefail
  apt-get update -y
  apt-get install -y python3.12 python3.12-venv python3-pip
  pip3 install poetry==1.8.3 ruff==0.4.8
  python3.12 --version
  poetry --version
provisioning_timeout: "15m"
description: "Python 3.12 with Poetry and Ruff"
```

```bash theme={null}
cat <<'EOF' | murmur set recipe python-toolchain
name: python-toolchain
base_image_gce_ref: murmur-gce-base
provisioning_script: |
  #!/bin/bash
  set -euo pipefail
  apt-get update -y
  apt-get install -y python3.12 python3.12-venv python3-pip
  pip3 install poetry==1.8.3 ruff==0.4.8
  python3.12 --version
  poetry --version
provisioning_timeout: "15m"
description: "Python 3.12 with Poetry and Ruff"
EOF
```

### Multi-substrate recipe

```yaml theme={null}
name: go-service
base_image_aws_ref: murmur-aws-base
base_image_gce_ref: murmur-gce-base
provisioning_script: |
  #!/bin/bash
  set -euo pipefail
  curl -fsSL https://go.dev/dl/go1.22.4.linux-amd64.tar.gz | tar -C /usr/local -xz
  export PATH=$PATH:/usr/local/go/bin
  go install golang.org/x/tools/gopls@latest
  go version
provisioning_timeout: "20m"
secret_allowlist:
  - GITHUB_TOKEN
  - NPM_TOKEN
description: "Go 1.22 with gopls, cross-substrate"
```

### Recipe with secret access

```yaml theme={null}
name: private-deps
base_image_gce_ref: murmur-gce-base
provisioning_script: |
  #!/bin/bash
  set -euo pipefail
  echo "//npm.pkg.github.com/:_authToken=${NPM_TOKEN}" >> ~/.npmrc
  npm install -g @acme/internal-cli@latest
provisioning_timeout: "10m"
secret_allowlist:
  - NPM_TOKEN
description: "Installs private npm packages"
```

### Listing recipes

```bash theme={null}
murmur get recipe
```

```
NAME               DESCRIPTION
python-toolchain   Python 3.12 with Poetry and Ruff
go-service         Go 1.22 with gopls, cross-substrate
private-deps       Installs private npm packages
```

### Reading a single recipe

```bash theme={null}
murmur get recipe python-toolchain
```

### Baking a recipe

After creating a [recipe](/concepts/recipe), [bake](/cli/bake) it to produce a runnable [image](/concepts/images):

```bash theme={null}
murmur bake python-toolchain prod us-central1
```

See the [custom images guide](/guides/custom-images) for a full walkthrough.

## Errors

| Code                  | Meaning                                                                      | What to do                                                                                                                                    |
| --------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `INVALID_ARGUMENT`    | `name is required`                                                           | Provide a `name` field.                                                                                                                       |
| `INVALID_ARGUMENT`    | `name must match [a-z][a-z0-9-]{0,62}`                                       | Use a lowercase DNS label — starts with a letter, only lowercase letters, digits, and hyphens, max 63 characters.                             |
| `INVALID_ARGUMENT`    | `at least one of base_image_aws_ref or base_image_gce_ref is required`       | Set `base_image_aws_ref`, `base_image_gce_ref`, or both.                                                                                      |
| `INVALID_ARGUMENT`    | `provisioning_script is required`                                            | Provide the script content in `provisioning_script`.                                                                                          |
| `INVALID_ARGUMENT`    | `provisioning_script exceeds 256 KiB limit`                                  | Reduce the script size. Move large assets to a remote location and fetch them during provisioning.                                            |
| `INVALID_ARGUMENT`    | `provisioning_timeout is required`                                           | Set `provisioning_timeout` to a Go duration string (e.g. `10m`).                                                                              |
| `INVALID_ARGUMENT`    | `provisioning_timeout: invalid duration`                                     | Use Go duration format: `10m`, `30m`, `1h`.                                                                                                   |
| `INVALID_ARGUMENT`    | `provisioning_timeout: duration must be positive`                            | The duration must be greater than zero.                                                                                                       |
| `INVALID_ARGUMENT`    | `provisioning_timeout exceeds 1h maximum`                                    | Reduce the timeout to 1 hour or less.                                                                                                         |
| `INVALID_ARGUMENT`    | `secret_allowlist[N]: secret name must match [A-Z][A-Z0-9_]*`                | Secret names use uppercase letters, digits, and underscores, starting with a letter.                                                          |
| `INVALID_ARGUMENT`    | `secret_allowlist[N]: secret name is reserved (MURMUR_*)`                    | Names starting with `MURMUR_` are reserved. Choose a different name.                                                                          |
| `INVALID_ARGUMENT`    | `description exceeds 1024 byte limit`                                        | Shorten the description to 1024 bytes or fewer.                                                                                               |
| `INVALID_ARGUMENT`    | `base_image_aws_ref "X" does not exist`                                      | The named [image](/concepts/images) does not exist in the catalog. Create it first or fix the name.                                           |
| `INVALID_ARGUMENT`    | `base_image_aws_ref "X" is not an AWS image`                                 | The referenced [image](/concepts/images) exists but has a GCE or Docker source, not AWS. Use an [image](/concepts/images) with an AWS source. |
| `INVALID_ARGUMENT`    | `base_image_gce_ref "X" does not exist`                                      | The named [image](/concepts/images) does not exist in the catalog. Create it first or fix the name.                                           |
| `INVALID_ARGUMENT`    | `base_image_gce_ref "X" is not a GCE image`                                  | The referenced [image](/concepts/images) exists but has an AWS or Docker source, not GCE. Use an [image](/concepts/images) with a GCE source. |
| `INVALID_ARGUMENT`    | `architecture mismatch: base_image_aws_ref is X but base_image_gce_ref is Y` | Both base [images](/concepts/images) must have the same architecture. Replace one so they match.                                              |
| `FAILED_PRECONDITION` | `cannot delete recipe "X": referenced by image: Y`                           | Baked [images](/concepts/images) reference this [recipe](/concepts/recipe). Delete the referencing [images](/concepts/images) first.          |

## Related

* [Recipe](/concepts/recipe) — concept overview
* [Images](/concepts/images) — the artifacts produced by baking a [recipe](/concepts/recipe)
* [Custom images guide](/guides/custom-images) — end-to-end walkthrough for building and using custom [images](/concepts/images)
* [`murmur set`](/cli/set) — CLI command for creating and updating catalog resources
* [`murmur get`](/cli/get) — CLI command for reading catalog resources
* [`murmur bake`](/cli/bake) — CLI command for baking a [recipe](/concepts/recipe) into an [image](/concepts/images)
