> ## Documentation Index
> Fetch the complete documentation index at: https://www.plungeai.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Distribution and updates

> oceancode ships as two self-contained binaries: the engine oceancode and the terminal UI ocean-pager it launches, installed side by side. This page covers installing it, keeping it current, verifying a download, and removing it. Every download is checksummed, and every install channel agrees on …


`oceancode` ships as two self-contained binaries: the engine `oceancode` and the terminal UI
`ocean-pager` it launches, installed side by side. This page covers installing it, keeping it
current, verifying a download, and removing it. Every download is checksummed, and every install
channel agrees on one set of release-asset names.

## Installing

| Channel | Command |
|---|---|
| macOS / Linux (script) | `curl -fsSL https://raw.githubusercontent.com/OWNER/ocean-coding-agent/main/packaging/install/install.sh \| sh` |
| Windows (PowerShell) | `irm https://raw.githubusercontent.com/OWNER/ocean-coding-agent/main/packaging/install/install.ps1 \| iex` |
| Homebrew (macOS / Linux) | `brew install OWNER/oceancode/oceancode` |
| Cargo (Rust-native, npm-free) | `cargo install --locked --path crates/ocean-cli` (from a clone today; `cargo install --locked oceancode` once published) |

The script installer downloads the release asset for your platform, verifies it (see
[Verifying a download](#verifying-a-download)), and installs `oceancode` and `ocean-pager` into
`${OC_INSTALL_DIR:-$HOME/.local/bin}` (Windows `%USERPROFILE%\.oceancode\bin`). If that directory
is not on your `PATH`, the installer prints the line to add. See
[02 · Configuration](/oceancode/configuration) for `OC_INSTALL_DIR` and the other install knobs.

`cargo install` is npm-free by design — the whole toolchain is Rust; no Node package is pulled at
build or install time. See `packaging/homebrew/cargo-install.md`.

## Keeping current — `oceancode update`

```bash
oceancode update              # update to the newest release for your channel
oceancode update --self-test  # prove the swap + rollback offline (no network)
```

`update` fetches the newest release for the configured channel, **never downgrades**, verifies the
release signatures, swaps `oceancode` and `ocean-pager` atomically, and **rolls both back** if either
new binary fails a health check — so a failed update leaves the working pair exactly as it was.
`--self-test` prints `UPDATE_SELF_TEST_OK binaries=2` as its last line.

Channels and opt-out:

| Setting | Where | Effect |
|---|---|---|
| `update.channel` | config (`oceancode.json`) | `stable` (default) or `beta` (sees pre-releases). |
| `OC_UPDATE_CHANNEL` | env | Overrides `update.channel` for one run. |
| `update.auto_check` | config | `true` (default) checks for a newer release on boot. |
| `OC_NO_UPDATE_CHECK` | env | Any value suppresses the boot-time check. |
| `update.endpoint` | config | Overrides the release-metadata source (default: GitHub Releases). |

**Telemetry-free first run.** The boot-time update check is *always* skipped on the very first run
(and whenever `update.auto_check` is `false` or `OC_NO_UPDATE_CHECK` is set): a fresh install never
phones home before you ask it to.

## Verifying a download

Every release ships a single `SHA256SUMS` manifest and a detached minisign signature
(`<asset>.minisig`) per asset. Verify a download before trusting it — the same check on macOS,
Linux and Windows, with no external tool:

```bash
oceancode verify-release oceancode-macos-aarch64.tar.gz \
  --sha256sums SHA256SUMS
```

It prints `VERIFY_RELEASE_OK file=<name>` on success and refuses (non-zero exit) on any mismatch.
`--pubkey <base64>` overrides the embedded release public key.

**Signing tiers.** Releases are signed with minisign on every platform. When an Apple Developer ID
(macOS) or an Authenticode certificate (Windows) is available, the release *also* carries OS-native
codesigning / notarization. When no such certificate is present, the release ships **unsigned at the
OS level but with `SHA256SUMS` + minisign** — the portable trust root above still applies, and the
installer stays fail-closed (it refuses to install an unverifiable artifact unless you pass
`--insecure-skip-verify` / `OCEANCODE_INSECURE_SKIP_VERIFY=1`).

> **Test key notice.** The public key embedded in `oceancode verify-release`
> (`verify_release::EMBEDDED_PUBKEY`) and in the installers is a **deterministic test key**. The
> release owner must replace it with the real minisign public key before shipping a signed release.

## Uninstalling

```bash
oceancode uninstall            # remove the binary only
oceancode uninstall --purge    # also remove ~/.config/oceancode and the data dir
oceancode uninstall --dry-run  # print the plan, remove nothing
```

`uninstall` removes only what the installer placed. `--purge` additionally removes the app's config
and data directories (the data dir holds `auth.json`, TUI state and the default global session
store) — never your per-project `.oceancode/oceancode.db`. It requires a typed `oceancode`
confirmation unless `--yes`, never follows a symlink out of its own tree, and prints
`UNINSTALL_OK removed=<n>`.

## Windows notes

On Windows the `bash` tool spawns the shell selected by the `shell.kind` config key (default
`auto` → PowerShell). Tool output is normalized for cross-OS stability: `\r\n` and stray `\r`
become `\n`, and backslash paths are shown POSIX-style (`C:/Users/...`) for display only. ConPTY is
the PTY backend, and the console has ANSI/VT processing enabled so escape sequences render.

---

## Release-asset naming contract

Every channel — the script installer, Homebrew, `oceancode update`, `oceancode verify-release`, the
download page and the release CI job — agrees on **one** naming scheme. This is the single source of
truth; a producer or consumer that disagrees is a bug to reconcile against it.

**Per target, the release publishes BOTH:**

- **`oceancode-<os>-<arch>.tar.gz`** — a gzipped tar containing exactly `oceancode` and
  `ocean-pager`. The **script installer** (macOS/Linux) and **Homebrew** download this and install
  both side by side.
- **`oceancode-<os>-<arch>`** — the **bare binary** (Windows: `oceancode-<os>-<arch>.exe`).
  `oceancode update` downloads this and stages it directly as `oceancode.new` for the atomic swap, so
  it must NOT be an archive. On Windows the PowerShell installer also consumes this bare `.exe`.
- **`ocean-pager-<os>-<arch>`** — the bare TUI binary; `oceancode update` swaps it together with
  `oceancode` (the engine runs inside the pager process, so the pair must match). If either fails
  its `--version` health check after the swap, both are rolled back to their `<name>.bak`. A release
  without this asset updates `oceancode` alone and warns that the TUI was not updated.

Plus, for **every** asset (the tarball and both bare binaries):

- **`<asset>.minisig`** — a detached minisign signature, and
- **one `SHA256SUMS`** — a single manifest hashing every asset (no per-target manifest).

**No version appears in any filename** — the version lives in the release tag path and the download
manifest's `version` field.

### rustc triple ↔ `<os>-<arch>` token

The `<os>-<arch>` token is `oceancode update`'s `platform_suffix()` (`std::env::consts::OS` +
`std::env::consts::ARCH`), matched as a **substring** of the asset name — so the Linux `-musl` suffix
is tolerated. The installer's `detect_asset` (`packaging/install/install.sh`) names match the tarball
column.

| rustc triple | `<os>-<arch>` token | tarball (installer / Homebrew) | bare binary (`oceancode update`) | bare TUI (`oceancode update`) |
|---|---|---|---|---|
| `aarch64-apple-darwin` | `macos-aarch64` | `oceancode-macos-aarch64.tar.gz` | `oceancode-macos-aarch64` | `ocean-pager-macos-aarch64` |
| `x86_64-apple-darwin` | `macos-x86_64` | `oceancode-macos-x86_64.tar.gz` | `oceancode-macos-x86_64` | `ocean-pager-macos-x86_64` |
| `x86_64-unknown-linux-musl` | `linux-x86_64` | `oceancode-linux-x86_64-musl.tar.gz` | `oceancode-linux-x86_64-musl` | `ocean-pager-linux-x86_64-musl` |
| `aarch64-unknown-linux-musl` | `linux-aarch64` | `oceancode-linux-aarch64-musl.tar.gz` | `oceancode-linux-aarch64-musl` | `ocean-pager-linux-aarch64-musl` |
| `x86_64-pc-windows-msvc` | `windows-x86_64` | `oceancode-windows-x86_64.tar.gz` | `oceancode-windows-x86_64.exe` | `ocean-pager-windows-x86_64.exe` |

Because the `.tar.gz` and the bare binaries carry the same `<os>-<arch>` token, the update path
must select the **bare** binaries specifically (skip `.tar.gz`) and tells them apart by the
`ocean-pager-` prefix; the installer/Homebrew select the tarball.

## Platform download-page contract

When `update.endpoint` is set, `oceancode update` fetches release metadata from the platform's
release endpoint (Track P / S11-T03; the canonical schema lives in
`docs/platform-download-contract.md`). The endpoint returns JSON of this shape — the platform and
the binary agree on the artifact list here:

```json
{
  "version": "0.8.8.01",
  "channel": "stable",
  "artifacts": [
    {
      "target": "aarch64-apple-darwin",
      "url": "https://…/oceancode-macos-aarch64",
      "sha256": "…",
      "minisig": "https://…/oceancode-macos-aarch64.minisig"
    }
  ]
}
```

`version` and `channel` are strings; `artifacts` is one object per shipped target. `url` is the
**bare binary** `oceancode update` downloads and stages as `oceancode.new` (not the `.tar.gz` — that
is the installer's), `sha256` matches its `SHA256SUMS` entry, and `minisig` is its detached
signature. This page documents the shape only; the endpoint itself is the platform's (Track P,
`docs/platform-download-contract.md`), not the binary's.

## Release checklist

An ordered, mostly-automated release. Agents never publish or tag — the owner does the final GitHub
Release and tap steps.

1. **Bump the version.** `bash scripts/release/bump-version.sh <X.Y.Z.B>` — moves the `## Unreleased`
   CHANGELOG section under the new dated heading and updates `VERSION`. The number is
   `MAJOR.MINOR.PATCH.BUILD`: the first three name the release (a human sets them with the explicit
   argument), the fourth is the build counter — every `scripts/release/build-release.sh` run adds one
   to it on its own (`0.8.8.01`, `0.8.8.02`, … `0.8.8.99`, `0.8.8.100`; two digits minimum, never
   capped), so a build number is never reused and self-update treats a newer build of the same
   release as an update. The check.sh lanes build with `NO_BUMP=1`. Re-baselined to `0.8.8.00` on
   2026-10-22 (the `2.6.NN` numbers before it carried the build counter in the patch field).
2. **CHANGELOG dated.** Confirm the moved section reads correctly under `## 0.8.8.01 — <date>`.
3. **User-guide tables current.** `node scripts/gates/check-user-guide.mjs` → `USER_GUIDE_OK … missing=0`
   (every `OC_*` var and subcommand has a row) and `node scripts/gates/check-changelog.mjs` →
   `CHANGELOG_OK`.
4. **Whole-tree green on three OSes.** `./check.sh` → `ALL CHECKS PASSED` on macOS, Linux and Windows in CI.
5. **Build the five targets.** `bash scripts/release/build-all.sh` (or the CI `release` job's matrix)
   → `BUILD_RELEASE_OK targets=5`. Per target publish **both** the bare `oceancode-<os>-<arch>`
   (Windows `.exe`) and the `oceancode-<os>-<arch>.tar.gz`, using the `<os>-<arch>` tokens in the
   mapping table above — no version in any filename.
6. **Per-artifact budgets.** `RELEASE=1 ./check.sh` (or the CI native legs) runs `size-gate.sh` per
   artifact (≤ 40 MiB → `SIZE_GATE_OK`) and `boot-bench.sh` (< 36 ms → `BOOT_BENCH_OK`).
7. **Sign.** `bash scripts/sign/sign-artifacts.sh` (minisign → `SIGN_OK artifacts=<n>`); where
   certificates exist, `scripts/sign/codesign-macos.sh` (Apple notarization) and
   `scripts/sign/authenticode-windows.ps1` (Windows Authenticode).
8. **Checksums.** `bash scripts/release/gen-sha256sums.sh dist` → `SHA256SUMS_OK count=<n>` over the
   packaged assets.
9. **Draft the GitHub Release** (owner): upload the assets, `SHA256SUMS` and each `.minisig`.
10. **Homebrew tap** (owner): mirror `packaging/homebrew/oceancode.rb` to the tap with the real
    `sha256`s / bottle digests.

### Owner-only steps (agents never do these)

- Replace `verify_release::EMBEDDED_PUBKEY` and the installers' embedded minisign pubkey with the
  **real** release key.
- Provision the CI secret `MINISIGN_SECRET_KEY` and install `minisign` on the release runners.
- Relocate `docs/plans/ci/oceancode.yml` → `.github/workflows/oceancode.yml`.
- `git tag` / publish the GitHub Release; push the Homebrew tap; `cargo publish`.

## Release-notes template

```md
# oceancode v<X.Y.Z>

## Highlights
- <the one or two changes users will notice first>

## Install
- macOS/Linux: `curl -fsSL <install.sh> | sh`
- Windows: `irm <install.ps1> | iex`
- Homebrew: `brew install OWNER/oceancode/oceancode`
- Cargo: `cargo install --locked oceancode`

## Verify
Download the asset for your platform and run:
`oceancode verify-release <asset> --sha256sums SHA256SUMS`

## Changed
- <user-visible changes from the CHANGELOG's dated section>

## Fixed
- <fixes from the CHANGELOG>

## Checksums
See `SHA256SUMS` and the per-asset `<asset>.minisig` attached to this release.
```

## See also

- [01 · Getting started](/oceancode) — the install one-liners and first run.
- [02 · Configuration](/oceancode/configuration) — `update.*`, `shell.kind`, `OC_UPDATE_CHANNEL`, `OC_NO_UPDATE_CHECK`, `OC_INSTALL_DIR`.
- [07 · Headless and server](/oceancode/headless-and-server) — `update` / `verify-release` / `uninstall` as management subcommands.
