Install and update an additional Host
This operator procedure targets macOS Apple Silicon and an existing Hub. Virgo is in release preparation. Access to its canonical release repository is required; this is not an anonymous public installer.
Publication boundary: these commands require the accepted Host install/update CLI and canonical bootstrap to be published together. Older current.json metadata does not acquire new commands when documentation changes. The release owner must publish and verify that boundary before treating this guide as ready.
The result is one Host connected to your existing Hub, without local Hub databases or per-Seat setup files. Provider discovery, claim-first attachment and feature activation have their own availability checks.
Prepare the machine and runtime
Use the logged-in macOS account that will own the Host. Its launchd user domain supervises the process. Check uname -m reports arm64. The tested interpreter is Bun 1.3.14; install that exact version in a stable location using the official Bun installer:
VIRGO_BUN_HOME="$HOME/.local/share/virgo/providers/bun/1.3.14"
curl -fsSL https://bun.com/install | BUN_INSTALL="$VIRGO_BUN_HOME" bash -s "bun-v1.3.14"
export PATH="$VIRGO_BUN_HOME/bin:$PATH"
bun --version
Require 1.3.14. Keep this executable at the same location: the supervisor records its actual interpreter. Docker and Node are not needed for this additional Host. Install the GitHub CLI and authenticate an account with read access to virgo-codes/virgo-release. GitHub access and Hub enrollment are separate authorities.
Obtain the canonical bootstrap
Clone the release repository using its authenticated GitHub route:
VIRGO_BOOTSTRAP="$HOME/virgo-release-bootstrap"
gh repo clone virgo-codes/virgo-release "$VIRGO_BOOTSTRAP"
git -C "$VIRGO_BOOTSTRAP" checkout main
current.json records the source repository/commit, exact release and CLI checksum. The bootstrap downloads that CLI from release-<release>, verifies it, and invokes it through Bun. The CLI verifies the manifest and native archive. No local product source checkout is needed and no feature branch is substituted for a release.
Supply enrollment authority
The Hub owner supplies an enrollment credential through the existing private operator route, in a regular file owned by your account with mode 0600. This path uses the Hub's existing installationAdmin authority; it is not a single-use enrollment grant. Keep the file outside the Host instance directory and pass only its path. Never paste its value into a command or receipt.
The installer creates the Host key and local management credential. These are separate from the Hub enrollment credential and GitHub artifact access.
Install
Set your existing Hub URL, Account, machine name and credential-file path. Use an available fixed local port. This example's --network local describes the Host's loopback listener; its Hub connection is outbound HTTPS.
umask 077
VIRGO_ROOT="$HOME/virgo"
VIRGO_MACHINE="my-new-host"
VIRGO_HUB_URL="https://your-existing-hub.example/"
VIRGO_ACCOUNT="your-account"
VIRGO_ENROLLMENT_FILE="$HOME/.config/virgo/enrollment/hub-admin.token"
VIRGO_RECEIPT="$HOME/virgo-host-install.json"
bash "$VIRGO_BOOTSTRAP/install.sh" install --mode host \
--root "$VIRGO_ROOT" --machine "$VIRGO_MACHINE" --instance host \
--hub-url "$VIRGO_HUB_URL" --account "$VIRGO_ACCOUNT" \
--network local --advertised-url http://127.0.0.1:58612/ --api-port 58612 \
--enrollment-credential-file "$VIRGO_ENROLLMENT_FILE" > "$VIRGO_RECEIPT"
Require exit zero and ok: true, state.outcome.state: "active" in the receipt. Preserve its exact installationDirectory and releaseDirectory; do not construct an encoded instance path. An identical retry preserves identity and configuration. Use the update command for a new release, rather than reinstalling the Host.
Verify the connection
Use the installed CLI path from the successful receipt:
VIRGO_INSTANCE=$(bun -e 'const r=await Bun.file(process.argv[1]).json(); if(!r.ok||r.state?.outcome?.state!=="active")process.exit(1); console.log(r.state.installationDirectory)' "$VIRGO_RECEIPT")
VIRGO_INSTALLED_CLI=$(bun -e 'const r=await Bun.file(process.argv[1]).json(); if(!r.ok||r.state?.outcome?.state!=="active")process.exit(1); console.log(r.state.releaseDirectory+"/bin/virgo")' "$VIRGO_RECEIPT")
bun "$VIRGO_INSTALLED_CLI" --directory "$VIRGO_INSTANCE" host status
The returned value must show the expected process.machine and process.release, a PID, process.protocol: "responding", hub.state: "connected", and both hub.associated and hub.fresh true. Preserve hub.hostId for later comparison. This read requires no Seat or provider principal. Historical association alone is not proof of a current Hub connection; a local process can remain responsive while its Hub state is reconnecting.
Update from the same canonical source
Refresh the clean bootstrap checkout, then update the existing target:
git -C "$VIRGO_BOOTSTRAP" pull --ff-only
VIRGO_UPDATE_RECEIPT="$HOME/virgo-host-update.json"
bash "$VIRGO_BOOTSTRAP/install.sh" upgrade --mode host \
--root "$VIRGO_ROOT" --machine "$VIRGO_MACHINE" --instance host \
> "$VIRGO_UPDATE_RECEIPT"
The wrapper selects the newly published release from current.json; do not add a release, bundle or distribution override. Upgrade preserves the existing Hub, Account, key, association and unrelated provider configuration. Save its planId and returned state. Repeating the same release verifies the artifact and preserves the original rollback plan instead of replacing it with an empty upgrade.
The initial install receipt remains historical. After an update, resolve the installed CLI from the successful update receipt:
VIRGO_INSTALLED_CLI=$(bun -e 'const r=await Bun.file(process.argv[1]).json(); if(!r.ok||r.state?.state!=="active")process.exit(1); console.log(r.releaseDirectory+"/bin/virgo")' "$VIRGO_UPDATE_RECEIPT")
bun "$VIRGO_INSTALLED_CLI" --directory "$VIRGO_INSTANCE" host status
Require the new release, fresh Hub connection and unchanged hub.hostId. For a Host already running providers, the installation owner must also verify preserved provider sessions, pending effects and actual native delivery. A Host status result alone does not establish those provider outcomes.
Roll back the exact update
Use the plan from that update, not a guessed older release:
VIRGO_APPLIED_PLAN=$(bun -e 'const r=await Bun.file(process.argv[1]).json(); if(typeof r.planId!=="string")process.exit(1); console.log(r.planId)' "$VIRGO_UPDATE_RECEIPT")
VIRGO_UPDATE_CLI="$VIRGO_INSTALLED_CLI"
VIRGO_ROLLBACK_RECEIPT="$HOME/virgo-host-rollback.json"
bash "$VIRGO_BOOTSTRAP/install.sh" rollback --mode host \
--root "$VIRGO_ROOT" --machine "$VIRGO_MACHINE" --instance host \
--plan-id "$VIRGO_APPLIED_PLAN" > "$VIRGO_ROLLBACK_RECEIPT"
Rollback restores the prior verified artifact/configuration and leaves the Host stopped. Read the restored release from that receipt and deliberately reactivate it using the newer verified CLI, which remains installed:
VIRGO_PRIOR_RELEASE=$(bun -e 'const r=await Bun.file(process.argv[1]).json(); const v=r.state?.actual?.installedRelease; if(!r.ok||r.activation!=="stopped"||typeof v!=="string")process.exit(1); console.log(v)' "$VIRGO_ROLLBACK_RECEIPT")
bun "$VIRGO_UPDATE_CLI" upgrade --mode host \
--root "$VIRGO_ROOT" --machine "$VIRGO_MACHINE" --instance host \
--release "$VIRGO_PRIOR_RELEASE" --github-repository virgo-codes/virgo-release
bun "$VIRGO_UPDATE_CLI" --directory "$VIRGO_INSTANCE" host status
Require the restored release and a fresh connection with the same Host identity. The canonical wrapper selects current.json; its ordinary upgrade would select the newer release again. This explicit recovery command selects only the release that the exact rollback plan restored.
A failed successor activation can also be rolled back by its returned plan. For unresolved state, retain the receipt and keys; do not delete the association or invent a new machine name. If only the Hub is unavailable, restore its route and read status again—the Host reconnects with the existing identity.
Continue with bottom-up verification for the installed provider and feature capabilities. Controlled installation evidence and acceptance on your actual machine remain separate.