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

# workspace

> Catalog resource that composes an image, environment, placement, repos, and secrets into a launchable configuration for spawning agents.

A [workspace](/concepts/workspaces) is a catalog resource that brings together everything an agent needs to run — an [image](/concepts/images), an [environment](/concepts/environments), a [placement](/concepts/placement), one or more repos, and optional [secrets](/concepts/secrets). When you spawn an agent, you specify a [workspace](/concepts/workspaces) and the platform uses it to provision the VM.

## Fields

| Name                    | Type      | Required | Description                                                                                                                             |
| ----------------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                  | string    | yes      | Unique identifier. DNS label format: `[a-z][a-z0-9-]{0,62}`.                                                                            |
| `image_ref`             | string    | yes      | [Image](/concepts/images) name. Must reference an existing image in the same tenant.                                                    |
| `environment_ref`       | string    | yes      | [Environment](/concepts/environments) name. Must reference an existing environment in the same tenant.                                  |
| `placement`             | string    | yes      | [Placement](/concepts/placement) name. Must reference an existing placement in the same tenant.                                         |
| `repos`                 | object\[] | yes      | One or more repos to clone. At least one is required. See [Repo fields](#repo-fields).                                                  |
| `min_idle`              | int       | no       | Minimum warm VMs to keep idle in the pool. `0` disables prewarming. Default: `0`.                                                       |
| `secret_refs`           | string\[] | no       | [Secret](/concepts/secrets) names exposed to agents as environment variables. Each must reference an existing secret.                   |
| `runtime_secret_mounts` | object\[] | no       | [Secrets](/concepts/secrets) delivered to agent VMs as environment variables or files. See [Secret mount fields](#secret-mount-fields). |
| `ports`                 | object\[] | no       | Labeled ports surfaced in the dashboard. See [Port label fields](#port-label-fields).                                                   |
| `description`           | string    | no       | Human-readable description shown in the dashboard. Max 1024 bytes.                                                                      |

## Repo fields

Each entry in `repos` describes a repository the agent clones at startup.

| Name                  | Type   | Required | Description                                                                                                                   |
| --------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `clone_url`           | string | yes      | HTTPS clone URL of the repository. Automatically canonicalized (trailing `.git` stripped).                                    |
| `base_branch`         | string | yes      | Branch to branch from (e.g. `main`).                                                                                          |
| `conflict_resolution` | string | no       | Strategy for file-changed events. Values: `MERGE` (default), `REBASE`, `NONE`. `NONE` opts out of file-changed notifications. |

<Note>
  Clone URLs are canonicalized on write — `https://github.com/acme/app.git` becomes `https://github.com/acme/app`.
</Note>

## Secret mount fields

Each entry in `runtime_secret_mounts` declares how a [secret](/concepts/secrets) is delivered to the agent VM.

| Name         | Type   | Required    | Description                                                                                                                                                                                                                                                                                                                                                               |
| ------------ | ------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`       | string | yes         | Name of an existing [secret](/concepts/secrets) in the same tenant.                                                                                                                                                                                                                                                                                                       |
| `mount_type` | string | yes         | How the secret is delivered. Values: `ENV` (environment variable), `FILE` (written to disk).                                                                                                                                                                                                                                                                              |
| `path`       | string | conditional | Absolute file path on the VM. Required when `mount_type` is `FILE`.                                                                                                                                                                                                                                                                                                       |
| `mode`       | string | no          | File permission mode in octal (e.g. `"0600"`). Defaults to `"0600"` for `FILE` mounts.                                                                                                                                                                                                                                                                                    |
| `env_name`   | string | no          | `ENV` mounts only. Environment variable the secret value is delivered as, instead of the secret name (which is then not exported). Must match `[A-Za-z_][A-Za-z0-9_]*`; platform-delivered variables (`GH_TOKEN`, `ANTHROPIC_API_KEY`, `CLAUDE_CODE_OAUTH_TOKEN`, `OPENAI_API_KEY`, git plumbing, `MURMUR_*`) are rejected. Empty delivers the secret under its own name. |

<Warning>
  File mount paths must be absolute and unique within a single [workspace](/concepts/workspaces). Duplicate paths are rejected. Likewise, two `ENV` mounts may not deliver the same environment variable — each mount's `env_name` (or secret name, when `env_name` is empty) must be unique.
</Warning>

## Port label fields

Each entry in `ports` maps a TCP port number to a human-readable label shown in the dashboard.

| Name    | Type   | Required | Description                                     |
| ------- | ------ | -------- | ----------------------------------------------- |
| `port`  | int    | yes      | TCP port number (1–65535).                      |
| `label` | string | yes      | Human-readable purpose (e.g. `"web"`, `"api"`). |

## Validation

The platform validates cross-resource consistency when you create or update a [workspace](/concepts/workspaces):

* The [image](/concepts/images) and [placement](/concepts/placement) must target the same cloud provider. An [image](/concepts/images) built for one provider cannot run on a [placement](/concepts/placement) configured for another.
* For AWS [placements](/concepts/placement), the [image](/concepts/images) must be available in the [placement](/concepts/placement) region.
* The [image](/concepts/images) architecture must match the machine type architecture specified by the [environment](/concepts/environments).
* The [environment](/concepts/environments) cloud provider must match the [placement](/concepts/placement) cloud provider.
* The machine type referenced by the [environment](/concepts/environments) must be available in the [placement](/concepts/placement) region.
* You cannot remove a repo from a [workspace](/concepts/workspaces) if a [flight](/concepts/flights) trigger still references that repo.

## Examples

### Minimal workspace

```yaml theme={null}
name: default
image_ref: murmur-ubuntu-24
environment_ref: murmur-medium
placement: murmur-gcp-us-central1
repos:
  - clone_url: https://github.com/acme/backend
    base_branch: main
```

```bash theme={null}
cat <<'EOF' | murmur set workspace default
name: default
image_ref: murmur-ubuntu-24
environment_ref: murmur-medium
placement: murmur-gcp-us-central1
repos:
  - clone_url: https://github.com/acme/backend
    base_branch: main
EOF
```

### Workspace with secrets and port labels

```yaml theme={null}
name: fullstack
image_ref: murmur-ubuntu-24
environment_ref: murmur-large
placement: murmur-gcp-us-central1
repos:
  - clone_url: https://github.com/acme/backend
    base_branch: main
  - clone_url: https://github.com/acme/frontend
    base_branch: main
secret_refs:
  - npm-token
runtime_secret_mounts:
  - name: DOCKER_CONFIG_JSON
    mount_type: FILE
    path: /home/user/.docker/config.json
    mode: "0600"
  - name: NPM_PUBLISH_TOKEN
    mount_type: ENV
    env_name: NODE_AUTH_TOKEN
ports:
  - port: 3000
    label: web
  - port: 8080
    label: api
min_idle: 2
description: "Full-stack workspace with frontend and backend repos"
```

### Listing workspaces

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

```
NAME        IMAGE               ENVIRONMENT    PLACEMENT                DESCRIPTION
default     murmur-ubuntu-24    murmur-medium  murmur-gcp-us-central1
fullstack   murmur-ubuntu-24    murmur-large   murmur-gcp-us-central1   Full-stack workspace with frontend and backend repos
```

### Reading a single workspace

```bash theme={null}
murmur get workspace default
```

## 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 DNS label: starts with a lowercase letter, only lowercase letters, digits, and hyphens, max 63 characters.                                                              |
| `INVALID_ARGUMENT`    | `image_ref is required`                                                                                   | Set `image_ref` to the name of an existing [image](/concepts/images).                                                                                                         |
| `INVALID_ARGUMENT`    | `environment_ref is required`                                                                             | Set `environment_ref` to the name of an existing [environment](/concepts/environments).                                                                                       |
| `INVALID_ARGUMENT`    | `placement is required`                                                                                   | Set `placement` to the name of an existing [placement](/concepts/placement).                                                                                                  |
| `INVALID_ARGUMENT`    | `at least one repo is required`                                                                           | Add at least one entry to `repos`.                                                                                                                                            |
| `INVALID_ARGUMENT`    | `repo clone_url is required`                                                                              | Every repo entry needs a `clone_url`.                                                                                                                                         |
| `INVALID_ARGUMENT`    | `repo base_branch is required`                                                                            | Every repo entry needs a `base_branch`.                                                                                                                                       |
| `INVALID_ARGUMENT`    | `image "<name>" does not exist`                                                                           | The `image_ref` does not match any [image](/concepts/images) in your tenant. Check the name with [`murmur get image`](/cli/get).                                              |
| `INVALID_ARGUMENT`    | `environment "<name>" does not exist`                                                                     | The `environment_ref` does not match any [environment](/concepts/environments) in your tenant. Check the name with [`murmur get environment`](/cli/get).                      |
| `INVALID_ARGUMENT`    | `placement "<name>" does not exist`                                                                       | The `placement` does not match any [placement](/concepts/placement) in your tenant. Check the name with [`murmur get placement`](/cli/get).                                   |
| `INVALID_ARGUMENT`    | `substrate mismatch: image "<image>" is <X> but placement "<placement>" is <Y>`                           | The [image](/concepts/images) targets a different cloud provider than the [placement](/concepts/placement). Use an [image](/concepts/images) that matches.                    |
| `INVALID_ARGUMENT`    | `image "<name>" not available in region "<region>"`                                                       | The [image](/concepts/images) has no AMI in the [placement](/concepts/placement) region. Use an [image](/concepts/images) available in that region.                           |
| `INVALID_ARGUMENT`    | `architecture mismatch: image "<image>" is <X> but machine type "<mt>" is <Y>`                            | The [image](/concepts/images) architecture does not match the machine type in the [environment](/concepts/environments). Choose compatible resources.                         |
| `INVALID_ARGUMENT`    | `machine type "<name>" is not available in region "<region>" (placement "<placement>")`                   | The machine type referenced by the [environment](/concepts/environments) is not offered in the [placement](/concepts/placement) region.                                       |
| `INVALID_ARGUMENT`    | `substrate mismatch: environment "<env>" is <X> but placement "<placement>" is <Y>`                       | The [environment](/concepts/environments) targets a different cloud provider than the [placement](/concepts/placement).                                                       |
| `INVALID_ARGUMENT`    | `secret_refs[<i>]: secret "<name>" does not exist`                                                        | A [secret](/concepts/secrets) in `secret_refs` does not exist. Create it first with [`murmur secret set`](/cli/secret-set).                                                   |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>].name is required`                                                             | Every secret mount needs a `name`.                                                                                                                                            |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>].mount_type is required`                                                       | Every secret mount needs a `mount_type` — either `ENV` or `FILE`.                                                                                                             |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>].path is required for FILE mounts`                                             | File mounts need an absolute `path`.                                                                                                                                          |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>].path must be absolute`                                                        | The `path` must start with `/`.                                                                                                                                               |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>]: duplicate path "<path>"`                                                     | Two file mounts share the same path. Each must be unique.                                                                                                                     |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>].mode: invalid octal "<value>"`                                                | The `mode` is not valid octal. Use a string like `"0600"`.                                                                                                                    |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>].env_name is only valid for ENV mounts`                                        | `env_name` was set on a `FILE` mount. Use `path` to control where a `FILE` mount lands.                                                                                       |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>].path is only valid for FILE mounts`                                           | `path` was set on an `ENV` mount. Use `env_name` to control the variable an `ENV` mount is delivered as.                                                                      |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>].mode is only valid for FILE mounts`                                           | `mode` was set on an `ENV` mount.                                                                                                                                             |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>].env_name: "<value>" is not a valid environment variable name`                 | `env_name` must match `[A-Za-z_][A-Za-z0-9_]*`.                                                                                                                               |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>].env_name: "<value>" is reserved (would shadow a platform-delivered variable)` | The variable is delivered by the platform itself (`GH_TOKEN`, `ANTHROPIC_API_KEY`, `CLAUDE_CODE_OAUTH_TOKEN`, `OPENAI_API_KEY`, git plumbing, `MURMUR_*`). Pick another name. |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>]: duplicate environment variable "<name>"`                                     | Two `ENV` mounts deliver the same variable. Each mount's `env_name` (or secret name when `env_name` is empty) must be unique.                                                 |
| `INVALID_ARGUMENT`    | `runtime_secret_mounts[<i>]: secret "<name>" does not exist`                                              | A [secret](/concepts/secrets) referenced by a mount does not exist. Create it first.                                                                                          |
| `INVALID_ARGUMENT`    | `description exceeds 1024 byte limit (<n> bytes)`                                                         | Shorten the `description` to 1024 bytes or fewer.                                                                                                                             |
| `FAILED_PRECONDITION` | `cannot delete workspace "<name>": referenced by flight: <flight>`                                        | A [flight](/concepts/flights) references this [workspace](/concepts/workspaces). Delete or update the [flight](/concepts/flights) first.                                      |
| `FAILED_PRECONDITION` | `cannot remove repo "<url>" from workspace "<name>": flight "<flight>" trigger references it`             | A [flight](/concepts/flights) trigger references this repo. Update the [flight](/concepts/flights) trigger before removing the repo.                                          |

## Related

* [Workspaces](/concepts/workspaces) — concept overview
* [Placements](/catalog/placement) — the placement resource a workspace references
* [Environments and placements](/concepts/environments) — concept overview for environments
* [Images](/concepts/images) — the image resource a workspace references
* [Secrets](/concepts/secrets) — secrets referenced by `secret_refs` and `runtime_secret_mounts`
* [Flights](/concepts/flights) — flights that reference a workspace
* [`murmur set`](/cli/set) — CLI command for creating and updating catalog resources
* [`murmur get`](/cli/get) — CLI command for reading catalog resources
