Docs/Operations/Distribution and upgrade

Distribution and upgrade

How the Fermix macOS app and standalone binaries are distributed, updated, and migrated between installation types.

Fermix ships as a macOS application with a bundled engine and as standalone binaries built with Burrito. Neither requires Elixir or Erlang on the target machine. The update method depends on which one you installed.

macOS application

The macOS app is distributed as a signed, notarized DMG and the tezra-io/tap/fermix cask. It owns its background service and updates by replacing the whole application. Use brew upgrade --cask tezra-io/tap/fermix for a cask install, or replace the app with the newer DMG download. Reopen it and apply any requested restart.

The bundled fermix upgrade opens update guidance; it does not swap an engine inside the signed bundle. Automatic update checks are not available. Doctor’s standalone upgrade, binary-integrity, and service-unit checks report not applicable for an app-managed engine.

To move an existing Homebrew formula install, use fermix migrate-to-app before installing the app. Running it without flags prints a plan; --yes retires the old user service, replaces the formula with the cask, and hands the preserved Fermix home to the app.

Standalone binary targets

Burrito produces one artifact per platform. The four supported targets are:

Target Binary name
macOS (Apple Silicon) fermix_macos_aarch64
macOS (Intel) fermix_macos_x86_64
Linux (ARM64) fermix_linux_aarch64
Linux (x86-64) fermix_linux_x86_64

Building from source additionally requires Zig, Burrito’s packaging dependency. See installation for the toolchain versions and the full build-from-source steps.

Homebrew formula

For a standalone daemon on macOS or Linux, use the Homebrew formula:

brew install tezra-io/tap/fermix

After brew upgrade fermix, run fermix restart. The upgrade swaps the binary on disk, but the daemon (the background Fermix process) keeps running the old version until it is restarted. While the running daemon’s version differs from the installed binary, fermix status appends a warning and fermix doctor’s daemon-socket check degrades to a warning, each naming both versions and the fermix restart fix.

When the old daemon predates the management protocol, fermix status cannot read it and exits 1 with the restart instruction. Restarting onto the new engine restores status reporting.

That restart also keeps computer use working across the upgrade. A new release can pin a newer native helper; a daemon that boots with computer use enabled but without the helper matching its build downloads it automatically before the readiness checks run. The fetch is bounded at about 30 seconds and fails soft: a slow or failed download is logged and leaves computer use off until the next restart or the setup card — it never blocks or crashes boot. When the helper is already installed, or the feature is disabled, boot touches no network.

If the OS service unit (the file that tells your operating system how to run Fermix in the background) drifted across the upgrade — an updated PATH or template — re-run fermix setup instead. It rewrites and reloads the unit, which a plain restart never does, so the daemon picks up the change without a manual fermix service install.

fermix upgrade

fermix upgrade is the self-update command for installs not managed by a package manager. Each release also carries an updated signed plugin catalog inside the binary, so newly published and updated plugins become installable after upgrading. Browse and install them from the Plugins page of fermix setup. (On the command line, fermix plugins catalog lists only the plugins already bundled or installed — not the full set of plugins a release makes available; the setup Plugins page renders the complete catalog.)

Package-manager detection

Fermix detects whether the running binary is owned by a package manager — a Homebrew Cellar/prefix path, or a path tracked by dpkg. If it is, fermix upgrade refuses to self-modify and prints the correct command to use instead on standard error, then exits non-zero (exit code 2):

fermix upgrade: managed by homebrew; run: brew upgrade fermix, then `fermix restart` — the daemon keeps running the old version until restarted

For dpkg-managed installs the equivalent guidance is printed:

fermix upgrade: managed by dpkg; run: sudo apt update && sudo apt upgrade fermix, then `fermix restart` — the daemon keeps running the old version until restarted

Upgrade flow for unmanaged installs

For binaries not under a package manager, fermix upgrade runs this sequence:

  1. Fetch releases.json over HTTPS from the GitHub release.
  2. Compare manifest.latest to the running version.
  3. Select the platform-specific artifact URL, SHA-256, and signature URL.
  4. Download the artifact, signature, and certificate.
  5. Stream-SHA verify the downloaded artifact against the manifest SHA-256 (confirm the download’s fingerprint matches the expected one, so it was not corrupted or tampered with).
  6. Run cosign verify-blob (cosign checks the release’s cryptographic signature) with the certificate identity bound to the exact manifest version. The identity regex enforces refs/tags/v<exact-version> to prevent substitution attacks (swapping in a different signed file).
  7. Snapshot the current binary to ~/.fermix/.previous (keep a copy of the old version in case rollback is needed).
  8. Atomic rename to install the new binary (swap in the new file in one step, so there is never a half-installed state).
  9. Restart the OS service.
  10. Poll the daemon’s status over its control socket for up to 10 seconds (checking every 500 ms) until it answers healthy and reports the new version — a semver comparison against manifest.latest, so a stale daemon that survived the restart fails the check rather than passing as a false green.
  11. If the health check fails, roll back from ~/.fermix/.previous, restart the service so the restored binary is the one running, and write the failure to the audit record.

Pass --check to query the manifest and report whether an update is available without downloading anything.

cosign requirement

Fermix verifies release artifacts with cosign. cosign must be on PATH before running fermix upgrade or activating plugins. Install it with:

brew install cosign

The OS service unit pins a PATH so the supervised daemon resolves cosign the same way an interactive shell does. That pinned PATH also lets the daemon find Homebrew-installed node and python, the runtimes used by MCP plugins. A stripped or bare unit PATH that omits the Homebrew prefix surfaces as a misleading signature invalid failure when installing a plugin: the daemon cannot find cosign, so verification never actually runs. Re-running fermix setup rewrites the unit with the correct PATH and fixes it.

Rollback

The previous binary is preserved at ~/.fermix/.previous before each swap. If the health check after restart does not pass within the timeout, the swapper restores the previous binary from ~/.fermix/.previous and restarts the service, so the restored binary is the one actually running — restoring the file alone would leave the wrong-version daemon still executing. The upgrade failure is written to the audit log.

Audit log

Every upgrade attempt appends a structured record to ~/.fermix/upgrades.jsonl. Each record includes status, old and new versions, sha256 of the artifact, and the timestamp.

{"status":"ok","from":"<old>","to":"<new>","sha256":"a1b2c3...","timestamp":"2026-01-01T00:00:00Z"}
{"status":"error","from":"<old>","to":"<new>","sha256":"d4e5f6...","timestamp":"2026-01-02T00:00:00Z"}

Service unit reconciliation

After a standalone upgrade (self-upgrade or package-manager), re-running fermix setup is safe and idempotent (running it again does no harm and changes nothing if everything is already in sync). It detects whether the installed service unit differs from what the current binary would write and reconciles it if needed. This keeps the daemon in sync when the unit template changes between releases without requiring a manual fermix service install.

See setup for setup flags and auth and secrets for keychain and credential management across upgrades.

Next steps