# Releasing

> How rt-core runtime packages are built, identified and verified, how robot-stack bundles are assembled offline, and what a release does and does not claim. Provisional.

URL: https://advancedmetalresearch.com/docs/contributing/releasing
Section: RosieOS docs / Contributing
Last updated: 2026-10-10

> [!NOTE] **Provisional.** RosieOS has no published public release process yet. This page describes the packaging and bundling tools that exist in the repository today. Expect it to change.

There are two layers: an **rt-core runtime package**, which is what a cell host installs, and a **robot-stack bundle**, which pins a set of component artifacts together. Neither contacts a device, and neither qualifies hardware.

## rt-core runtime package

Build a package from a clean, built tree:

```bash
cd rt-core
bash tools/build-igh-userlib.sh
export PKG_CONFIG_PATH="$PWD/build/deps/igh-prefix/lib/pkgconfig"
make live control
SOURCE_DATE_EPOCH=$(git log -1 --format=%ct) bash tools/package-runtime.sh /tmp/rt-package
# package status=staged backend=live
# component status=staged output=/tmp/rt-package.components
bash tools/verify-package.sh /tmp/rt-package
```

`package-runtime.sh DESTINATION` requires an empty or absent destination. It refuses a daemon whose built source identity differs from `git describe --always --dirty` ("daemon source identity is stale … rebuild it"), so rebuild after every commit.

### Package contents

| Path | Contents |
|---|---|
| `bin/` | `rosie-rt-core`, `rt-control`, `rtctl`, `rt-package`, and `rt-natspublisher` if built |
| `lib/libethercat.so.1`, `licenses/igh/` | The IgH userspace library the core links against, with its licence files |
| `host/` | `install.sh`, `generate-control-env.sh`, `remote-pki.sh`, `ethercat-foundation.sh`, `run-core`, and the three unit files, rewritten for the slot root |
| `tools/verify-package.sh` | The verifier |
| `config/` | The rt-core configuration tree |
| `robot_description/robots/…` | Every robot description's manifest and registered files, so a cell can compile its machine config from the package |
| `rt_package.json` | The package manifest |

### The manifest

`rt_package.json` has schema `rosie.rt-core.package.v1`. It records the backend (`live` or `simulation`), the component version, every file with its mode, install mode and SHA-256 (and, for ELF files, the machine, needed libraries, symbol versions and interpreter), and the build inputs:

| Input | Description |
|---|---|
| `git_sha`, `dirty` | Source commit, and whether the tree had uncommitted or untracked changes |
| `daemon_version` | The core's own `--version` |
| `compiler`, `go` | Toolchain versions |
| `igh_version`, `igh_archive_sha256` | The pinned IgH release |
| `architecture`, `build_kernel`, `kernel_requirement` | Target and build host facts |
| `source_date_epoch` | `SOURCE_DATE_EPOCH`, if set, for reproducible timestamps |

