Shared memory for your AI coding agents — one command, all local.
This page exists so you can read the installer before you run it. Nothing here pipes anything automatically — copy a line when you're ready.
macOS & Linux:
Windows (PowerShell):
Prefer to check the bytes first? Download the script and its checksum, verify, then run:
On macOS without sha256sum, use shasum -a 256 -c SHA256SUMS.
These are the SHA-256 of the exact files this domain serves. They change only when a new release is deployed.
Raw files: /install.sh · /install.ps1 · /SHA256SUMS · source on GitHub
@legioncodeinc/honeycomb globally.The full scripts, inline. This is byte-for-byte what the checksums above cover.
sh)#!/bin/sh
# Honeycomb one-command bootstrap installer (POSIX) — PRD-050a.
#
# Usage (the single line a brand-new user pastes):
# curl -fsSL https://get.theapiary.sh | sh
#
# Contract (PRD-050a a-AC-1..6): leave the user on a running dashboard, OR tell them in ONE plain
# sentence why not. It assumes the operator knows nothing — no Node, no npm, no idea what a daemon
# is. It is deliberately THIN and IDEMPOTENT: it detects what is already present, installs only what
# is missing, and re-running it is safe.
#
# This script owns ONLY the host-bootstrap half: detect/install Node+npm (via fnm + a pinned LTS),
# then `npm i -g @legioncodeinc/honeycomb`. The moment a `honeycomb` bin exists it HANDS OFF to the
# `honeycomb install` CLI verb for the daemon-ensure + health-gate + dashboard-open — so that logic
# lives ONCE in TypeScript (src/commands/install.ts), not duplicated across two shell dialects.
#
# POSIX sh ONLY (no bashisms): this runs under `sh`, which may be dash/ash, not bash.
# `set -e` would abort on the FIRST non-zero command, surfacing a raw error. We instead handle every
# failure explicitly and print a plain-language line (parent AC-7) — so `set -e` is intentionally OFF.
set -u
# ─────────────────────────────────────────────────────────────────────────────
# THE ONE PLACE TO BUMP NODE. The single pinned Node LTS the installer provisions
# via fnm. To upgrade the provisioned Node for every new user, change THIS line
# only. (Existing users with a working Node are left untouched — see step 1.)
# ─────────────────────────────────────────────────────────────────────────────
HONEYCOMB_NODE_VERSION="22"
# The published npm package the global install pulls (PRD-048 publishes it; this consumes it).
HONEYCOMB_NPM_PACKAGE="@legioncodeinc/honeycomb@latest"
# Distribution base URL: the vanity domain that serves this installer surface (PRD-050a follow-up,
# now RESOLVED). get.theapiary.sh is a Cloudflare Pages site (site/install/) that content-negotiates:
# a shell client piping `/` gets this script as text/plain; a browser gets an "inspect before piping"
# page with the PUBLISHED SHA-256 checksums. `${BASE}/install.sh` and `${BASE}/install.ps1` always
# resolve to the raw, checksummed scripts. To verify before running: see https://get.theapiary.sh
HONEYCOMB_INSTALL_BASE_URL="https://get.theapiary.sh"
# ── Friendly progress log: step lines to stdout, the single failure summary to stderr. ──
step() { printf '→ %s\n' "$1"; }
ok() { printf '✓ %s\n' "$1"; }
fail() { printf 'Honeycomb install could not continue: %s\n' "$1" >&2; }
# `command -v` is the POSIX way to test for a binary (NOT `which`, which is not guaranteed present).
have() { command -v "$1" >/dev/null 2>&1; }
# ─────────────────────────────────────────────────────────────────────────────
# Step 1 — Node + npm. If both are present, use them. Else install fnm (NO elevation)
# + the pinned Node LTS. fnm installs entirely under $HOME, so it never needs
# sudo; that is exactly why it is the primary path over the official installer.
# ─────────────────────────────────────────────────────────────────────────────
ensure_node() {
if have node && have npm; then
ok "Node $(node --version) and npm $(npm --version) found."
return 0
fi
step "Node/npm not found — installing a private copy via fnm (no admin rights needed)…"
# fnm install is a curl|sh that writes ONLY under ~/.local/share/fnm + ~/.fnm — no elevation.
if ! have fnm; then
if ! have curl; then
# We cannot fetch fnm without curl, and installing curl itself needs the OS package manager
# (which needs elevation). Print the EXACT copy-paste and exit cleanly (a-AC-3).
elevation_required_node
return 1
fi
if ! curl -fsSL https://fnm.vercel.app/install | sh >/dev/null 2>&1; then
# fnm's own installer failed (e.g. a locked-down $HOME it cannot write). Fall back to the
# documented manual command + clean non-zero exit (a-AC-3) — never a raw error dump.
elevation_required_node
return 1
fi
fi
# Load fnm into THIS shell so `fnm`/`node`/`npm` resolve in-process (the install does not refresh
# the current shell's env). fnm lives at ~/.local/share/fnm or ~/.fnm depending on the platform.
FNM_DIR="${HOME}/.local/share/fnm"
[ -d "$FNM_DIR" ] || FNM_DIR="${HOME}/.fnm"
if [ -d "$FNM_DIR" ]; then
PATH="${FNM_DIR}:${PATH}"
export PATH
fi
if have fnm; then
# `fnm env` exports the shims; evaluate them so node/npm are on PATH for the rest of this run.
eval "$(fnm env 2>/dev/null)" || true
if ! fnm install "$HONEYCOMB_NODE_VERSION" >/dev/null 2>&1; then
elevation_required_node
return 1
fi
fnm use "$HONEYCOMB_NODE_VERSION" >/dev/null 2>&1 || true
eval "$(fnm env --use-on-cd 2>/dev/null)" || true
fi
if have node && have npm; then
ok "Installed Node $(node --version) via fnm."
return 0
fi
# fnm landed but node/npm still are not resolvable — surface the manual path, clean exit (a-AC-3).
elevation_required_node
return 1
}
# a-AC-3 — print the EXACT copy-paste install command + a one-line WHY, then signal a clean
# non-zero exit. NEVER a raw error dump. The caller exits with this function's surfaced intent.
elevation_required_node() {
fail "Honeycomb needs Node ${HONEYCOMB_NODE_VERSION} and could not install it automatically (your machine blocked the no-admin install)."
printf '\nInstall Node %s yourself with ONE of these, then re-run this installer:\n\n' "$HONEYCOMB_NODE_VERSION"
printf ' # macOS (Homebrew):\n'
printf ' brew install node@%s\n\n' "$HONEYCOMB_NODE_VERSION"
printf ' # Debian/Ubuntu:\n'
printf ' curl -fsSL https://deb.nodesource.com/setup_%s.x | sudo -E bash - && sudo apt-get install -y nodejs\n\n' "$HONEYCOMB_NODE_VERSION"
printf ' # Then re-run:\n'
printf ' curl -fsSL %s/install.sh | sh\n\n' "$HONEYCOMB_INSTALL_BASE_URL"
}
# ─────────────────────────────────────────────────────────────────────────────
# Step 2 — install @legioncodeinc/honeycomb globally. The embedding runtime
# (@huggingface/transformers) is an OPTIONAL dependency of the package and
# is pulled by npm during this install; its MODEL WEIGHTS are NOT fetched
# here (that is the embed daemon's lazy warmup — 050b), so this stays fast.
# ─────────────────────────────────────────────────────────────────────────────
install_honeycomb() {
# Idempotent: a re-run on a machine that already has `honeycomb` is a NO-OP — no npm mutation, no
# network. This keeps the documented "safe to re-run" contract and lets a rerun succeed OFFLINE. Only
# an absent install triggers the global npm install. (`resolve_honeycomb_bin` is defined below; POSIX sh
# resolves functions at call time, so the forward reference is fine — both exist before `main` runs.)
if existing_bin="$(resolve_honeycomb_bin 2>/dev/null)"; then
ok "${HONEYCOMB_NPM_PACKAGE} already installed (${existing_bin})."
return 0
fi
step "installing ${HONEYCOMB_NPM_PACKAGE} globally…"
if ! npm install -g "$HONEYCOMB_NPM_PACKAGE" >/dev/null 2>&1; then
fail "the global install of ${HONEYCOMB_NPM_PACKAGE} failed."
printf '\nTry it directly to see the npm error, then re-run this installer:\n\n npm install -g %s\n\n' "$HONEYCOMB_NPM_PACKAGE"
return 1
fi
ok "installed ${HONEYCOMB_NPM_PACKAGE}."
return 0
}
# Resolve the ABSOLUTE path to the freshly-installed `honeycomb` bin. `npm i -g` does NOT refresh the
# CURRENT shell's PATH, so calling `honeycomb` by bare name in the same run can fail "command not
# found" (PRD-050a impl-note). Resolve `<npm prefix -g>/bin/honeycomb` and invoke THAT.
resolve_honeycomb_bin() {
if have honeycomb; then
command -v honeycomb
return 0
fi
prefix="$(npm prefix -g 2>/dev/null)"
if [ -n "$prefix" ] && [ -x "${prefix}/bin/honeycomb" ]; then
printf '%s\n' "${prefix}/bin/honeycomb"
return 0
fi
return 1
}
# ─────────────────────────────────────────────────────────────────────────────
# Step 3 — hand off to the CLI verb for the daemon-ensure + health-gate + dashboard
# open. The open logic lives ONCE in the CLI (src/commands/install.ts), not
# here. The verb is idempotent + health-gated (a-AC-2 / a-AC-4) and opens
# honeycomb.local → loopback (a-AC-6), writing onboarding "installed" (a-AC-5).
# ─────────────────────────────────────────────────────────────────────────────
main() {
ensure_node || exit 1
install_honeycomb || exit 1
bin="$(resolve_honeycomb_bin)"
if [ -z "$bin" ]; then
fail "could not locate the installed 'honeycomb' command after the global install."
printf '\nOpen a NEW terminal (so PATH refreshes) and run:\n\n honeycomb install\n\n'
exit 1
fi
# The verb prints its own friendly step log (daemon up / onboarding marked / opening dashboard) and
# returns a clean exit code; we forward it verbatim. A handled failure inside the verb is already a
# plain-language line + non-zero exit — no raw stack reaches the user here. Forward the caller's args
# ("$@") so a bootstrap `--ref <code>` (and any future install flag) reaches the CLI's install verb.
"$bin" install "$@"
exit $?
}
main "$@"
# Honeycomb one-command bootstrap installer (Windows PowerShell) -- PRD-050a.
#
# Usage (the single line a brand-new Windows user pastes):
# irm https://get.theapiary.sh/install.ps1 | iex
#
# This is the FUNCTIONAL EQUIVALENT of install.sh (PRD-050a a-AC-5): same contract -- leave the user
# on a running dashboard, or tell them in ONE plain sentence why not. It owns ONLY the host-bootstrap
# half (detect/install Node+npm via fnm + a pinned LTS, then `npm i -g @legioncodeinc/honeycomb`),
# then HANDS OFF to the `honeycomb install` CLI verb for the daemon-ensure + health-gate +
# dashboard-open -- so that logic lives ONCE in TypeScript (src/commands/install.ts).
#
# Thin + idempotent: detect what is present, install only what is missing, re-run safely.
#
# ASCII-only by design: this file is sourced via `irm | iex` and parsed by Windows PowerShell 5.1,
# which reads a non-BOM file as the system ANSI codepage -- so non-ASCII glyphs would corrupt the
# parse. The friendly progress GLYPHS the user sees come from the CLI verb's UTF-8 output; this
# script's own prefixes stay ASCII.
# Handle every failure explicitly + print a plain-language line (parent AC-7). We do NOT set
# $ErrorActionPreference='Stop' globally -- that would surface a raw PowerShell exception/trace.
$ErrorActionPreference = 'Continue'
# -----------------------------------------------------------------------------
# THE ONE PLACE TO BUMP NODE. The single pinned Node LTS the installer provisions
# via fnm. To upgrade the provisioned Node for every new user, change THIS line
# only. (Existing users with a working Node are left untouched -- see Ensure-Node.)
# -----------------------------------------------------------------------------
$HoneycombNodeVersion = '22'
# The published npm package the global install pulls (PRD-048 publishes it; this consumes it).
$HoneycombNpmPackage = '@legioncodeinc/honeycomb@latest'
# Distribution base URL: the vanity domain that serves this installer surface (PRD-050a follow-up,
# now RESOLVED). get.theapiary.sh is a Cloudflare Pages site (site/install/) that content-negotiates:
# a shell client piping `/` gets the POSIX install.sh as text/plain; a browser gets an "inspect before
# piping" page with the PUBLISHED SHA-256 checksums. `$HoneycombInstallBaseUrl/install.ps1` always
# resolves to the raw, checksummed script. To verify before running: see https://get.theapiary.sh
$HoneycombInstallBaseUrl = 'https://get.theapiary.sh'
# Friendly progress log: step lines to the host, the single failure summary to the error stream.
function Write-Step([string]$m) { Write-Host "-> $m" }
function Write-Ok([string]$m) { Write-Host "[ok] $m" }
function Write-Fail([string]$m) { [Console]::Error.WriteLine("Honeycomb install could not continue: $m") }
function Test-Have([string]$name) { return [bool](Get-Command $name -ErrorAction SilentlyContinue) }
# a-AC-3 -- print the EXACT copy-paste install command + a one-line WHY. NEVER a raw error dump.
function Show-NodeElevationHelp {
Write-Fail "Honeycomb needs Node $HoneycombNodeVersion and could not install it automatically (your machine blocked the no-admin install)."
Write-Host ''
Write-Host "Install Node $HoneycombNodeVersion yourself with ONE of these, then re-run this installer:"
Write-Host ''
Write-Host ' # winget (recommended on Windows 10/11):'
Write-Host ' winget install OpenJS.NodeJS.LTS'
Write-Host ''
Write-Host ' # or via the official MSI:'
Write-Host ' https://nodejs.org/en/download'
Write-Host ''
Write-Host ' # Then re-run:'
Write-Host " irm $HoneycombInstallBaseUrl/install.ps1 | iex"
Write-Host ''
}
# -----------------------------------------------------------------------------
# Step 1 -- Node + npm. If both present, use them. Else install fnm (NO elevation)
# + the pinned Node LTS. fnm installs under the user profile, so it never
# needs admin; that is why it is the primary path over the official MSI.
# -----------------------------------------------------------------------------
function Ensure-Node {
if ((Test-Have 'node') -and (Test-Have 'npm')) {
Write-Ok "Node $(node --version) and npm $(npm --version) found."
return $true
}
Write-Step 'Node/npm not found -- installing a private copy via fnm (no admin rights needed)...'
if (-not (Test-Have 'fnm')) {
# Prefer winget (per-user, no elevation) to install fnm; fall back to the documented manual path.
if (Test-Have 'winget') {
winget install Schniz.fnm --accept-source-agreements --accept-package-agreements 2>$null | Out-Null
# winget does NOT refresh THIS session's PATH, so a bare `fnm` lookup right after the install can
# still miss even though the binary is on disk. Rebuild $env:Path from the machine + user
# registry so the just-installed shim resolves in-process before we judge the install failed.
try {
$machinePath = [System.Environment]::GetEnvironmentVariable('Path', 'Machine')
$userPath = [System.Environment]::GetEnvironmentVariable('Path', 'User')
$env:Path = (@($machinePath, $userPath) | Where-Object { $_ }) -join ';'
} catch {
# Fail-soft: the `Test-Have 'fnm'` re-check below is the real gate; just surface why, don't abort.
Write-Warning "Couldn't refresh PATH from the registry ($($_.Exception.Message)); continuing."
}
}
if (-not (Test-Have 'fnm')) {
# Could not install fnm without elevation -- surface the exact manual command + clean exit (a-AC-3).
Show-NodeElevationHelp
return $false
}
}
# Load fnm into THIS session so node/npm resolve in-process (the install does not refresh the
# current shell's PATH). `fnm env` emits the PowerShell shims; invoke them here.
# Fail-soft on `fnm env`: the final `Test-Have 'node'/'npm'` gate below is the real decider; a failure
# here must not abort the bootstrap, but the reason should be visible (not silently swallowed).
try { fnm env --use-on-cd | Out-String | Invoke-Expression } catch {
Write-Warning "fnm env (pre-install) didn't load into this session ($($_.Exception.Message)); continuing."
}
fnm install $HoneycombNodeVersion 2>$null | Out-Null
fnm use $HoneycombNodeVersion 2>$null | Out-Null
try { fnm env --use-on-cd | Out-String | Invoke-Expression } catch {
Write-Warning "fnm env (post-install) didn't load into this session ($($_.Exception.Message)); continuing."
}
if ((Test-Have 'node') -and (Test-Have 'npm')) {
Write-Ok "Installed Node $(node --version) via fnm."
return $true
}
Show-NodeElevationHelp
return $false
}
# -----------------------------------------------------------------------------
# Step 2 -- install @legioncodeinc/honeycomb globally. The embedding runtime is an
# OPTIONAL dep pulled by npm here; its MODEL WEIGHTS are NOT fetched now
# (lazy warmup -- 050b), so this stays fast.
# -----------------------------------------------------------------------------
function Install-Honeycomb {
Write-Step "installing $HoneycombNpmPackage globally..."
npm install -g $HoneycombNpmPackage 2>$null | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Fail "the global install of $HoneycombNpmPackage failed."
Write-Host ''
Write-Host 'Try it directly to see the npm error, then re-run this installer:'
Write-Host ''
Write-Host " npm install -g $HoneycombNpmPackage"
Write-Host ''
return $false
}
Write-Ok "installed $HoneycombNpmPackage."
return $true
}
# Resolve the ABSOLUTE path to the freshly-installed honeycomb bin. `npm i -g` does NOT refresh the
# CURRENT session's PATH, so calling `honeycomb` by bare name in the same run can fail (PRD-050a
# impl-note). Resolve `%AppData%\npm\honeycomb.cmd` (the npm global bin shim on Windows).
function Resolve-HoneycombBin {
$cmd = Get-Command 'honeycomb' -ErrorAction SilentlyContinue
if ($cmd) { return $cmd.Source }
$prefix = (npm prefix -g 2>$null)
if ($prefix) {
$candidate = Join-Path $prefix 'honeycomb.cmd'
if (Test-Path $candidate) { return $candidate }
}
$appdataCmd = Join-Path $env:AppData 'npm\honeycomb.cmd'
if (Test-Path $appdataCmd) { return $appdataCmd }
return $null
}
# -----------------------------------------------------------------------------
# Step 3 -- hand off to the CLI verb for the daemon-ensure + health-gate + dashboard
# open. The verb is idempotent + health-gated (a-AC-2 / a-AC-4) and opens
# honeycomb.local -> loopback (a-AC-6), writing onboarding "installed" (a-AC-5).
# -----------------------------------------------------------------------------
# Returns a status CODE (never calls `exit`): in the documented `irm ... | iex` bootstrap, `exit`
# terminates the CALLER's PowerShell host and can close the user's terminal. The single process-exit
# handling lives at the entrypoint below, which sets `$global:LASTEXITCODE` from this return value.
function Invoke-Main {
if (-not (Ensure-Node)) { return 1 }
if (-not (Install-Honeycomb)) { return 1 }
$bin = Resolve-HoneycombBin
if (-not $bin) {
Write-Fail "could not locate the installed 'honeycomb' command after the global install."
Write-Host ''
Write-Host 'Open a NEW terminal (so PATH refreshes) and run:'
Write-Host ''
Write-Host ' honeycomb install'
Write-Host ''
return 1
}
# The verb prints its own friendly step log and returns a clean exit code; forward it verbatim. A
# handled failure inside the verb is already a plain-language line + non-zero exit -- no raw trace.
& $bin install
return $LASTEXITCODE
}
# Entrypoint: run main, then set the exit code ONCE without tearing down the host (so `irm | iex`
# hands control back to the user's session instead of closing it).
$global:LASTEXITCODE = Invoke-Main