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

# Workspace Images

> Build custom Docker images for your task environments.

Workspace images let you build custom container runtimes with your project's dependencies pre-installed. Instead of installing tools on every task startup, bake them into an image once and every new task launches ready to go.

There are two workflows: **manual** (paste a Dockerfile in settings) and **repo-managed** (commit a Dockerfile in your repo and let Whim rebuild automatically on branch changes).

<CardGroup cols={2}>
  <Card title="Manual" icon="pen">
    Paste a Dockerfile into **Settings > Images**. Best for simple, project-wide customizations.
  </Card>

  <Card title="Repo-managed" icon="code-branch">
    Add config to `whim.json` or `package.json`, commit a Dockerfile, and Whim builds branch-specific images automatically.
  </Card>
</CardGroup>

## Manual setup

<Steps>
  <Step title="Create a new image">
    Navigate to **Workspace Settings** > **Images** and click **New Image**. Paste a full Dockerfile.
  </Step>

  <Step title="Watch the build">
    Builds run remotely. If something fails, check the **Build Log** tab.
  </Step>

  <Step title="Activation">
    Builds started from **Settings > Images** auto-activate after they pass runtime compatibility validation. If you start a build through the API or agent tooling without auto-activation, activate the ready image manually.
  </Step>
</Steps>

```dockerfile theme={null}
ARG RUNNER_COMPAT_REF
FROM ${RUNNER_COMPAT_REF}

USER root
RUN apt-get update && apt-get install -y git ripgrep
RUN python3 -m pip install --no-cache-dir poetry ruff
USER node
```

<Note>
  Manual builds use a Dockerfile-only context — no local files. Use inline heredoc `COPY`/`ADD` or `COPY --from=...` from earlier stages.
</Note>

## Repo-managed setup

Add image configuration to your repository root. Whim checks `whim.json` first, then falls back to the `whim.image` field in `package.json`.

```json whim.json theme={null}
{
  "image": {
    "dockerfile": "Dockerfile.whim",
    "context": ".",
    "stagedFiles": ["package.json", "pnpm-lock.yaml"],
    "buildSecrets": ["NPM_TOKEN"]
  }
}
```

| Field          | Description                                                                                                                                                   |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dockerfile`   | Path to the Dockerfile relative to repo root                                                                                                                  |
| `context`      | Build context directory (usually `"."`)                                                                                                                       |
| `stagedFiles`  | Files available for `COPY`/`ADD` during build                                                                                                                 |
| `buildSecrets` | Workspace env var names exposed as build secrets. `GITHUB_TOKEN` is platform-managed for repo-managed builds — only list additional secrets like `NPM_TOKEN`. |

```dockerfile Dockerfile.whim theme={null}
ARG RUNNER_COMPAT_REF
FROM ${RUNNER_COMPAT_REF}

COPY package.json pnpm-lock.yaml /app/
RUN cd /app && pnpm install --frozen-lockfile

