# `release-assets.json` manifest

Every published GitHub release uploads a `release-assets.json` file
alongside the per-target archives. It is the consumer contract for
downstream packagers — `burin-code/scripts/fetch-harn.sh`, the
`@burin/cli` npm postinstall, Homebrew/Scoop formula generators —
so they can verify and download the right binary without scraping the
releases API.

The manifest is generated by
`scripts/build_release_assets_manifest.harn`, invoked from the
`Generate release-assets.json` step in
`.github/workflows/build-release-binaries.yml`. The manifest is in the
expected-assets list, so a release with a broken or missing manifest
fails the workflow early.

## Schema

```json
{
  "version": "0.8.21",
  "tag": "v0.8.21",
  "release_url": "https://github.com/burin-labs/harn/releases/tag/v0.8.21",
  "assets": {
    "x86_64-pc-windows-msvc": {
      "filename": "harn-x86_64-pc-windows-msvc.zip",
      "url":      "https://github.com/burin-labs/harn/releases/download/v0.8.21/harn-x86_64-pc-windows-msvc.zip",
      "sha256":   "<lowercase hex>",
      "size":     12345678,
      "format":   "zip",
      "binaries": ["harn.exe", "harn-dap.exe", "harn-lsp.exe"]
    },
    "aarch64-apple-darwin": {
      "filename": "harn-aarch64-apple-darwin.tar.gz",
      "url":      "...",
      "sha256":   "...",
      "size":     12345678,
      "format":   "tar.gz",
      "binaries": ["harn", "harn-dap", "harn-lsp"]
    },
    "x86_64-unknown-linux-gnu": {
      "filename": "harn-x86_64-unknown-linux-gnu.tar.gz",
      "url":      "...",
      "sha256":   "...",
      "size":     12345678,
      "format":   "tar.gz",
      "binaries": ["harn", "harn-dap", "harn-lsp", "harn-container-probe"]
    }
  }
}
```

| Key                                | Meaning |
| ---------------------------------- | --- |
| `version`                          | Semver without the `v` prefix. Matches `Cargo.toml`'s workspace version. |
| `tag`                              | Git tag, with the `v` prefix. |
| `release_url`                      | Human-readable releases-page URL. |
| `assets`                           | Map keyed by Rust target triple. |
| `assets[triple].filename`          | Archive file name. |
| `assets[triple].url`               | Deterministic GitHub-releases download URL. |
| `assets[triple].sha256`            | Lowercase hex SHA-256 of the archive bytes. |
| `assets[triple].size`              | Archive size in bytes. |
| `assets[triple].format`            | `"tar.gz"` or `"zip"`. |
| `assets[triple].binaries`          | List of files unpacked from the archive. |

Linux archives also include `harn-container-probe`, which the release
container image uses for its distroless health check. Installer scripts
may ignore that extra binary unless they are assembling the container
root filesystem.

The currently published target triples are:

- `aarch64-apple-darwin`
- `x86_64-apple-darwin`
- `x86_64-unknown-linux-gnu`
- `aarch64-unknown-linux-gnu`
- `x86_64-pc-windows-msvc`

## Stable URLs

The manifest is published as a release asset with two stable URLs:

- Pinned: `https://github.com/burin-labs/harn/releases/download/<tag>/release-assets.json`
- Latest: `https://github.com/burin-labs/harn/releases/latest/download/release-assets.json`

The pinned URL is the one downstream packagers should embed in
checked-in version files; the latest URL is for tooling that wants to
follow the moving target.

## Adding a new target triple

1. Add the target to the build matrix in
   `.github/workflows/build-release-binaries.yml`.
2. Add the same target to the `EXPECTED_ASSETS` list in the workflow's
   `setup` job and to the per-step expected lists in the `release` job.
3. Add a new entry to the `TARGETS` map in
   `scripts/build_release_assets_manifest.harn` with the matching filename,
   format, and binary names.
4. Make a note in `CHANGELOG.md` so downstream consumers know to bump
   their pinned manifest URL.

The triple key in `TARGETS` is the single source of truth — the
workflow fails loudly if a target appears in the matrix but not in the
manifest script, or vice versa, because the expected-assets list is
checked at multiple points.
