Skip to content

Latest commit

 

History

History
228 lines (194 loc) · 11.6 KB

File metadata and controls

228 lines (194 loc) · 11.6 KB

Install, update, and uninstall the provider

Last updated: 2026-09-18 · commit 397b4d902

How to put the darkbloom CLI on an Apple Silicon Mac with scripts/install.sh, what the script verifies before it touches an existing install, how the binary is updated afterwards, and how to remove everything. For operators; at the end darkbloom doctor runs and reports the machine's state.

Prerequisites

  • An Apple Silicon Mac. The binary targets macOS 14 (provider-swift/Package.swift, .macOS(.v14)); the installer checks only uname = Darwin and uname -m = arm64 and prints the macOS version without gating on it. Sizing (RAM, disk, which models fit) is in hardware requirements.
  • Outbound HTTPS to the coordinator (https://api.darkbloom.dev).
  • No sudo. The script writes to ~/.darkbloom, appends one PATH line to ~/.zshrc (or ~/.bashrc), and tries — best effort, no prompt — to link /usr/local/bin/darkbloom.

Steps

1. Run the installer

[backend] enabled_models = [] idle_timeout_mins = 60 # free when idle; 0 = always ready (see darkbloom idle) max_model_slots = 3

[gemma_optimizations] prefill_layer18 = true weighted_r1 = true

[coordinator] url = "wss://api.darkbloom.dev/ws/provider" private_only = false


The coordinator serves `scripts/install.sh` at `/install.sh` with its own base
URL substituted for the `__DARKBLOOM_COORD_URL__` placeholder; the embedded copy
`coordinator/api/install.sh` is regenerated byte-for-byte by
`scripts/sync-install-embed.sh`. To run the script from a checkout, set the
placeholder yourself: `COORD_URL=https://api.darkbloom.dev bash scripts/install.sh`.

The script performs these actions in order (`scripts/install.sh`; failures exit
1 and are listed in [troubleshooting](./troubleshooting.md#installer-exits)):

1. **Preflight.** Aborts unless `uname` is `Darwin` and `uname -m` is `arm64`.
   Prints chip (`sysctl machdep.cpu.brand_string`), RAM (`hw.memsize`) and
   macOS version (`sw_vers`).
2. **Step 1/5 — release metadata.** `GET $COORD_URL/v1/releases/latest`, then
   extracts `url`, `bundle_hash`, `binary_hash`, `metallib_hash`, `version`,
   `backend` with `sed`. Missing `url`, `bundle_hash` or `version` aborts.
3. **Step 2/5 — download and verify.** Creates `~/.darkbloom` and
   `~/.darkbloom/bin`, downloads the tarball to `/tmp/darkbloom-bundle.tar.gz`
   and requires `shasum -a 256` to equal `bundle_hash` (mismatch deletes the
   file and aborts). `install_bundle_atomically` then:
   - extracts into `~/.darkbloom/.install-staging-<pid>-<random>`;
   - requires `bin/darkbloom`, `bin/darkbloom-enclave`, `bin/mlx.metallib`;
   - hashes `bin/darkbloom` against `binary_hash` and `bin/mlx.metallib`
     against `metallib_hash` (`verify_file_hash`; a hash the release record
     omits is skipped);
   - when the tarball contains `Darkbloom.app`: `verify_staged_app_payload`
     (both hashes are then mandatory and `Contents/MacOS/darkbloom` and
     `Contents/MacOS/mlx.metallib` are re-hashed) and `verify_staged_app`:
     `codesign --verify --deep --strict -R="$DARKBLOOM_DESIGNATED_REQUIREMENT"`
     where the requirement is
     `anchor apple generic and identifier "io.darkbloom.provider" and certificate leaf[subject.OU] = "SLDQ2GJ6TL"`;
     the fan-helper triple (`darkbloom-fan-helper-v1` string in the binary ⇔
     marker `Contents/Resources/darkbloom-runtime-capabilities/fan-helper-v1`
     = `1` ⇔ `Contents/Helpers/darkbloom-fan-helper` present, a regular file,
     mode `0755`, signed to
     `anchor apple generic and identifier "io.darkbloom.fan-helper" and certificate leaf[subject.OU] = "SLDQ2GJ6TL"`);
     the paged-kernel pair (`engine_v2_kv_backend` string in the binary ⇔
     marker `paged-kernel-v1` = `1`, plus exactly one non-empty
     `Contents/Resources/mlx-swift-lm_MLXLMCommon.bundle/pagedattention.metal`);
     and a runtime smoke test:
     `DARKBLOOM_NO_UPDATE_CHECK=1 DARKBLOOM_GEMMA4_PREFILL_CHUNK_EVAL=18 MLX_GEMMA4_FUSED_WEIGHTED_UNSORT=1 MLX_GATHER_QMM_EXPERT_SLICES=1 darkbloom runtime-smoke`
     (`provider-swift/Sources/darkbloom/RuntimeSmokeCommand.swift`,
     `RuntimeSmoke`);
   - `commit_staged_app` moves any existing `~/.darkbloom/Darkbloom.app` to
     `~/.darkbloom/.install-backup-<pid>-<random>`, moves the staged app in,
     writes the symlinks `~/.darkbloom/bin/darkbloom`, `darkbloom-enclave`,
     `mlx.metallib` → `../Darkbloom.app/Contents/MacOS/*` and the legacy alias
     `bin/eigeninference-enclave → darkbloom-enclave`, and `chmod +x`. Any
     failure moves the backup back;
   - a tarball without `Darkbloom.app` (legacy flat layout) gets
     `codesign --verify --strict -R=…` on `bin/darkbloom` and
     `commit_staged_flat_bundle` swaps `~/.darkbloom/bin` the same way;
   - the staging directory is removed; on any failure the script prints
     `Existing installation was left unchanged.` and exits 1.
4. **PATH.** `ln -sf ~/.darkbloom/bin/darkbloom /usr/local/bin/darkbloom`
   (errors ignored). The rc file is `~/.zshrc`, or `~/.bashrc` only when
   `~/.zshrc` does not exist. If the rc does not already mention
   `.darkbloom/bin`, lines referencing `.dginf/bin`, `.eigeninference/bin`,
   `alias eigeninf`, `alias dginf`, `# EigenInference` and `# Darkbloom` are
   deleted and `# Darkbloom` + `export PATH="$HOME/.darkbloom/bin:$PATH"` is
   appended; the rc is then sourced.
5. **Legacy install migration.** For each real directory `~/.dginf` and
   `~/.eigeninference`: `cp -n` of `enclave_key.data`, `wallet_key` and
   `auth_token` into `~/.darkbloom`, then the old directory is replaced by a
   symlink to `~/.darkbloom`. `provider.toml` is not migrated by the script;
   the CLI copies a config found at a legacy path to
   `~/.config/darkbloom/provider.toml` on its next run
   (`provider-swift/Sources/darkbloom/Darkbloom.swift`, `migrateConfigIfNeeded`).
6. **Step 3/5 — Secure Enclave identity.** Runs `darkbloom-enclave info`
   (`provider-swift/Sources/darkbloom-enclave-cli/EnclaveCLI.swift`), which
   creates the P-256 key if missing. Failure prints a warning; the install
   continues with reduced trust (see [attestation](./attestation.md)).
7. **Step 4/5 — verification setup.** `configure_device_verification` uses the
   local `sw_vers` major version. On macOS 27 or later it skips profile checks,
   download and System Settings, and directs the user to login/start/status for
   App Attest approval. Older macOS retains legacy enrollment and prints the
   upgrade option and upcoming MDM deactivation notice. If `profiles status
   -type enrollment` reports no management, the script posts `{}` to
   `$COORD_URL/v1/enroll`, saves the profile under
   `${TMPDIR:-/tmp}/Darkbloom-Enroll.XXXXXX/`, and opens System Settings for
   approval. Existing management is preserved without claiming it is Darkbloom
   verification. Unknown OS versions download no profile and direct users to
   `darkbloom enroll`. Setup choice grants no serving authorization; see the
   [authorization contract](../reference/provider-authorization.md).
8. **Step 5/5 — catalog.** `GET $COORD_URL/v1/models/catalog?type=text`;
   interactive runs print up to 20 entries. Nothing is downloaded.

### 2. Reload your shell

```bash
source ~/.zshrc   # or open a new terminal

3. Check the machine

darkbloom doctor

Continue with the quickstart to download a model, link the account and start serving.

Verify

darkbloom --version          # prints ProviderCore.version, e.g. 0.8.16
ls -l ~/.darkbloom/bin       # symlinks into ../Darkbloom.app/Contents/MacOS/
codesign --verify --deep --strict \
  -R='anchor apple generic and identifier "io.darkbloom.provider" and certificate leaf[subject.OU] = "SLDQ2GJ6TL"' \
  ~/.darkbloom/Darkbloom.app && echo signature OK

Update

Manual

darkbloom update --check-only     # report only
darkbloom update                  # download, verify, atomic replace, restart the service

darkbloom update (provider-swift/Sources/darkbloom/UpdateCommand.swift, Update) drives SelfUpdater (provider-swift/Sources/ProviderCore/Update/SelfUpdater.swift): it fetches GET {coordinator}/v1/releases/latest?platform=macos-arm64, verifies the SHA-256 of the bundle and, when published, of the binary and mlx.metallib, verifies the code signature (production always constructs the updater with verifyCodeSignatures: true), replaces the install, and — if the LaunchAgent is loaded — restarts it via ProcessLifecycle.restartAfterUpdate(). Flags: --check-only, --override-quarantine, --coordinator <url>, --config.

Automatic

provider.auto_update (default true, provider-swift/Sources/ProviderCore/Config/ProviderConfig.swift) is toggled with darkbloom autoupdate enable|disable|status (provider-swift/Sources/darkbloom/AutoUpdateCommand.swift). When enabled the daemon checks once at start (runStartupAutoUpdate, provider-swift/Sources/darkbloom/StartCommand+Modes.swift) and then on a loop (provider-swift/Sources/ProviderCore/ProviderLoop+AutoUpdate.swift):

Step Symbol
First in-daemon check after start autoUpdateInitialDelay
Check interval autoUpdateInterval
Random delay before installing up to provider.update_jitter_seconds (updateJitterSeconds)
Drain of in-flight requests before restart updateDrainTimeout
Skip every check (banner, start, loop, watchdog) DARKBLOOM_NO_UPDATE_CHECK set to any value

The values are in cli-reference.md (the jitter default in its provider.toml table).

A freshly installed version that crashes rollbackThreshold times before surviving defaultStabilizationSeconds is quarantined on this machine (provider-swift/Sources/ProviderCore/Update/UpdateRecoveryState.swift; values in runtime constants). Only that exact version is blocked; a newer release installs normally. darkbloom update --override-quarantine reinstalls it anyway, and darkbloom doctor reports the quarantine under up to date.

The unprivileged updater never touches the root fan helper; after an update run sudo darkbloom fan enable again if you use fan control.

Uninstall

sudo darkbloom fan uninstall    # only if fan control was enabled
darkbloom stop --uninstall      # stops the daemon, removes both LaunchAgent plists
darkbloom unenroll              # opens System Settings to remove the MDM profile; offers to delete config + tokens
rm -rf ~/.darkbloom ~/.config/darkbloom
sudo rm -f /usr/local/bin/darkbloom

darkbloom stop --uninstall (provider-swift/Sources/darkbloom/StopCommand.swift) disarms the watchdog first, deletes ~/Library/LaunchAgents/io.darkbloom.watchdog.plist and io.darkbloom.provider.plist, and disables both labels in launchd. darkbloom unenroll (provider-swift/Sources/darkbloom/UnenrollCommand.swift) opens System Settings → Device Management (macOS does not let a binary remove a profile) and, after confirmation or with --force, deletes ~/.config/darkbloom/, ~/.darkbloom/auth_token and the legacy key files. Remove the # Darkbloom PATH line from your rc file by hand. Model weights live in ~/.cache/huggingface/hub; delete them with darkbloom models remove <id> before removing the CLI.

Related