---
name: iso-publish
description: Publish a completed Clawdie operator USB image from tmp/output to the OSA nginx downloads webroot, generating compression/checksum/manifest when needed, rotating public symlinks, updating the simple index.html, and verifying download URLs.
---

# iso-publish

Use this skill after `iso-build` succeeds and the operator wants the image made
available at `https://osa.smilepowered.org/downloads/iso/`.

Only publish when the operator explicitly assigns it. Publishing changes the
public download target.

## Paths

- Repo root: `/home/clawdie/ai/clawdie-iso`
- Build output: `tmp/output`
- Public webroot: `/usr/local/www/osa/downloads/iso`
- Public base URL: `https://osa.smilepowered.org/downloads/iso`

## Manifest contract

`scripts/write-artifact-manifest.sh` writes the canonical
`clawdie.iso.publish.v1` manifest beside the image as
`tmp/output/<image>.manifest.json`. Hermes consumes that file for
`iso-flash-verify`; Colibri can ingest it directly. See
`docs/ISO-MANIFESTS.md` for shared fields and handoff rules.

## Preconditions

Run from the repo root on the FreeBSD host. Use one command at a time.

```sh
git fetch origin
```

```sh
git status --short --branch
```

```sh
git rev-parse --short HEAD
```

```sh
ls -lh tmp/output
```

```sh
find tmp/output -maxdepth 1 -type f -name 'clawdie-*.img*' -ls
```

Confirm the image filename includes the current commit suffix. Do not publish an
old unsuffixed or wrong-commit image.

If `tmp/output` is root-owned from the build, use an elevated shell for publish
steps that write beside the artifact, or use the `sudo` variants shown below.

## 1. Select the image

Set `IMG` to the raw image produced by the current build. Example:

```sh
IMG="tmp/output/clawdie-quindecim-0.11.0.img"
```

```sh
test -f "$IMG"
```

```sh
XZ="${IMG}.xz"
```

```sh
SHA="${XZ}.sha256"
```

## 2. Compress if needed

If `${XZ}` already exists for the same raw image, inspect it before reusing it:

```sh
ls -lh "$IMG" "$XZ"
```

If `${XZ}` is missing or stale, create it:

```sh
xz -T0 -c "$IMG" > "$XZ"
```

Record the published file size:

```sh
stat -f '%z %N' "$XZ"
```

## 3. Generate checksum and manifest

```sh
sha256 "$XZ" > "$SHA"
```

```sh
cat "$SHA"
```

```sh
MANIFEST="$(scripts/write-artifact-manifest.sh "$XZ" --base-url https://osa.smilepowered.org/downloads/iso)"
```

```sh
cat "$MANIFEST"
```

If `tmp/output` artifacts are root-owned, run the manifest step with `sudo` and
preserve the base URL:

```sh
MANIFEST="$(sudo env BUILT_BY="Codex ISO Builder" scripts/write-artifact-manifest.sh "$XZ" --base-url https://osa.smilepowered.org/downloads/iso)"
```

## 4. Inspect current public links

```sh
ls -l /usr/local/www/osa/downloads/iso
```

Remove only the old public Clawdie image/checksum symlinks, not the new output
files under `tmp/output`:

```sh
sudo find /usr/local/www/osa/downloads/iso -maxdepth 1 -type l -name 'clawdie-*.img.xz' -delete
```

```sh
sudo find /usr/local/www/osa/downloads/iso -maxdepth 1 -type l -name 'clawdie-*.img.xz.sha256' -delete
```

```sh
sudo find /usr/local/www/osa/downloads/iso -maxdepth 1 -type l -name 'clawdie-*.manifest.json' -delete
```

## 5. Link the new artifacts

```sh
sudo ln -s "$(pwd)/$XZ" "/usr/local/www/osa/downloads/iso/$(basename "$XZ")"
```

```sh
sudo ln -s "$(pwd)/$SHA" "/usr/local/www/osa/downloads/iso/$(basename "$SHA")"
```

```sh
sudo ln -s "$(pwd)/$MANIFEST" "/usr/local/www/osa/downloads/iso/$(basename "$MANIFEST")"
```

