Pre-release Harn is pre-1.0 — the language, standard library, and CLI may change between releases. See the release notes

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 — fetch-harn.sh scripts, npm CLI postinstall hooks, 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 in the collect_candidate_manifest job of .github/workflows/build-release-binaries.yml, from the same candidate archives the release publishes. The candidate manifest lists it, so a release candidate with a broken or missing asset manifest fails its build run.

Schema#

{
  "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"]
    }
  }
}
KeyMeaning
versionSemver without the v prefix. Matches Cargo.toml's workspace version.
tagGit tag, with the v prefix.
release_urlHuman-readable releases-page URL.
assetsMap keyed by Rust target triple.
assets[triple].filenameArchive file name.
assets[triple].urlDeterministic GitHub-releases download URL.
assets[triple].sha256Lowercase hex SHA-256 of the archive bytes.
assets[triple].sizeArchive size in bytes.
assets[triple].format"tar.gz" or "zip".
assets[triple].binariesList 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.

Generated Agents API SDK clients are a separate release contract. They are not entries in release-assets.json. Downstream SDK repositories pin a Harn tag and download harn-sdk-python.tar.gz plus harn-sdk-typescript.tar.gz from that GitHub release. The retrieval path and fail-closed missing-language check live in spec/openapi-sdk-surface.md.

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.

Integrity metadata versus build provenance#

SHA256SUMS and release-assets.json are consumer integrity metadata. They let a downloader detect corruption or substitution relative to the metadata it fetched, but they do not prove which source revision or workflow produced an archive.

A release publishes exactly the files that main CI built and checked at the version commit. Nothing is rebuilt after it has been tested:

  1. The release commit is an ordinary pull request that changes the workspace version to a stable X.Y.Z.
  2. Its push to main runs build-release-binaries.yml in candidate mode at exactly that commit. The run builds, signs, notarizes, packages, and attests the five target archives, then builds SHA256SUMS, release-assets.json, and the release notes from those archives. It writes a candidate manifest (burin-labs.candidate_manifest.v1) that records the commit, the run, and the SHA-256 of every file, and uploads it as the run artifact candidate-manifest-<commit>.
  3. The same run checks those files. The residual release audit lanes run on the candidate's own Linux harn, restored from its archive and verified against the manifest. Release smoke runs each platform's archive, verified the same way. The run is green only if every check passed.
  4. A separate promotion workflow checks that the run passed at that commit, recomputes every file's digest and verifies its attestation against the manifest, then tags the commit and publishes those same files.

Every file the manifest lists has a GitHub artifact attestation with predicate type https://harnlang.com/attestations/release-archive/v1, signed by the candidate run at the version commit.

Historical release tags remain immutable at their original commits; automation never moves an existing public tag.

Adding a new target triple#

  1. Add the target and its warm, primary, recovery, standard, and fast runner labels to .github/release-runner-policy.json, then extend scripts/tests/release_runner_matrix_test.harn.
  2. Add the same target to the five-target lists in scripts/lib/candidate_archive_contract.sh and the collect_candidate_manifest 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 runner policy owns build-matrix targets and TARGETS owns manifest packaging. The workflow fails loudly if those contracts drift because the manifest assembler refuses a candidate that is missing any listed target.