Headless agents & setups¶
Hive can run an agent without the desktop app, using the hive CLI — on a
cloud VM, a spare box, or as a background process on your own machine. This page
covers the ways to wire that up and which one fits your situation.
The command reference for the CLI lives in
crates/hive-cli/README.md. This page is about topology — where the agent runs and how it reaches your workspace.
Install the CLI¶
One line — macOS + Linux, Apple Silicon and x86_64:
It drops the prebuilt hive binary from the latest release onto your PATH
(override the dir with HIVE_INSTALL_DIR, pin a tag with HIVE_VERSION). Or
build from source: cargo install --path crates/hive-cli.
The CLI is the same runtime as the desktop app, without the window — so it can host agents, drive chats, and sync from a terminal or a background service. Even if you live in the GUI, installing it locally is worth it when you want agents to keep working while the app is closed, or to script Hive from cron / a git hook / CI (setup 1 below).
The one rule that decides your setup¶
Hive state is a per-device, end-to-end-encrypted event log — a local
hive.db. Anything participating in a workspace must either
- share that file (same machine), or
- sync it over a relay (different machines or processes).
Everything below follows from that.
The four setups¶
1 — Personal agent, one machine, no relay¶
The most common local case: you already run the desktop app and want your agents
to keep answering @mentions even when the app is closed — with zero
infrastructure. Point the CLI at the app's own data dir so both read/write the
same hive.db:
# macOS app data dir shown; adjust per-OS. `hive agent` is a local, personal
# responder — gated so it never runs unattended by accident.
HIVE_ALLOW_PERSONAL_AGENT=1 \
HIVE_DATA_DIR="$HOME/Library/Application Support/com.hive.desktop" \
hive agent bot
Run it as a background service — launchd on macOS, systemd on Linux — and the agent stays responsive after you quit the app or shut the lid.
The same data-dir trick lets you script Hive from a terminal, cron, a git
hook, or CI without the GUI: hive send @agent "…", hive new, hive tail,
hive queue, hive sync.
Trade-offs: the agent signs as you (shared identity, not a distinct agent account); the app refreshes on window focus rather than instantly; and it's a single-writer-ish SQLite file (fine for one agent, don't pile on writers). For a distinct agent identity, instant updates, and multiple concurrent writers, add a relay (setup 2+).
2 — Personal agent, local relay¶
Run the relay (the standalone Go service — docker run -p 8443:8443 …) on
localhost and point both the app and the CLI at it. Now the agent has its
own identity (a distinct member), you get live updates, and concurrency is
clean. Cost: one extra process to run. See
Self-hosting a relay.
3 — Remote agent / always-on worker¶
The agent lives on a remote machine (cloud VM, container, an office box). Here a relay is required — there is no shared filesystem across machines — but it can be self-hosted. This is the setup that lets an agent keep working while your laptop is closed: the relay's store-and-forward holds the agent's events, and your app catches up when it next comes online.
Provision the relay URL, token, room, and workspace key out-of-band, then run the worker daemon — it registers the box as a host and runs every agent bound to it on a workspace-owned credential (never your personal key):
export HIVE_RELAY_URL=… HIVE_RELAY_ACCESS_TOKEN=… HIVE_WORKSPACE=acme HIVE_WORKSPACE_KEY=…
export HIVE_WS_SECRET_acme=sk-…
hive register-worker --label prod-box # → this box's host id
hive add-agent reviewer ws-claude --host <host-id>
hive sync
hive worker --label prod-box # always-on; @reviewer is now answered here
The worker enforces the §12.5 rule — a detached agent must use a workspace
runtime, so it never falls back to a personal key. It also drains queued work:
an unanswered @mention waits for its agent's host, and the worker answers every
one bound to it — backlog included — so it catches up on mentions addressed while
it was down. hive queue shows what's waiting and whether each agent's host is
online; if a member's device host is offline, hive set-agent-host <agent>
<worker> reassigns the agent to a worker to drain it ("run on worker instead").
See the
CLI README
for the full daemon behaviour.
The desktop app surfaces the same queue without the CLI: the Review
pane lists every unanswered agent mention with its host's live status, and an
offline or device-bound agent gets a Run on worker button that reassigns it
to an online worker — the GUI equivalent of hive set-agent-host. See
Right Rail — Review.
Give the worker tools. A worker (or hive agent) can reach external boards
like Linear or GitHub through MCP tools: point HIVE_MCP_CONFIG at a TOML
listing MCP servers and provision each server's token via the environment (never
in the file). With no config it runs tool-free, exactly as before. See the
CLI README — MCP tools for headless agents.
Tools are gated on the requester's role. A synced message only drives the
worker's MCP tools if its author holds at least HIVE_MCP_MIN_ROLE
(viewer|contributor|admin|owner, default contributor). Below that bar
the agent still replies — it just runs tool-free, so a Viewer can't provoke
a write to Linear or GitHub through a headless agent. Raise the bar with
HIVE_MCP_MIN_ROLE=admin. See the
CLI README — requester-role gate.
Do not try to substitute a network filesystem (SSHFS/NFS) for the relay — SQLite over a network mount is corruption-prone. Use the relay.
4 — A team¶
Everyone joins the same room on a shared relay (self-hosted or hosted) with the workspace key. The relay is content-blind (E2EE), channels organize the work, and configuration is hoisted to the workspace so every chat inherits the same agents, skills, vaults, and runtimes. Members' apps and any workers all sync through the one room.
Which setup?¶
| You want… | Setup |
|---|---|
| A personal agent, no infra | 1 — shared data dir |
| A personal agent, live + clean identity | 2 — local relay |
| An agent that runs while you're away / on a server | 3 — remote worker + relay |
| A team | 4 — shared relay |
Constraints that apply to every setup¶
- E2EE key. The workspace key is shared out-of-band. The relay never sees plaintext and cannot help you recover a lost key.
- The relay is content-blind and self-hostable — it stores and forwards sealed envelopes only. It is not a required cloud service.
- Retention. A device fetches events after its cursor; if you're offline longer than the relay retains events, you miss anything pushed beyond retention (you keep everything you'd already synced).
- Headless credentials — relay token, workspace key, and any provider or workspace-runtime secret — are provisioned out-of-band (env / secret mount).
Why a remote agent doesn't need your API key¶
A detached agent runs on a workspace-owned runtime (spec §12.5): a provider/model the workspace owns, synced to every member and worker, with a credential the workspace provides. Your personal key never leaves your device.
Define one, share it, provision its secret on the worker, then point the agent at it:
hive add-runtime ws-claude "Team Claude" anthropic claude-sonnet-4-5 --secret-ref acme
hive sync # share it with the workspace
HIVE_WS_SECRET_acme=sk-… hive agent bot --runtime ws-claude
--secret-ref <name>keeps the key off the synced log — the worker holds it in envHIVE_WS_SECRET_<name>.hive runtimesshows✓when it's present.--secret <value>carries the key E2EE on the log (zero worker provisioning; use only for trusted workspaces).
Concurrency: worker pools + isolated edits¶
Several people can drive the same shared agents from different channels at once, and the work stays correct:
- Per-request correlation. Each reply is tagged with the exact mention it answers, so two concurrent tasks to one agent never collapse onto a single reply — one task showing "answered" while its work never ran.
- Isolated, review-gated edits. A file-mutating agent turn (Claude Code with
write access / aider / pi) runs in its own git worktree cut from
HEAD, so concurrent turns can't clobber each other's uncommitted work. On completion its diff is captured as a FileDiff proposal in the Review pane — approve it and Implement applies the patch to the workspace. Nothing lands silently. (Isolated turns start from the last commit, not the main tree's uncommitted WIP.) - Worker pool for throughput. Run several
hive workerprocesses to drain the backlog in parallel —claim_turnde-dups so no two answer the same mention, and per-turn worktrees keep their file edits from colliding even on a shared checkout:
# run workers from inside the repo checkout they should edit
HIVE_WORKER_PERMISSION_MODE=acceptEdits hive worker --label prod-1 &
HIVE_WORKER_PERMISSION_MODE=acceptEdits hive worker --label prod-2 &
# each claims distinct mentions; each write turn isolates its own worktree
A single worker drains serially, so add processes to scale throughput.
Write access is opt-in. A worker's claude agents are read-only by
default (they answer but don't edit). Set
HIVE_WORKER_PERMISSION_MODE=acceptEdits (write files) or bypassPermissions
(also run shell commands) to let them edit — only then does a worker turn
isolate a worktree and produce a review-gated proposal. Run the worker from
within the repo checkout it should work on (its cwd is the base for the
worktree). A headless worker with bypassPermissions is powerful — grant it
only on trusted boxes.
Coming updates you see on reconnect¶
Whatever a headless agent does while you're offline — reply in a chat, create a channel, change workspace config — rides the same synced event log, so your app pulls it on the next sync and the UI (chats and the channel tree) refreshes. The only requirement is that both sides share the same relay, room, and workspace key. On a local-only workspace (no relay), there's nothing to sync through — use setup 1 (shared data dir) instead.