```sh
sudo chgrp -h webmaster "/usr/local/www/osa/downloads/iso/$(basename "$XZ")"
```

```sh
sudo chgrp -h webmaster "/usr/local/www/osa/downloads/iso/$(basename "$SHA")"
```

```sh
sudo chgrp -h webmaster "/usr/local/www/osa/downloads/iso/$(basename "$MANIFEST")"
```

## 6. Update index.html

Set helper variables:

```sh
XZ_BASE="$(basename "$XZ")"
```

```sh
SHA_BASE="$(basename "$SHA")"
```

```sh
MANIFEST_BASE="$(basename "$MANIFEST")"
```

Write the simple public index:

```sh
sudo sh -c "cat > /usr/local/www/osa/downloads/iso/index.html" <<EOF
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Clawdie ISO Downloads</title>
</head>
<body>
  <h1>Clawdie ISO Downloads</h1>
  <ul>
    <li><a href="${XZ_BASE}">${XZ_BASE}</a></li>
    <li><a href="${SHA_BASE}">${SHA_BASE}</a></li>
    <li><a href="${MANIFEST_BASE}">${MANIFEST_BASE}</a></li>
  </ul>
</body>
</html>
EOF
```

```sh
sudo chown root:webmaster /usr/local/www/osa/downloads/iso/index.html
```

```sh
sudo chmod 0644 /usr/local/www/osa/downloads/iso/index.html
```

## 7. Verify local webroot

```sh
ls -l /usr/local/www/osa/downloads/iso
```

```sh
readlink "/usr/local/www/osa/downloads/iso/$(basename "$XZ")"
```

```sh
readlink "/usr/local/www/osa/downloads/iso/$(basename "$SHA")"
```

```sh
readlink "/usr/local/www/osa/downloads/iso/$(basename "$MANIFEST")"
```

```sh
cat /usr/local/www/osa/downloads/iso/index.html
```

## 8. Verify public URLs

```sh
fetch -qo - https://osa.smilepowered.org/downloads/iso/
```

```sh
fetch -qo - "https://osa.smilepowered.org/downloads/iso/$(basename "$SHA")"
```

```sh
fetch -qo - "https://osa.smilepowered.org/downloads/iso/$(basename "$MANIFEST")"
```

This downloads the full compressed image to `/dev/null`; run it so the direct
image URL is proven, but expect it to take time:

```sh
fetch -o /dev/null "https://osa.smilepowered.org/downloads/iso/$(basename "$XZ")"
```

## 9. Report back

Report these items to the operator:

- image URL
- checksum URL
- manifest URL
- index URL
- SHA256 hash
- published compressed size in bytes
- Hermes deploy block
- any root-owned output or permission hiccups

Example:

```text
Published:
- https://osa.smilepowered.org/downloads/iso/<image>.img.xz
- https://osa.smilepowered.org/downloads/iso/<image>.img.xz.sha256
- https://osa.smilepowered.org/downloads/iso/<image>.manifest.json
- https://osa.smilepowered.org/downloads/iso/

Checksum: <sha256>
Size: <bytes> bytes

HERMES_USB_DEPLOY_READY=1
IMAGE_URL=https://osa.smilepowered.org/downloads/iso/<image>.img.xz
SHA256_URL=https://osa.smilepowered.org/downloads/iso/<image>.img.xz.sha256
MANIFEST_URL=https://osa.smilepowered.org/downloads/iso/<image>.manifest.json
COMMIT=<short-commit>
SIZE_BYTES=<compressed-size-bytes>
SHA256=<sha256>
EXPECTED_USB_MODEL=<operator-supplied-model>
EXPECTED_USB_SIZE=<operator-supplied-size>
USB_ATTACHED_TO=linux-hermes | freebsd-host
```

## Safety notes

- Do not delete `tmp/output` artifacts during publish.
- Do not publish an image whose filename lacks the current commit suffix.
- Do not replace unrelated files in the webroot.
- Prefer symlinks into `tmp/output` for current internal testing; if this becomes
  a public release process, switch to copied immutable artifacts outside the
  build workspace.
