# sandbox.yaml

`sandbox.yaml` defines your sandbox: the virtual machines, the tools in the UI, and how they connect.

All field names are **camelCase** — not snake_case.

## Minimal working example

```
apiVersion: p3.ed.linuxfoundation.org/v1alpha1
kind: SandboxBlueprint
metadata:
  name: my-sandbox
spec:
  virtualmachines:
    - name: host1
      baseImage: ubuntu
  tools:
    - name: terminal
      terminal:
        version: v1
        targetHost: host1
        targetUser: tux
    - name: instructions
      instructions:
        version: v1
        sourcePath: task.en.md
  ui:
    version: v1
    defaultTool: terminal
    showTimer: false
```

---

## Virtual machines

```
spec:
  virtualmachines:
    - name: host1
      baseImage: ubuntu
      ports:
        - "*"
      resources:
        requests:
          memory: "2Gi"
          cpu: "1"
        limits:
          memory: "4Gi"
          storage: "10Gi"
```

| Field | Required | Default | Description |
| --- | --- | --- | --- |
| `name` | Yes | — | VM hostname. Lowercase alphanumeric and hyphens only. |
| `baseImage` | Yes | — | Image shorthand or full URL. See [base images](#base-images). |
| `user` | No | `tux` | Primary user account on the VM. |
| `ports` | No | `["*"]` | Ports to expose. Single (`"80"`), range (`"8000-8080"`), or `"*"` for all. |
| `resources` | No | — | CPU and memory allocation. |

### Resources

```
resources:
  requests:
    memory: "2Gi" # minimum
    cpu: "1"
  limits:
    memory: "4Gi" # maximum
    storage: "10Gi" # overlay disk size
```

Memory and storage use binary units: `Mi`, `Gi`. CPU uses cores (`"1"`, `"2.5"`) or millicores (`"500m"`).

---

## Tools

Each tool entry requires a `name` and exactly one tool type block.

### Terminal

```
- name: terminal
  terminal:
    version: v1
    targetHost: host1
    targetUser: student
```

| Field | Required | Description |
| --- | --- | --- |
| `version` | Yes | Always `v1`. |
| `targetHost` | Yes | VM to connect to. Must match a VM `name`. |
| `targetUser` | Yes | User to connect as. |

Warning

The field is `targetHost` — not `target`, not `host`. Validation will fail silently with the wrong name.

For multi-VM sandboxes, add one terminal per VM:

```
- name: cp-terminal
  terminal:
    version: v1
    targetHost: cp
    targetUser: student
- name: worker-terminal
  terminal:
    version: v1
    targetHost: worker
    targetUser: student
```

### IDE

```
- name: editor
  ide:
    version: v1
    targetHost: host1
    targetUser: student
    workspaceDir: /home/student/project
```

| Field | Required | Description |
| --- | --- | --- |
| `version` | Yes | Always `v1`. |
| `targetHost` | Yes | VM to connect to via SSHFS. |
| `targetUser` | Yes | User for the SSHFS connection. |
| `workspaceDir` | No | Directory to open. Defaults to the user's home directory. |

### Browser

```
- name: browser
  browser:
    version: v1
    startingURL: "http://host1:8080"
    kioskMode: true
```

| Field | Required | Description |
| --- | --- | --- |
| `version` | Yes | Always `v1`. |
| `startingURL` | Yes | URL to open on launch. Use the VM `name` as the hostname (e.g. `http://host1:8080`). |
| `kioskMode` | No | Hide the browser toolbar. Defaults to `false`. |

### Instructions

```
- name: instructions
  instructions:
    version: v1
    sourcePath: task.en.md
```

| Field | Required | Description |
| --- | --- | --- |
| `version` | Yes | Always `v1`. |
| `sourcePath` | Yes | Path to the markdown file, relative to the sandbox root. |

---

## UI

```
ui:
  version: v1
  defaultTool: terminal
  showTimer: false
```

| Field | Required | Description |
| --- | --- | --- |
| `version` | Yes | Always `v1`. |
| `defaultTool` | Yes | Tool shown when the sandbox opens. Must exactly match a tool `name`. |
| `showTimer` | No | Show a countdown timer. Required `true` for labs. Defaults to `true`. |

---

## TTL

```
spec:
  ttlSeconds: 3600
```

How long the sandbox runs before automatic teardown. Defaults to `3600` (1 hour). Maximum is `86400` (24 hours). Not enforced during local development with `sandbox shell`.

---

## Base images

Write a shorthand name in `baseImage` — the CLI resolves it to `ghcr.io/lf-certification/sandbox-vm-<name>` automatically. Use the full image URL only when referencing an image outside this registry.

| `baseImage` | OS | Pre-installed |
| --- | --- | --- |
| `ubuntu` | Ubuntu 24.04 (noble) | — |
| `debian` | Debian 13 (trixie) | — |
| `k3s` | Debian 13 (trixie) | K3s 1.35.2 |
| `k8s` | Debian 13 (trixie) | Kubernetes 1.35.2 |
| `k8sn` | Debian 13 (trixie) | Kubernetes 1.35.2, nerdctl |

---

## Multi-VM example

A two-node Kubernetes cluster with a terminal for each node:

```
apiVersion: p3.ed.linuxfoundation.org/v1alpha1
kind: SandboxBlueprint
metadata:
  name: kubernetes-lab
spec:
  ttlSeconds: 7200
  virtualmachines:
    - name: cp
      baseImage: k8sn
      ports:
        - "6443"
        - "2379-2380"
        - "10250"
      resources:
        requests:
          memory: "2Gi"
    - name: worker
      baseImage: k8sn
      ports:
        - "10250"
        - "30000-32767"
      resources:
        requests:
          memory: "2Gi"
  tools:
    - name: cp
      terminal:
        version: v1
        targetHost: cp
        targetUser: tux
    - name: worker
      terminal:
        version: v1
        targetHost: worker
        targetUser: tux
    - name: instructions
      instructions:
        version: v1
        sourcePath: instructions.md
  ui:
    version: v1
    defaultTool: cp
    showTimer: true
```

Develop against both VMs using [background live reload and independent attached terminals](https://skills.staging.lf-cert.cloud/docs/sandbox/cli/#sandbox-start-and-stop). Changes to this blueprint require stopping and starting the affected VMs; source watching does not reconfigure a running VM from `sandbox.yaml`.
