Watch
0
0
Fork
You've already forked hyperhive
0

docs: nest config examples and use neutral swarm/hive names

Closes #6146
This commit is contained in:
atlas 2026-11-06 20:53:32 +01:00 • committed by mara
commit 4c321f3d2d
8 changed files with 113 additions and 77 deletions

View file

@ -68,11 +68,17 @@ The smallest working config, as in the README's
```nix
services.hyperhive = {
deploy.singleHostSwarm = true;
deploy.hive-controller.enable = true;
swarm.domain = "hive.example";
deploy.hive-controller.hiveName = "pr1ma";
swarm.hives.pr1ma = { };
swarm = {
domain = "myswarm.example";
hives.firsthive = { };
};
deploy = {
singleHostSwarm = true;
hive-controller = {
enable = true;
hiveName = "firsthive";
};
};
};
```

View file

@ -119,7 +119,7 @@ an agent's config arrive as PRs you merge. → [`2-handbook/agent-lifecycle/agen
To create an agent yourself instead, use the swarm UI, or:
```bash
swarmctl agent create iris --hive pr1ma
swarmctl agent create iris --hive firsthive
```
The controller provisions iris's identity, forge user and config repo

View file

@ -503,17 +503,21 @@ as the forge or the secret store is down. A restart isn't needed to recover.
```nix
services.hyperhive = {
swarm.domain = "example.com"; # required — the swarm's DNS domain
deploy.hive-controller.hiveName = "pr1ma"; # required on a hive host — this hive's label in it
swarm.name = "constellat1on"; # shared swarm display name (optional)
swarm = {
domain = "myswarm.example"; # required — the swarm's DNS domain
name = "myswarm"; # shared swarm display name (optional)
# required — the directory, identical on every host in the swarm.
# Names only: each entry's `domain` defaults to <name>.<swarm.domain>.
swarm.hives = {
pr1ma = { }; # this host, per hiveName
lab = { }; # a second hive
edge = { domain = "edge.elsewhere.example"; }; # addressed off-convention
# required — the directory, identical on every host in the swarm.
# Names only: each entry's `domain` defaults to <name>.<swarm.domain>.
hives = {
firsthive = { }; # this host, per hiveName
secondhive = { }; # a second hive
thirdhive.domain = "thirdhive.elsewhere.example"; # addressed off-convention
};
};
# required on a hive host — this hive's label in the directory
deploy.hive-controller.hiveName = "firsthive";
};
```
@ -536,9 +540,9 @@ names the missing hive. Peers are _every entry but this host's_, so a
directory without this host would make every hive a peer, itself included.
```
# hive A # hive B
deploy.hive-controller.hiveName = "pr1ma"; deploy.hive-controller.hiveName = "edge";
swarm.hives = { … }; swarm.hives = { … }; # byte-identical
# hive A # hive B
deploy.hive-controller.hiveName = "firsthive"; deploy.hive-controller.hiveName = "secondhive";
swarm.hives = { … }; swarm.hives = { … }; # byte-identical
```
One entry per hive means two hosts can't hold _different_ facts about the
@ -548,7 +552,7 @@ same third hive, such as a stale endpoint.
is names only. Set it only for a hive addressed by something else. This
hive's own `services.hyperhive.domain` comes from its entry; it drives
`HYPERHIVE_HIVE_DOMAIN` in every container so agents can form qualified
labels (`iris@pr1ma.example.com`). Setting `services.hyperhive.domain`
labels (`iris@firsthive.myswarm.example`). Setting `services.hyperhive.domain`
directly overrides the directory entry, with a deprecation warning: the
option is local to this host while every host shares the directory, so a
value written only here is invisible to the rest of the swarm.
@ -608,42 +612,44 @@ wg pubkey < /etc/wireguard/hive.key # → share this with peer operators
#### Config example (two hives)
```nix
# hive A (pr1ma.example.com, mesh IP 10.100.0.1)
# hive A (firsthive.myswarm.example, mesh IP 10.100.0.1)
services.hyperhive = {
deploy.wireguard = {
enable = true;
enable = true;
privateKeyFile = "/etc/wireguard/hive.key";
address = "10.100.0.1/24";
listenPort = 51820; # optional, default 51820
address = "10.100.0.1/24";
listenPort = 51820; # optional, default 51820
};
# The same `hives` attrset both hosts hold — mesh fields included,
# since "where this hive can be dialled" is a fact about that hive.
swarm.hives = {
pr1ma = {
domain = "pr1ma.example.com";
firsthive = {
domain = "firsthive.myswarm.example";
wireguardPublicKey = "base64keyA=";
wireguardEndpoint = "198.51.100.1:51820";
wireguardAddress = "10.100.0.1/32";
wireguardEndpoint = "198.51.100.1:51820";
wireguardAddress = "10.100.0.1/32";
};
edge = {
domain = "edge.corp";
secondhive = {
domain = "secondhive.elsewhere.example";
wireguardPublicKey = "base64keyB=";
wireguardEndpoint = "203.0.113.42:51820";
wireguardAddress = "10.100.0.2/32";
wireguardEndpoint = "203.0.113.42:51820";
wireguardAddress = "10.100.0.2/32";
};
};
};
# hive B (edge.corp, mesh IP 10.100.0.2)
# hive B (secondhive.elsewhere.example, mesh IP 10.100.0.2)
services.hyperhive = {
deploy.wireguard = {
enable = true;
enable = true;
privateKeyFile = "/etc/wireguard/hive.key";
address = "10.100.0.2/24";
address = "10.100.0.2/24";
};
swarm.hives = { /* … identical to hive A's … */ };
swarm.hives = {
# … identical to hive A's …
};
};
```

