# Runner Image Manifest (schema_version: 1)

This document is the canonical reference for the `runner-image-manifest` schema. The schema is owned by this crate. ci-forge and other offline runners emit manifests conforming to v1 and pass them to the CLI for validation/probes.

The manifest is plain JSON. Field names use `snake_case`. Unknown top-level fields are ignored to allow future additive growth without breaking older readers; `schema_version: 1` is required and is the explicit version contract.

## Top level

```json
{
  "schema_version": 1,
  "tool": { "name": "<generator>", "version": "<x.y.z>" },
  "generated_at": "<RFC3339>",
  "image": { ... },
  "labels": ["..."],
  "capabilities": ["..."],
  "toolcache": { "root": "/opt/hostedtoolcache" },
  "tools": [ ... ],
  "packages": [ ... ],
  "environment": { "RUNNER_OS": "Linux", ... },
  "evidence": { ... }
}
```

| Field            | Required | Notes                                                                 |
| ---------------- | -------- | --------------------------------------------------------------------- |
| `schema_version` | yes      | Must be `1`.                                                          |
| `tool`           | no       | Identifies the generator.                                             |
| `generated_at`   | no       | RFC 3339 timestamp.                                                   |
| `image`          | yes      | Image identity. See below.                                            |
| `labels`         | no       | GitHub-Actions-style routing labels.                                  |
| `capabilities`   | no       | Open-ended set of capability strings (kebab-case lowercase).          |
| `toolcache`      | no       | Toolcache layout. Required if any tool sets `in_toolcache: true`.     |
| `tools`          | no       | Declared tool binaries.                                               |
| `packages`       | no       | Declared OS packages.                                                 |
| `environment`    | no       | Process environment defaults (`RUNNER_OS`, `RUNNER_ARCH`, etc).       |
| `evidence`       | no       | Pointers to upstream sources (e.g. runner-images README URLs).        |

## `image`

```json
{
  "name": "ci-forge/mortar-ubuntu-22.04",
  "tag": "local",
  "digest": "sha256:...",
  "os": {
    "family": "linux",
    "distro": "ubuntu",
    "version": "22.04",
    "arch": "x64"
  }
}
```

- `family`: one of `linux`, `macos`, `windows`.
- `arch`: canonical names are `x64`, `arm64`, `x86`, `arm`. Equivalents (`x86_64`, `amd64`, `aarch64`) normalize to canonical.

## `tools`

```json
{
  "name": "node",
  "version": "22.11.0",
  "arch": "x64",
  "path": "/opt/hostedtoolcache/node/22.11.0/x64",
  "aliases": ["22", "lts/jod"],
  "source": "actions/runner-images",
  "digest": "sha256:...",
  "in_toolcache": true,
  "version_flag": "--version"
}
```

- `aliases` are the offline name set used by `setup-node`. Broad specs (`22`, `lts/*`) only resolve when the manifest declares the alias.
- `in_toolcache: true` means the binary lives under `toolcache.root` and `actions/setup-node@v4` can stage it without download.
- `version_flag` defaults to `--version`. Set it for binaries that print version on a different flag (`-v`, `version`).

## `packages`

```json
{
  "manager": "apt",
  "name": "docker.io",
  "version": "27.3.1-0ubuntu1",
  "source": "ubuntu-22.04-archive"
}
```

Supported managers for probes: `apt`, `dpkg`, `dnf`, `yum`, `rpm`, `brew`, `apk`, `pacman`. Other manager strings are accepted in the manifest but `probe-host` / `probe-docker` will record a `probe.package_manager_unsupported` skip.

## `capabilities`

Open-ended kebab-case lowercase strings. Common values: `docker`, `docker-socket`, `podman`, `buildx`, `playwright-chromium`, `playwright-firefox`, `tauri-linux-build`, `cargo-advisory-tools`. Strings outside the well-known set are accepted (the catalog is intentionally open).

## `evidence`

```json
{
  "source_urls": [
    "https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md"
  ],
  "image_digest": "sha256:...",
  "probe_records": []
}
```

Free-form provenance. The `check` command does not enforce structure; it just records that evidence is present.

## Compatibility

- The schema is additive within `schema_version: 1`. New top-level keys may appear in later releases of this crate; ci-forge and other consumers should tolerate them.
- Renames or removals advance `schema_version`. The CLI hard-errors when a manifest's `schema_version` does not match `SCHEMA_VERSION` (currently `1`).