USER root
RUN python3 -m pip install --no-cache-dir poetry ruff
USER node
```

After committing the config and Dockerfile, go to **Settings > Images** and track the branch. The default branch is tracked automatically; non-default branches must be explicitly tracked.

## Dockerfile rules

These apply to both manual and repo-managed Dockerfiles:

* **Must start with** `ARG RUNNER_COMPAT_REF` and the final stage must use `FROM ${RUNNER_COMPAT_REF}`. Whim resolves this to the workspace-compatible runner image at build time.
* **Repo-managed builds** can only `COPY`/`ADD` files listed in `stagedFiles`.
* **Image freshness** is determined by hashing the normalized config, Dockerfile content, and `stagedFiles` contents — not the entire repo.
* **Multi-stage builds** work as long as you use `COPY --from=...` between stages.
* **Build secrets** referenced in `buildSecrets` must exist as [workspace environment variables](/workspaces/settings-and-environment#environment-variables). For repo-managed builds, `GITHUB_TOKEN` is automatically provided by the platform — you don't need to list it or set it as an env var.

## Build status

| Status       | Description                               |
| ------------ | ----------------------------------------- |
| **Building** | Docker build running remotely             |
| **Ready**    | Build succeeded, available for activation |
| **Failed**   | Build failed — check the build log        |

After a successful build, Whim validates **runtime compatibility**. An image must be both Ready and Compatible before activation.

## Activating images

Only one image can be active per workspace (or per tracked branch for repo-managed workflows).

* **Activate** — sets the image as active and triggers warm reserve pool rebuild. Only Ready + Compatible images can be activated.
* **Deactivate** — removes the active image. Tasks fall back to the default Whim runtime.

<Warning>
  Only team admins can build, activate, delete, or track workspace images.
</Warning>

## Warm reserves

Warm reserves are pre-created, suspended machines running your custom image. When a task starts, Whim claims a reserve and resumes it instantly instead of building a new container.

### How it works

1. Whim creates machines with your image and initializes them
2. Machines are **suspended** — no compute cost, but ready to go
3. When a task starts, Whim claims an available machine, resumes it, and injects the task config
4. If no reserve is available, Whim falls back to creating a new container (slower startup)

### Reserve targets

Each tracked branch has a reserve target (0–20 machines). Default branch reserves are included in your plan:

| Plan | Included reserves |
| ---- | ----------------- |
| Free | 3 machines        |
| Pro  | 5 machines        |
| Max  | 10 machines       |

Machines above the included amount, and all non-default branch reserves, cost **3 CU per week** each (prorated).

<Tip>
  Warm starts are best-effort. Even with reserves configured, the pool can be empty. Whim falls back to creating a new container if needed.
</Tip>

## Branch tracking

For repo-managed workflows, branch tracking controls which branches get dedicated images and warm reserves.

* **Default branch** — automatically tracked, uses plan-included reserve capacity.
* **Non-default branches** — must be explicitly tracked from **Settings > Images**. Reserve machines consume CU.
* **Fallback** — if a tracked branch's image isn't ready yet, tasks may launch with a similar image or the default runtime.
* **Stale cleanup** — branches with no task activity for 14 days are automatically untracked.

## Agent workflow

Inside Whim task containers, agents can help create and update workspace images.

* The built-in `setup-workspace-image` skill can inspect the repo, draft a compliant Dockerfile, and update existing image definitions.
* For manual images, agents can use the built-in `images` MCP tool to list images, start a build from a full Dockerfile, fetch build logs, activate ready images, and delete old images.
* Repo-managed image work still happens as repo changes: update `whim.json` or `package.json`, edit the Dockerfile in git, commit the changes, then track the branch from **Settings > Images** if it is not already tracked.

## Baked repository

The baked-repo optimization pre-clones your repository into the workspace image at build time. When a task starts, Whim runs a fast `git fetch` to freshen the clone instead of doing a full clone from scratch — significantly faster startup for large repos.

### How it works

Use `RUN --mount=type=secret,id=GITHUB_TOKEN` in your Dockerfile to clone the repo during the build:

```dockerfile Dockerfile.whim theme={null}
ARG RUNNER_COMPAT_REF
FROM ${RUNNER_COMPAT_REF}

RUN --mount=type=secret,id=GITHUB_TOKEN \
    git clone https://x-access-token:$(cat /run/secrets/GITHUB_TOKEN)@github.com/your-org/your-repo /home/node/repo
```

For repo-managed builds, Whim automatically injects `GITHUB_TOKEN` using its GitHub App installation — no personal access tokens or workspace environment variables needed. At task startup, the pre-cloned repo is freshened with `git fetch` rather than cloned from scratch.

<Note>
  Baked-repo builds only work with repo-managed setups. Whim needs GitHub App access to the repository to inject the token at build time.
</Note>

### Overriding the token

If you need to access a different repository than the one connected to the workspace, declare `GITHUB_TOKEN` in `buildSecrets` and set it as a workspace environment variable. A user-supplied value takes precedence over the auto-injected platform token.

## Mixing workflows

Manual and repo-managed images can coexist, but behavior is easier to reason about if you standardize on one.