View file

@ -171,8 +171,10 @@ They derive together: a store with no UI is unreadable and a UI with no
store is empty. To run one without the other, set it directly:
```nix
services.hyperhive.deploy.victoriametrics.enable = true;
services.hyperhive.deploy.grafana.enable = false;
services.hyperhive.deploy = {
victoriametrics.enable = true;
grafana.enable = false;
};
```
⚠️ **This starts a database that grows for as long as the swarm runs.**

View file

@ -153,9 +153,13 @@ Only the swarm's forge host runs it (`services.hyperhive.deploy.forgejo.enable`,
```nix
# The SSH port is swarm-wide: every hive dials it. The HTTP port and whether
# THIS host opens them in its firewall are this host's deployment decisions.
services.hyperhive.swarm.forge.sshPort = 2222; # default — git-over-SSH, off the host's openssh on 22
services.hyperhive.deploy.forgejo.httpPort = 3000; # default — outside hyperhive's 7000 / 8100-8999
services.hyperhive.deploy.forgejo.openFirewall = false; # default
services.hyperhive = {
swarm.forge.sshPort = 2222; # default — git-over-SSH, off the host's openssh on 22
deploy.forgejo = {
httpPort = 3000; # default — outside hyperhive's 7000 / 8100-8999
openFirewall = false; # default
};
};
```
`sshPort` serves `git clone/push/pull` over SSH (`git@<domain>:owner/repo.git` with `-p 2222`). SSH goes straight to Forgejo, not through nginx.

View file

@ -92,10 +92,14 @@ listener sits on `bridgeIp`, on the host's bridge interface.
```nix
{
services.hyperhive = {
deploy.hive-controller.enable = true;
deploy.hive-controller.hiveName = "pr1ma";
swarm.domain = "darkest.space";
swarm.hives.pr1ma = { }; # -> domain = pr1ma.darkest.space
swarm = {
domain = "myswarm.example";
hives.firsthive = { }; # -> domain = firsthive.myswarm.example
};
deploy.hive-controller = {
enable = true;
hiveName = "firsthive";
};
# network.bridgeIp = "10.42.0.1"; # default
};
}

View file

@ -19,17 +19,19 @@ assumptions:
## Enabling it
```nix
services.hyperhive.snapshotStore = {
enable = true;
path = "/var/lib/hyperhive-snapshots"; # must be on btrfs
port = 51821;
};
services.hyperhive = {
snapshotStore = {
enable = true;
path = "/var/lib/hyperhive-snapshots"; # must be on btrfs
port = 51821;
};
# The mesh is a hard requirement, and is asserted:
services.hyperhive.deploy.wireguard = {
enable = true;
address = "10.100.0.9/24";
privateKeyFile = "/etc/wireguard/hive.key";
# The mesh is a hard requirement, and is asserted:
deploy.wireguard = {
enable = true;
address = "10.100.0.9/24";
privateKeyFile = "/etc/wireguard/hive.key";
};
};
```

View file

@ -135,8 +135,10 @@ single-host deploy, but are useful for multi-hive or custom-network
setups.
```nix
services.hyperhive.agent.forge.url = "http://forge.example:3000"; # default: null
services.hyperhive.agent.matrix.url = "https://matrix.example"; # default: null
services.hyperhive.agent = {
forge.url = "http://forge.example:3000"; # default: null
matrix.url = "https://matrix.example"; # default: null
};
```
**`services.hyperhive.agent.forge.url`** — base URL of the Forgejo instance. It scopes
@ -179,15 +181,19 @@ The harness installs Claude Code plugins before the serve loop opens.
Three per-agent `agent.nix` options control this:
```nix
services.hyperhive.agent.claudeMarketplaces = [ # default
"anthropics/claude-plugins-official"
"${services.hyperhive.agent.packages.claude-plugins}" # hive's own local marketplace, registered as `hyperhive`
];
services.hyperhive.agent.claudePlugins = [ # default
"skill-creator@claude-plugins-official"
"base@hyperhive"
];
services.hyperhive.agent.claudePluginsAutoUpdate = false; # default
services.hyperhive.agent = {
claudeMarketplaces = [
# default
"anthropics/claude-plugins-official"
"${services.hyperhive.agent.packages.claude-plugins}" # hive's own local marketplace, registered as `hyperhive`
];
claudePlugins = [
# default
"skill-creator@claude-plugins-official"
"base@hyperhive"
];
claudePluginsAutoUpdate = false; # default
};
```
- **`claudeMarketplaces`** — list of marketplace sources passed to
@ -248,10 +254,11 @@ programmatically and don't pass `--message-format json` themselves.
## API-key provider (`useApiKey` / `backendEnvironmentFile`)
```nix
services.hyperhive.agent.useApiKey = true; # default: false
services.hyperhive.agent.backendEnvironmentFile =
"/agents/myagent/harness/openrouter.env"; # default: null
services.hyperhive.agent.model = "anthropic/claude-3.5-sonnet"; # provider-specific model string
services.hyperhive.agent = {
useApiKey = true; # default: false
backendEnvironmentFile = "/agents/myagent/harness/openrouter.env"; # default: null
model = "anthropic/claude-3.5-sonnet"; # provider-specific model string
};
```
Runs this agent's `claude` against an API-key provider (for example OpenRouter)