--- name: darkbloom-fleet-ops description: Use when running or re-modeling Darkbloom provider Macs. Covers update recovery over SSH, stale PID fixes, revenue-driven model selection, safe model switches, and a controller-agent pattern. version: 1.0.0 author: Pixel Rainbow (shagghiesuperstar) license: MIT metadata: hermes: tags: [darkbloom, provider-node, launchd, model-selection, fleet-ops] category: local-inference related_skills: [darkbloom-provider, multi-mac-fleet-ops] --- # Darkbloom Fleet Operations ## Overview Darkbloom pays provider nodes for serving inference from a consumer account. Running several Macs as providers creates three recurring problems: a daemon that cannot be restarted from a remote shell, an earnings record that a poller can silently lose, and model slots that keep earning nothing after the plan was set. This skill covers the recovery steps, the revenue loop that drives model choice, and a controller-agent pattern that watches the other nodes. ## When to Use - A provider daemon stays down after an update that ran over SSH. - A node refuses to start with a PID-file error after a reboot. - You are choosing or re-checking which models each node serves. - You are setting up one always-on agent to monitor and update the provider nodes. ## Features - Restart recovery for a provider daemon whose launchd agent failed to bootstrap in an SSH session. - Stale PID file cleanup and launchd re-registration through the provider CLI. - Earnings ledger collection from the account API, deduplicated by job id, with gap reporting. - Per-model ranking by revenue per active provider-day, plus a dead-weight alert for secondary models. - A model-swap sequence that drains jobs instead of cancelling them. - Controller routines: a status pulse, a daily digest, a one-node-at-a-time update window, and a balance check. ## Benefits - A node that fails to restart after an update returns in minutes without a physical visit. - Model decisions rest on recorded revenue, not on last month's plan. - Gaps in the earnings record show up in the digest instead of making the numbers quietly wrong. - Updates never take the whole fleet offline at once. ## Procedure 1. Read each node's state and version. `auto_update = true` in the provider config is an option the operator can choose, not a default. A scheduled check reports the version, and an update waits for the operator's go-ahead: ```zsh darkbloom status ``` Expect `Daemon: running`, and an enabled-model filter that matches the plan. 2. After the operator's go-ahead for each node, update one node at a time, with the wait for success before the next node: ```zsh darkbloom update --timeout 600 ``` 3. If the update leaves the daemon down with `launchctl bootstrap failed: 5: Input/output error`, the SSH session is outside the user's GUI launchd domain. Bootstrap the provider agent from that domain, then confirm: ```zsh launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ darkbloom status ``` 4. If startup fails with "a live process owns the provider PID file", confirm the recorded PID is dead with `kill -0 `. Back up the PID file, then start with the intended model. The start command clears the stale file and re-registers the agent: ```zsh cp .bak darkbloom start --model ``` 5. If launchd refuses to load the agent because its label is disabled, check who disabled it before enabling it: ```zsh launchctl print-disabled gui/$(id -u) launchctl enable gui/$(id -u)/