AkurAI Build
Menu

Public repository / c78c5f453208c5008730fff38de1f8fa1ec46219

AkurAI-Framework / AGENTS_DEPLOY.md

Latest change 4ed55d17e0979479dc70291811217113b6062fa0 - docs: split AGENTS.md into domain-indexed subfiles + add breaking-changes guide by Ólafur Búi Ólafsson

# AGENTS_DEPLOY.md — release & deploy

> How a release is cut and shipped, how versions stay in lockstep, and how end
> users install + self-update. The release engine is `./deploy.sh`; the ops layer
> is the reusable `akurai-ec2` CLI.

## `./deploy.sh` — the release engine

```
./deploy.sh [patch|minor|major]   release (default: patch)
./deploy.sh ec2                    publish the live site only, no version bump
```

A full release runs these stages, in order, and **dies on the first failure** so a
half-release is never tagged or pushed:

1. **Quality gate** (the green gate — see [`AGENTS_TESTING.md`](./AGENTS_TESTING.md)):
   `cargo fmt --all --check` → `cargo clippy --all-targets --all-features -D warnings`
   → `cargo test --all`. Then, if present, Playwright e2e (`tests/e2e/`) and the
   performance-budget bench (`bench/`). Missing optional gates skip, not fail.
2. **Version bump (lockstep)** — read `VERSION`, bump patch/minor/major, write it
   back, and `sed` the same number into `Cargo.toml`'s `[workspace.package]
   version`. Every crate inherits it via `version.workspace = true`, so one bump
   moves the whole workspace. The site's displayed version (`site/backend/page.json`)
   is synced too.
3. **Cut both changelogs** — stamp the "Unreleased" section of **both**
   `CHANGELOG.md` (developer-facing, `## [Unreleased]` → `## [X.Y.Z] - date`) and
   `site/content/changelog.md` (visitor-facing, `## Unreleased` → `## X.Y.Z - date`)
   into a dated version section, leaving a fresh empty Unreleased on top. See the
   changelog policy in [`AGENTS_DOCS.md`](./AGENTS_DOCS.md).
4. **Commit, tag, push** — `release: vX.Y.Z` commit + annotated `vX.Y.Z` tag,
   pushed to `origin` (creating the GitHub repo `olibuijr/AkurAI-Framework` on
   first run if needed).
5. **Publish live** (`ec2_publish`) — so `/changelog` reflects the version just
   shipped.

### The `ec2` publish-only mode

`./deploy.sh ec2` runs **only** `ec2_publish` — no gate, no bump, no tag. Use it
to re-publish the live site (e.g. after editing docs/content) without cutting a
release. `ec2_publish` is idempotent and shared by both `ec2` mode and the tail
of every release.

`ec2_publish` builds a **static musl binary**
(`cargo build --release --target x86_64-unknown-linux-musl -p akurai`) and ships
the framework's own `site/` via the `akurai-ec2` ops CLI:
`deploy-binary` (systemd unit on port 8094) → `nginx-proxy` → `tls`. A missing
`akurai-ec2` is a **warning, not a failure** — a release that's already tagged
and pushed must not be undone by an absent ops CLI; run `./deploy.sh ec2` later.

## `akurai-ec2` ops CLI + EC2 topology

The live site runs on the AkurAI AWS EC2 box behind **nginx + systemd + TLS**:

| Setting | Value |
|---------|-------|
| Domain | `akurai-framework.olibuijr.com` |
| Internal port | `8094` |
| systemd unit name | `akurai-framework` |
| Binary | static musl `target/x86_64-unknown-linux-musl/release/akurai` |
| Served content | the framework's own `site/` (landing + docs + changelog + components) |

`akurai-ec2` (the reusable AWS ops CLI; see the `_AWSEC2` skill) is the only
interface used here — `deploy-binary <name> <bin> <port> <static-dir>`,
`nginx-proxy <domain> <port>`, `tls <domain>`. TLS requests skip gracefully if
DNS hasn't propagated yet. DNS for `olibuijr.com` is managed at 1984.is.

## Lockstep workspace versioning

`VERSION`, `Cargo.toml` `[workspace.package] version`, and `site/backend/page.json`
all carry the same number, and `deploy.sh` is the **only** thing that bumps them —
in lockstep, in one commit. Don't hand-edit versions. Crates never set their own
`version`; they inherit `version.workspace = true`.

## `install.sh` + `akurai update` — end-user install & self-update

Two entry points share one asset-naming convention so they always resolve the
same artifact:

- **`install.sh`** (`site/frontend/install.sh`, served at
  `https://akurai-framework.olibuijr.com/install.sh`) — POSIX `sh`, rustup/claude
  style: `curl -fsSL …/install.sh | sh`. Detects OS + arch, downloads the
  matching binary from the **latest GitHub release**, installs to
  `~/.local/bin` (override `AKURAI_INSTALL_DIR`).
- **`akurai update`** (`crates/cli/src/cmd_update.rs`; aliases `upgrade`,
  `self-update`; `--check` reports without installing) — the CLI self-updater,
  resolving the same asset via `asset_name()`.

**Shared asset naming:** `akurai-<os>-<arch>` with `<os>` ∈ {`linux`, `macos`}
and `<arch>` ∈ {`x86_64`, `aarch64`}. `install.sh`'s `detect_asset()` and the
CLI's `asset_name()` MUST stay in lockstep — change one, change both.

**Prerequisite (honest gate):** both paths require a **public repo + a published
GitHub release** whose assets follow that naming. The repo is currently private,
so the public installer 404s **by design** and fails loudly — it never fakes
success. Activating it needs (1) making `olibuijr/AkurAI-Framework` public and
(2) cutting a release with correctly-named assets.