A cell host stores each installed release under its 40-hex git SHA and refuses to replace one with different bytes under the same identity. See [Install rt-core on a cell host](https://advancedmetalresearch.com/docs/guides/install-on-a-cell-host#install).

### Component archive

Beside the package, `DESTINATION.components/` holds what a release publishes:

| File | Contents |
|---|---|
| `rosie-rt-core-<version>-linux-<arch>.tar.gz` | The runtime archive (`<arch>` is the ELF machine: x86-64 or aarch64) |
| `rosie-rt-core.json` | The component descriptor: name, role, version, runtime requirements, receipts |
| `rt_package.json` | The manifest |
| `build.log`, `verify-package.log` | Receipts. Pass the producer's build log with `ROSIE_RT_PACKAGE_BUILD_LOG`. |
| `SHA256SUMS` | Checksums of the above |

The component version comes from the packaging tool (currently `0.1.0`).

### Options

| Variable | Default | Description |
|---|---|---|
| `ROSIE_RT_PACKAGE_SLOT_ROOT` | `/opt/rosie-rt-core/current` | Absolute path the unit files point at. Not under `/home`, `/root` or `/run/user`. |
| `ROSIE_RT_PACKAGE_BUILD_LOG` | — | A non-empty build log to include as a receipt. |
| `ROSIE_RT_PACKAGE_CORE` | `build/rosie-rt-core` | Set to `build/rosie-rt-core-sim` to build a `simulation` package. No other substitution is allowed. |
| `SOURCE_DATE_EPOCH` | — | Integer seconds; stamps every file's time. |
| `ECRT_LICENSE_DIR` | `build/deps/ethercat-<version>` | Where the IgH `COPYING` files are. |
| `GO` | `go` | Go command used to build `rt-package`. |

### Verify

```bash
bash tools/verify-package.sh /tmp/rt-package            # exit 0 on success, 3 if the inspector is missing
build/rt-package git-sha /tmp/rt-package
build/rt-package backend /tmp/rt-package
```

`verify-package.sh` runs `rt-package verify`, which checks every payload hash and the definition-bound robot resources without executing any packaged code. `rt-package` also has `manifest` and `component`, which `package-runtime.sh` calls.

## Robot-stack bundles

A robot-stack release pins several components by exact commit and artifact hash. The specification is a `rosie.robot-stack.release.v1` JSON file under `releases/robot-stack/`. `releases/robot-stack/next/` is a draft covering the native rt-core package only; `v0.1.0/` is the historical record of an earlier release.

`tools/robot-stack-release/bundle.py` works entirely offline:

```bash
uv run --no-project python tools/robot-stack-release/bundle.py package \
  --spec releases/robot-stack/<release>/release.json --repo . --inputs <artifacts-dir> --bundle <new-bundle-dir>
uv run --no-project python tools/robot-stack-release/bundle.py verify \
  --spec releases/robot-stack/<release>/release.json --bundle <bundle-dir>
uv run --no-project python tools/robot-stack-release/bundle.py archives \
  --spec releases/robot-stack/<release>/release.json --bundle <bundle-dir> --output <dir>
```

| Command | Does |
|---|---|
| `package` | Reads source by the specification's exact commits (never by a moving tag) and the retained artifacts, and writes a bundle. It never fetches. |
| `verify` | Checks a bundle's integrity and completeness against the specification. |
| `archives` | Writes release archives and a `SHA256SUMS` to `--output`. |

On success it prints `passed: bundle integrity/completeness only; no deployment or physical claim`, and on failure `rejected: <reason>` with exit 1.

`tools/robot-stack-release/prepare.py` prepares an offline install packet from a verified bundle (`--spec`, `--bundle`, `--manifest`, `--fixture`, `--selection`, `--cell`, `--home`, `--output`). It refuses retired components and never contacts or restarts a device.

Run the tools' tests with:

```bash
uv run --no-project python -m unittest discover -s tools/robot-stack-release -v
```

## What a release claims

A package or bundle that verifies proves that its bytes are the ones recorded. It does not prove installation on a host, controller admission, or anything about powered motion. Hardware qualification of a cell is separate, manual work by the cell owner. See the [safety model](https://advancedmetalresearch.com/docs/get-started/safety-model#simulation).

## Sources

Written from these files in the RosieOS repository (https://github.com/advanced-metal-research/RosieOS):

- `rt-core/tools/package-runtime.sh:1-101`
- `rt-core/tools/verify-package.sh:1-9`
- `rt-core/tools/packageinfo/main.go:18-70,280-310,620-653`
- `rt-core/tools/packageinfo/component.go:17,50-110,150-245`
- `rt-core/host/install.sh:48-97`
- `rt-core/Makefile:7-16`
- `tools/robot-stack-release/bundle.py:1-215`
- `tools/robot-stack-release/prepare.py:1-125`
- `releases/robot-stack/<release>/release.json:1-10`
