hyperhive/docs/turn-loop/config.md
atlas 0e9b1c563d fix(#2860): no loopback default for the matrix homeserver
Third and last of #2860's agent-facing URL fallbacks. The operator's
ruling was "any special casing is done on the nix side - same binaries,
no hard coded fallback", so the default is deleted rather than replaced.

Every layer guessed the same wrong thing, and each guess was only ever
correct for a process sharing the host netns:

- nix/agent-modules/matrix.nix: matrixUrlDefault = localhost:8008, both
  as the option's default and as a sentinel the daemon unit compared
  against to decide whether to write HIVE_MATRIX_URL. Now nullOr str,
  default null, the guard is != null, and the doc says what forge.url's
  already says: null means "no matrix", not "guess one".
- nix/host-modules/hive-c0re/environment.nix: forwarded
  http://127.0.0.1:<port> when no gatewayHost was set. hive-c0re shares
  the host netns so it reads as harmless, but the value is handed to
  agents, which do not -- there it names the agent itself. Now forwarded
  only when there is a gateway vhost to name, matching the guard
  HIVE_MATRIX_PUBLIC_URL already uses twelve lines below.
- hive-matrix-mcp: paths::DEFAULT_HOMESERVER was the same address
  compiled in, so dropping the nix defaults alone would have left the
  daemon dialling loopback inside the agent's own netns -- the very bug,
  one layer down. homeserver_url() is now Option, and an account with no
  homeserver is skipped with a log, exactly as one with no token is.
  discover_token_accounts already refused to guess for the same reason.

Two comments taught the assumption back to the next reader ("shared host
netns means every agent container resolves localhost to the same
machine"); both now say which side of the netns boundary they describe.
MATRIX_HTTP keeps its value -- hive-c0re really does share the host
netns -- but no longer claims agents do.

Gated with nix eval against the extended agent-base config, as a pair:
with no url set the daemon unit carries no HIVE_MATRIX_URL, and with one
set it carries exactly that. Either check alone passes on a broken guard.
2026-08-03 20:34:36 +02:00

9.8 KiB

Agent config knobs

Optional per-agent knobs the meta flake wires into the container from services.hyperhive.agents.<name>, read at boot or per turn by the harness. Absent means the default. (The claude spawn + compaction themselves live in claude-invocation.)

Reference docs (hyperhive.docs.enable)

hyperhive.docs.enable = true;  # default: false (true for the manager agent)

Makes the hyperhive docs/ tree available inside the container at a nix store path read from $HIVE_DOCS_DIR, and injects a single pointer sentence into the agent's system prompt so it knows the docs exist and where to find them. The tree is served by claude --add-dir so the full markdown is readable during every turn.

Enabled by default only for the root/manager agent (nix/templates/ruth.nix). Any agent can opt in by adding the line above to its agent.nix.

The docs/ source is a narrow flake input (hyperhive-docs) tracked separately from the main hyperhive flake so editing docs re-locks only that input — not every agent's container gets rebuilt on a doc-only change.

Agent icon

hyperhive.icon = ./icon.svg;  # default: null (falls back to shared hyperhive logo)

Path to an SVG file used as this agent's visual identity — shown in the per-agent page header, as the page favicon, and uploaded to the agent's Forgejo profile avatar (via the forge-avatar-sync boot unit) and Matrix profile avatar (set by hive-matrix-daemon over its live Client). Commit the SVG next to agent.nix in the config repo and reference it as a relative path.

When null (the default), the agent falls back to the shared hyperhive branding mark. The harness serves whichever icon is active at GET /icon on the per-agent web port.

user.passwordlessSudo

hyperhive.user.passwordlessSudo = true;  # default

Grants the per-agent unix user passwordless sudo (NOPASSWD: ALL). Enabled by default so claude's shell tools work for operations that need root inside the container (systemctl, package managers in dev shells, etc.) — the same privilege surface the previous root-user shape had, now elevated explicitly rather than implicitly.

Set to false for agents that should be strictly unprivileged. Any tool invocation that needs root then fails loudly with the standard sudo rejection rather than silently succeeding — easier to audit.

hyperhive.user.uid, hyperhive.user.gid, and hyperhive.user.name are the companion options; see docs/agent-hierarchy.md — "Harness systemd unit shape" for the full user.* surface.

hyperhive.dashboardLinks = [
  { label = "Stats"; icon = "📊"; url = "http://localhost:9001/stats"; }
  { label = "Scratchpad"; url = "http://localhost:8080"; }
];

Declares extra navigation links that appear on the agent's dashboard card and in the per-agent page header alongside the built-in forge / config / container links. Each entry has:

Field Required Description
label yes Display text shown in the icon strip tooltip and meta-nav.
url yes Absolute URL — may include a different port (the dashboard renders it as a plain anchor).
icon no Emoji or short glyph prefix. Defaults to empty string.

The list is written to <state>/hyperhive-dashboard-links.json by a one-shot systemd unit at container boot. hive-c0re reads the file on each container-view snapshot and attaches the links to the agent card (kind = External) without any code change. Omitting the option (default empty) produces no extra links.

Custom static files

hyperhive.frontend.extraFiles = {
  "games/bitburner" = {
    source = ./bitburner-dist;   # path relative to agent.nix
    # target defaults to attribute name: "games/bitburner"
  };
  "my-page" = {
    source = ./my-page.html;
    target = "my-page.html";    # explicit override
  };
};

Layers additional files over the default per-agent web UI dist. Each attribute defines one overlay entry:

  • source — a Nix path (file or directory) copied into the merged static tree. Evaluated at nix build time; the resulting derivation is pointed at by HIVE_STATIC_DIR.
  • target — destination path within the merged tree, used as both the served URL prefix (/<target>/…) and the on-disk layout. Defaults to the attribute name. Forward slashes create nested layouts ("games/bitburner" serves at /games/bitburner/…).

Constraints: target must start with an alphanumeric or _ and contain only alphanumerics, _, ., /, -. .. segments are rejected by a config assertion. The merge step refuses to overwrite files already present in the default dist — pick a target name that does not collide with existing paths (static/, index.html, etc.).

The default dist ships at hyperhive.frontend.dist (the hyperhive-frontend package output, read-only). To replace the entire UI rather than layer on top, override frontend.dist directly.

Connectivity overrides

Two hyperhive.forge.* / hyperhive.matrix.* options override where the per-agent daemons connect. Both rarely need changing on a standard single-host deploy, but are useful for multi-hive or custom-network setups.

hyperhive.forge.url = "http://forge.example:3000";  # default: null
hyperhive.matrix.url = "https://matrix.example";    # default: null

hyperhive.forge.url — base URL of the Forgejo instance. Used by a one-shot boot unit (tea-login) that writes ~/.config/tea/config.yml directly from the agent's forge-token, so tea and hive-forge work without an interactive auth step. The unit is a no-op when forge-token is absent. Override when the agent should connect to a Forgejo on a different host or port (e.g. a swarm peer's forge). Validated: must be an http:// or https:// URL, or null.

Defaults to null, meaning "no forge" — not a guessed address. A loopback default would only ever be correct when the forge shares the agent's network namespace, and inside a container localhost is the agent itself, so the default was a value that built fine and then talked to the wrong machine. With null the tea-login and forge-avatar-sync units are not generated at all: an absent integration rather than a misdirected one. You do not normally set this — hive-c0re renders the host's real forge URL into every agent, and refuses to write a meta flake without one, so null only survives where the agent modules are evaluated outside a hive.

hyperhive.matrix.url — homeserver URL used by hive-matrix-daemon when connecting via the matrix-sdk. hive-c0re writes it into every agent at deploy time as the gateway-routed matrix.<domain> URL, so isolated agents can reach the homeserver. Override per-agent when an agent should talk to a different homeserver — for example a remote hive's tuwunel reached over a VPN, or an external Matrix server for a federation-only agent.

Defaults to null, meaning "no matrix" — for the same reason forge.url does. The homeserver may live on another host, and a loopback default resolves inside the agent's own netns to the agent, so it would be a value that evaluates fine and then talks to the wrong machine. With null the daemon has no homeserver and no-ops exactly as it does without a token. The hive only forwards HIVE_MATRIX_URL when it actually has a matrix vhost to name, so null survives where a hive runs no homeserver, or where the agent modules are evaluated outside a hive.

Claude Code plugins

The harness installs Claude Code plugins before the serve loop opens. Two per-agent agent.nix options control this:

hyperhive.claudeMarketplaces = [ "anthropics/claude-plugins-official" ];  # default
hyperhive.claudePlugins = [ "skill-creator@claude-plugins-official" ];     # default
hyperhive.claudePluginsAutoUpdate = false;                                 # default
  • claudeMarketplaces — list of marketplace sources passed to claude plugin marketplace add <source>. The official Anthropic marketplace is pre-configured by default; override or extend to add custom marketplaces. Idempotent — re-adding an existing source is a no-op.
  • claudePlugins — list of plugin specs passed to claude plugin install <spec>. Each spec is installed on every boot (install is expected to be idempotent); failures log a warning but do not abort boot. Defaults to Anthropic's skill-creator, so every agent can author, refine, and evaluate its own skills without any per-agent wiring.

Both plugin lists follow ordinary NixOS list-option semantics: a per-agent definition replaces the default, it does not extend it. An agent that sets claudePlugins and still wants skill-creator has to list it explicitly alongside its own entries — likewise for the official marketplace in claudeMarketplaces.

  • claudePluginsAutoUpdate — when true, runs claude plugin marketplace update before installing plugins to pull the latest index. Disabled by default to keep boot times short and plugin versions pinned.

cargo.shortMessages

hyperhive.cargo.shortMessages = true;  # default

When enabled (the default), the harness injects a cargo shell function into /etc/hyperhive/bash-env.sh that transparently appends --message-format short to compile subcommands (build, check, clippy, test, run, doc, bench, install, rustc, fix). This suppresses the per-crate progress lines that flood the response window, leaving only warnings and errors.

The function handles +toolchain selectors (cargo +nightly build) and passes through cleanly when --message-format is already present. Non-compile subcommands (new, add, third-party cargo-*) are left untouched.

Set to false for agents that parse cargo's JSON output programmatically and do not pass --message-format json themselves.