Commit graph hyperhive/nix
Author SHA1 Message Date
atlas
2b4e928afe feat(#1867): make the internal forge mandatory (remove forge.enable)
The internal forge is the canonical store for the meta flake, every
agent's config repo, and the internal/* repos, so it can no longer be
optional. Remove the services.hyperhive.forge.enable toggle:

- hive-forge.nix: drop the `enable` option; the forge config now
  deploys gated on `services.hyperhive.enable` (it ships with hyperhive).
- hive-c0re.nix: HIVE_FORGE_URL env unconditional; forge-public-URL gate
  drops the enable check (keeps behindGateway).
- hive-gateway.nix: local /etc/hosts forge entry keyed on behindGateway.
- hive-ci.nix: drop the now-moot `forge.ci.enable requires forge.enable`
  assertion (forge is always present); reword the option doc.
- nix/docs/default.nix: drop the `forge.enable = mkForce false` stub
  (option gone); the options-doc eval stays light via hyperhive.enable.
- hive-c0re forge.rs / hivectl.rs: reword 'forge.enable = true' error
  text to 'wait for hive-c0re to start the container' (the runtime
  token-absent path is unchanged — it's a bootstrap-timing check, not
  the opt-out).
- docs/approvals.md, docs/ci.md: drop stale forge.enable references.

Migration: configs that set `services.hyperhive.forge.enable = false`
must drop the line — the forge is now mandatory.

Prereq/companion to #1838 (PR-based config flow, which assumes the forge
is always present).
2026-06-22 19:26:34 +02:00
atlas
edad6f863c feat(#1886): trust a peer hive's root CA hive-wide for self-signed federation
Add swarm.peers.<domain>.caCert (path to a peer hive's root CA PEM),
trusted everywhere the hive's own internal CA is — so a self-signed
peer hive can federate (matrix) and any in-hive consumer validates its
certs.

Mechanism (reuses the existing hive-CA embedding): the meta-flake
renderer embeds a LIST of CA files next to each agent's flake —
hive-ca.pem (the hive's own self-signed CA, when active) plus each peer
caCert as peer-ca-<N>.pem — and emits them all in
security.pki.certificateFiles, so every agent trusts them at build
time. The matrix container trusts the same peer CAs for federation TLS.
Nothing is installed in the host trust store; the certs live in the nix
store (no mutable host file).

- meta.rs: embedded_ca_files() = hive CA + peer CAs (from new
  HIVE_PEER_CA_PATHS env); ca_embed_state() tracks the list (content +
  add/remove); sync_agents materialises + stages the list; render emits
  the multi-entry certificateFiles. Tests cover hive-only / hive+peers
  / peers-only / none.
- hive-c0re.nix: HIVE_PEER_CA_PATHS service env (colon-joined caCerts);
  caCert / certFingerprint option docs updated to the hive-wide scope.
- hive-matrix.nix + docs/swarm.md: scope + comment updates.

certFingerprint stays the c0re-only leaf-pin path.
2026-06-22 16:54:44 +02:00
atlas
4db8a8cd3d feat(#1843): static-serve the dashboard via the gateway, hive-c0re API-only
nginx proxied `<hive>/` straight to hive-c0re:7000, and hive-c0re served the
dashboard dist itself via `tower_http::ServeDir` (from `HIVE_STATIC_DIR` baked
into its service env). So a frontend-only change rebuilt the hive-c0re unit and
restarted the core daemon — every operator session dropped its SSE stream for a
pure CSS/JS change.

The gateway nginx now static-serves the dashboard dist directly; hive-c0re's
dashboard router is API-only. The split uses the Accept-header SPA fallback (the
same `map $http_accept` pattern the matrix/agent vhosts already use), so no
backend prefix has to be enumerated: a browser navigation (Accept: text/html)
whose path is not an on-disk asset gets the SPA index.html; everything else
(every /api route, the bare action/mutation routes, the two SSE streams, the
knowledge webhook — all Accept != text/html) falls through `try_files` to the
`@c0re` named location and is reverse-proxied to hive-c0re. A new c0re route
needs no gateway change.

- hive-c0re.nix: expose the themed dist as a new internal read-only option
  `services.hyperhive.c0re.servedFrontend`; drop `HIVE_STATIC_DIR` from the
  service env (the router no longer serves files).
- hive-gateway.nix: read that option in host-module scope (dashboardDist),
  static-serve `dashboard/` with the Accept-header `try_files ... @c0re` split;
  `@c0re` carries `proxy_buffering off` + a 1d read timeout for the SSE streams
  and a duplicated auth_basic block (named locations do not inherit it). The
  dashboard map is unconditional; the matrix map stays gated on the matrix GUI.
- dashboard.rs: drop the ServeDir fallback + the HIVE_STATIC_DIR resolution; the
  router 404s unmatched paths (the gateway only proxies non-static requests).
- hive-c0re/Cargo.toml: drop the now-unused tower-http dependency.
- docs/gateway.md: document the dashboard static split + the `@c0re` fall-through.

The store path is reachable inside the gateway nspawn container (shared
/nix/store), mirroring how HIVE_AGENT_FRONTEND_DIR already exposes the per-agent
UIs. The gateway and c0re changes must land together (atomic cutover) or the
dashboard 404s — this needs a watched gateway + c0re rebuild.
2026-06-22 01:18:01 +02:00
atlas
86ad8bc914 hive-ci: build locally when a remote builder is unreachable
The CI container set `nix.settings.sandbox-fallback` but never
`nix.settings.fallback`, so a cache-miss build with an unreachable
remote build machine had no local fallback and hard-failed. A single
down or DNS-unresolvable `nix.buildMachines` host therefore turned every
fresh `nix flake check` red hive-wide, in ~30s, even for diffs that
can't affect the nix build (pure JS/markdown). Add
`nix.settings.fallback = true` so CI degrades to a slower local build
instead of failing.
2026-06-21 21:48:53 +02:00
atlas
1f602d5fda hive-c0re: back agent state dirs with btrfs subvolumes
Progressive enhancement: a brand-new agent's state root under
/var/lib/hyperhive/agents is created as a btrfs subvolume when the host
filesystem is btrfs, otherwise it falls back to a plain directory. No
existing agent is auto-migrated — the new path only fires when the root
does not yet exist, so plain-dir agents are left untouched until an
explicit opt-in upgrade.

Two new privileged ops (subvolume create/delete are root-only):
EnsureAgentSubvolume statfs-gates on btrfs, creates the subvolume, and
chowns it to the hive-core user so the normal state/claude/harness
mkdirs succeed inside it; DeleteAgentSubvolume btrfs-subvolume-deletes
the root iff it is actually a subvolume. hive-c0re calls Ensure before
the per-agent dirs are created (spawn/rebuild/InitConfig) and Delete on
the purge path only — destroy keeps the subvolume for revival, matching
plain-dir semantics. btrfs-progs added to the hive-priv unit PATH.

Per-subvolume usage accounting + optional quota is a separate
follow-up.
2026-06-19 13:46:39 +02:00
damocles
2d97401fc0 hive-bash-mcp: run tasks under bash instead of sh 2026-06-19 02:06:13 +02:00
atlas
2efd95d0f5 nix(ci): pin the runner readiness gate to --store daemon
A bare `nix store ping` run as root with the daemon socket absent
resolves to a local store (root writes /nix/store directly) and pings
successfully, so the gate could false-pass at cold boot: nix-daemon.socket
carries ConditionPathIsReadWrite=/nix/var/nix/daemon-socket and is
condition-skipped until /nix/var goes read-write. systemd service units
don't source the profile that sets NIX_REMOTE=daemon, so auto-store
fallback to local is the real environment here.

Pin --store daemon so the readiness poll verifies the actual daemon
socket and the gate honours its wait-for-daemon contract instead of
passing against a local fallback while the daemon is still down.
2026-06-18 13:02:21 +02:00
atlas
3b8e77c1c1 nix(gateway): factor the self-signed condition into a shared option
Per review: the `tls.certDir == null && !tls.acme.enable` derivation was
duplicated in hive-gateway, hive-tls, and hive-ci. Expose it once as a
read-only internal option `services.hyperhive.gateway.useSelfSigned` (the
gateway module's single source of truth) and have hive-tls and hive-ci
consume it instead of re-deriving.

Eval-proven: gateway.useSelfSigned is true on the self-signed default /
false with tls.certDir, and the hive-tls (HIVE_TLS_CA_PATH) + hive-ci
(NODE_EXTRA_CA_CERTS) wiring derives correctly from it.
2026-06-18 01:03:55 +02:00
atlas
9f03cf31ba nix(ci): trust the hive CA in the runner's Node actions (self-signed TLS)
With self-signed TLS the gateway/forge serve a hive-CA-signed leaf and
forgejo's ROOT_URL is https://forge.<domain>. The CI runner's Node-based
actions (e.g. upload-artifact) POST to the ROOT_URL-derived artifact
endpoint and fail with "unable to verify the first certificate": Node uses
its own bundled CA bundle, not the system store, so it rejects the
self-signed chain. checkout etc. are fine — they hit the localhost http
registration URL.

Bind-mount the public hive CA cert (only ca.pem — never the hive-tls state
dir, which holds the CA + leaf private keys) into the hive-ci container and
set NODE_EXTRA_CA_CERTS on the runner service so every Node action trusts
it, hive-wide. Order container@hive-ci after the host hive-tls-ca service so
the cert exists before the bind-mount is set up. All gated on self-signed
mode; with an operator cert / ACME the public CA already validates and the
mount + env var are absent.

Eval-proven: self-signed → /run/hive-ca/ca.pem bind-mount (from
/var/lib/hive-tls/ca.pem), NODE_EXTRA_CA_CERTS=/run/hive-ca/ca.pem, and
container@hive-ci ordered after hive-tls-ca.service; certDir → all absent.
2026-06-18 00:17:53 +02:00
atlas
58cc720173 nix(ci): gate the actions runner on nix-daemon readiness
After a hive-ci restart the act_runner re-registers and immediately claims
any queued jobs, which can beat the in-container nix daemon coming up: its
nix-daemon.socket carries ConditionPathIsReadWrite=/nix/var/nix/daemon-socket
and is skipped until /nix/var is read-write, so the first nix-dependent
build dispatches into a cold daemon and hangs/retries (observed: a 55m48s
nix flake check vs the normal ~30s — a build-offload stall, not a code
failure; a non-nix step on the same runner passed in 1s, masking it).

Ordering the runner after/wants nix-daemon.socket does not help — a
condition-skipped unit satisfies systemd ordering immediately. Instead add
a blocking ExecStartPre that polls until the daemon actually answers
(nix store ping), placed with mkBefore so it runs ahead of the upstream
module's runner-registration ExecStartPre. The runner therefore cannot
register or claim jobs until nix is usable. Topology-agnostic (works
whether the daemon is in-container or a shared host socket); ~180s ceiling
then the unit fails cleanly rather than claiming jobs into a dead daemon.

Eval-proven: gitea-runner-hive's ExecStartPre is
[wait-nix-daemon, gitea-register-runner-hive] in that order.
2026-06-17 21:17:35 +02:00
atlas
1a3f82a459 nix(gateway): self-signed TLS as the implicit default, deprecate the toggle
Make self-signed TLS the gateway's default whenever no external TLS source
is configured, and deprecate the explicit selfSignedTls toggle. Self-signed
is now derived as `tls.certDir == null && !tls.acme.enable`, so an operator
selects a TLS mode by setting tls.certDir or tls.acme — or neither, for the
self-signed default. There is no http-only mode: matrix discovery hardcodes
https, so the gateway always terminates TLS.

The selfSignedTls option is kept as a deprecated no-op (warns when set to
false) so existing configs still eval. The two selfSignedTls mutual-
exclusion assertions and the HSTS-requires-TLS assertion are dropped — they
are impossible or vacuous now that self-signed is the floor. The hive-tls
module and the forge ROOT_URL scheme consume the derived value: the gateway
always terminates TLS, so behind the gateway the forge is always advertised
over https.

Updates docs/gateway.md (TLS-modes table, self-signed section, the removed
http-only section, firewall + discovery notes). Eval-proven: default →
self-signed (hive CA active, https ROOT_URL); tls.certDir → CA inactive;
selfSignedTls=false → deprecation warning fires.
2026-06-17 21:14:05 +02:00
atlas
4f3f6522d2 feat(tls): embed hive CA into agent flakes for self-signed trust
Wire agents to trust the gateway's self-signed leaf at build time. When
the gateway runs self-signed TLS, hive-tls sets HIVE_TLS_CA_PATH in
hive-c0re's service env pointing at the host hive CA cert. The meta flake
renderer reads it and, when present, writes the public CA cert next to
flake.nix as hive-ca.pem and emits security.pki.certificateFiles so every
agent's system trust store includes the hive CA.

Build-time embedding (rather than a runtime bind-mount + bundle service)
keeps trust robust: the CA travels with the flake source, lands in the
standard NixOS trust store, and needs no per-process SSL_CERT_FILE
plumbing. Only the public CA certificate is embedded; the CA private key
never leaves the host. The cert is re-embedded and re-committed on CA
rotation even when the flake is otherwise byte-identical; when self-signed
TLS is off the embedded cert is dropped so the flake stays buildable.

Covers OpenSSL-based tools (git, curl) directly. A follow-up switches the
hive-forge reqwest client to native roots so it picks up the same store.
2026-06-17 19:42:15 +02:00
atlas
74a90fd7d6 nix(tls): host hive-CA + gateway leaf for self-signed mode
Replace the gateway's bare in-container self-signed leaf with a leaf
signed by a host-held hive CA. A bare self-signed leaf is its own trust
anchor, so every regeneration is a fresh anchor every consumer would have
to re-trust, and a runtime-generated in-container leaf cannot be wired
into an agent's build-time trust store at all. A stable CA fixes both: a
single anchor that agents and federation peers trust once, surviving leaf
rotation.

New hive-tls module: a host oneshot generates a long-lived CA (default
~20y) under services.hyperhive.tls.stateDir and signs a gateway leaf
(default ~10y, SAN covering the bare domain, forge., matrix. and the
wildcard). It is ordered before the gateway container so the leaf exists
when nginx starts. Active only when the gateway uses self-signed TLS
(default) and a domain is set; inert under operator-cert or ACME modes.

Gateway: bind-mount the host CA dir read-only at /run/hive-ca; the
existing in-container cert unit now imports the host leaf into nginx's
state dir (copy as root, key left root:nginx 0640 for the pre-start
config test) instead of generating one. Cert/key paths nginx serves are
unchanged.

Foundational step toward agent + federation trust of self-signed hives;
no behaviour change for agents yet (they still reach the forge over plain
http on port 80). Eval-proven across self-signed, certDir and the inert
default paths.
2026-06-17 19:04:52 +02:00
atlas
e7a4b33c1e nix(forge): drop tracker tag from ROOT_URL comment
Rewrite the ROOT_URL scheme comment as prose without the parenthetical
issue reference, which the tracker-tag lint flags in source files.
2026-06-17 18:32:21 +02:00
atlas
147fb46cdc nix(forge): derive ROOT_URL scheme from gateway TLS, not always http
Fixes #1724. The forgejo ROOT_URL was hardcoded `http://` even when the
gateway terminates TLS, producing broken clone links and mixed-content
redirects for a TLS deployment.

Derive the scheme + port from gateway state: `https` (on httpsPort) when
the gateway terminates TLS (`gateway.selfSignedTls` or `gateway.tls.certDir`
set), `http` (on gateway.port) otherwise — dropping the port suffix on the
canonical port for the scheme (80 / 443). The per-agent in-cluster
HIVE_FORGE_URL is unaffected (it stays http on the gateway's :80 path);
this only changes the public ROOT_URL forgejo advertises.

Refreshes the `rootUrl` option description (the TLS scheme is auto-derived
now, so the manual-override-for-TLS note is gone).

Eval-proven: gateway.selfSignedTls = true → ROOT_URL =
https://forge.<domain>/; false → http://forge.<domain>/.
2026-06-17 18:32:21 +02:00
atlas
75dbcc2aa2 nix(c0re): trim the network-isolation narrative from the forge/matrix URL comments
Per mara's review of #1718: the HIVE_FORGE_URL / HIVE_MATRIX_URL comments
carried "network isolation is now unconditional / shared-netns removed"
backstory that doesn't belong on those keys. Trimmed to describe just the
value (the gateway vhost) + the gatewayHost null-guard. The
isolation-removal narrative stays where it's on-topic — the network
module's own deprecated-option descriptions and warning text.
2026-06-17 16:58:20 +02:00
atlas
e8c2ef087c nix(c0re): set HIVE_FORGE_URL to the gateway URL directly, drop dead if/else
Per mara's review of #1718: this env block only exists when hyperhive is
enabled (it lives inside `config = mkIf cfg.enable`), so the
`if hyperhive.enable then gateway else loopback` branch was dead — the
loopback fallback could never be reached. Set HIVE_FORGE_URL to the
gateway vhost directly.

HIVE_MATRIX_URL drops the same redundant `hyperhive.enable` term but
keeps the gatewayHost null-guard — that one is a real fallback for a
domain-less config, not the dead enable branch.
2026-06-17 16:56:26 +02:00
atlas
61db5afc22 nix(c0re): guard agent forge/matrix URLs on hyperhive.enable, not network.enable
Addresses argus's review of #1718: the HIVE_FORGE_URL / HIVE_MATRIX_URL
conditionals still keyed off the now-deprecated `network.enable`, so
setting it to `false` would point agents at host loopback (unreachable
from their private netns) even though isolation stays on — contradicting
the "deprecated and ignored" warning. Guard on the top-level
`hyperhive.enable` instead, so `network.enable` truly has no effect
anywhere and the loopback branch only covers a hyperhive-disabled host.

Eval-proven: with `network.enable = false`, HIVE_FORGE_URL now resolves
to the gateway vhost (`http://forge.<domain>`), and the deprecation
warning still fires.
2026-06-17 16:07:39 +02:00
atlas
78482cb624 nix: remove the non-isolated (shared-netns) mode
Network isolation is validated working end to end (forge + matrix reach
the gateway under private netns), so the shared-host-netns mode is
removed — there is now one mode.

- hive-network.nix: the bridge/DNS block and the isolation overlay are
  now unconditional whenever hyperhive is enabled (gated on
  services.hyperhive.enable, not the per-feature toggles). The redundant
  isolateContainers-implies-enable guard is dropped.
- network.enable and isolateContainers are kept as DEPRECATED no-op
  options so existing configs that set them to true still evaluate
  cleanly; setting either to false now warns (gated on hyperhive being
  enabled, so a non-hyperhive host gets no spurious warning) and has no
  effect. Both are slated for removal in a future release.
- hive-c0re.nix: the HIVE_FORGE_URL / HIVE_MATRIX_URL conditionals drop
  the "&& isolateContainers" clause — agents always reach forge/matrix
  through the gateway vhost now.
- hive-matrix.nix: refresh one stale comment.

The Rust lifecycle is env-driven (HIVE_NETWORK_ISOLATION), so no Rust
change is needed: the env is now always set, so the existing
private-netns path always runs.

Supersedes the default-on flip (the option it would have defaulted is
gone).
2026-06-17 15:29:52 +02:00
damocles
726561f66c harness: assert matrixAccounts tokenFile basenames start with matrix-token (#1702 BE-3) 2026-06-17 15:13:17 +02:00
damocles
f7199f183c drop issue number from source comment (tracker-tag lint) 2026-06-15 21:55:55 +02:00
damocles
354b270d2a matrixAccounts url: single-source-of-truth default binding (addresses review) 2026-06-15 21:48:51 +02:00
damocles
d15ecff6d2 isolation: forward HIVE_MATRIX_URL so matrix daemon reaches the gateway 2026-06-15 21:38:34 +02:00
damocles
8ba0abcf27 matrixAccounts: assert no extra named 'main' (reserved for hive account) 2026-06-15 21:24:16 +02:00
damocles
36fb041c55 matrixAccounts: hive 'main' is implicit primary, option declares extras only 2026-06-15 21:24:16 +02:00
damocles
63db108516 rework matrixAccounts to attrset keyed by name + matrixPrimaryAccount 2026-06-15 21:24:16 +02:00
damocles
dcc059b4b8 feat: hyperhive.matrixAccounts nix option (matrix multi-account layer 2) 2026-06-15 21:24:16 +02:00
atlas
26d81cd36e fix(harness): stop resolvconf/dhcpcd clobbering the bridge DNS resolver
Under network isolation, agents lost DNS resolution of the hive's own
zones (forge.<domain>, matrix.<domain>): the hyperhive-isolated-dns
oneshot points resolv.conf at the bridge resolver, but resolvconf
regenerated it from host-tracking right after (dhcpcd re-triggering that
when the veth comes up), reverting to the non-authoritative host
resolver. Agents then couldn't reach the in-hive forge or matrix through
the gateway, which broke an isolate-by-default rollout.

Take resolvconf and dhcpcd out of the resolv.conf loop: disable
resolvconf and tell dhcpcd not to touch resolv.conf (without disabling
dhcpcd itself, so the veth still gets its address). Then the last writer
owns it -- the nixos-container host-copy in shared netns, or the oneshot
in isolated mode. Mirrors the approach the matrix container already
takes. Eval-checked; flake check passes.
2026-06-15 20:45:20 +02:00
atlas
9902d9d9a5 fix(ci): resolve the forge domain to loopback in the hive-ci runner
Forgejo's Actions artifact API hands the runner an upload URL built from
forgejo's ROOT_URL — the public forge domain (forge.<domain>), not the
runner's 127.0.0.1:<httpPort> registration URL. The hive-ci container shares
host netns but has no resolver entry for the hive's own domains (the
gateway's localHostsEntry only touches the host), so actions/upload-artifact
fails with 'getaddrinfo ENOTFOUND forge.<domain>' while normal CI (checkout
via the localhost registration URL) is unaffected. Add a networking.extraHosts
entry mapping the forge domain to loopback so the upload reaches the local
forge via the gateway.
2026-06-15 13:32:01 +02:00
atlas
bfeb23ce06 fix(forge): pre-create Actions artifact storage dir so uploads persist
Forgejo's local Actions-artifact storage defaults to
/var/lib/forgejo/data/actions_artifacts but Forgejo does not pre-create it.
The artifact endpoint ingests the chunked upload, then the merge-chunks step
fails with 'lstat .../actions_artifacts/tmpNNN: no such file or directory',
so every upload-artifact step dies after a successful build. Pre-create the
dir (forgejo-owned) via tmpfiles. actions.ENABLED already registers the
endpoints; this gives them somewhere to write.
2026-06-15 11:37:33 +02:00
atlas
495146a05c fix(network): order isolated-DNS oneshot before the harness
Follow-up to the isolated-container egress fix. The hyperhive-isolated-dns
oneshot (which rewrites resolv.conf to the bridge resolver) was ordered
before network-online.target + tea-login, but NOT relative to the harness
(hive-ag3nt) or the matrix daemon. hive-ag3nt only declares
`after network.target`, so on first boot its first-turn api.anthropic.com
lookup could race ahead of the resolv.conf rewrite and error (self-heals
next turn, but flaps the first one).

Add hive-ag3nt.service + hive-matrix-daemon.service to the oneshot's
`before` so DNS is fixed before any network consumer starts. The matrix
entry is a harmless no-op when matrix is disabled (unit absent).

Caught by damocles in review of the parent PR.
2026-06-10 21:01:13 +02:00
atlas
d993ad2c47 fix(network): wire default route + bridge DNS for isolated containers
When isolateContainers=true, claude (and all egress) broke in every
container: agents came up with an IP but no way off the bridge subnet.

Two container-side gaps, both confirmed against nixpkgs
nixos-containers.nix:

1. No default route. hive-priv wrote HOST_ADDRESS= empty in the nspawn
   conf. nixos-container's container-side setup only installs
   `ip route add default via $HOST_ADDRESS` when HOST_ADDRESS is
   non-empty, so the container had an address but no gateway -> nothing
   off-subnet (incl. api.anthropic.com) was reachable. Fix: write
   HOST_ADDRESS=<bridge-ip>. In bridge mode the host-side address/route
   setup is skipped, so this only affects the container's default route.

2. No usable resolver. nixos-container copies the host's /etc/resolv.conf
   into the container at every start; the host resolver (e.g. 127.0.0.53)
   is unreachable from a private netns and isn't authoritative for the
   hive's own zones. Fix: hive-priv drops a marker carrying the gateway
   IP only when isolated, and a new harness-base oneshot
   (hyperhive-isolated-dns) rewrites resolv.conf to point at the bridge
   dnsmasq. Inert in shared-netns mode (no marker), so the shared
   container toplevel does the right thing in both modes.

The gateway IP is the address part of HIVE_NETWORK_SUBNET (the bridge IP
verbatim, honouring a non-.1 operator override), via a new validated
bridge_gateway_ip() helper with unit tests.

Unblocks defaulting isolation on.
2026-06-10 20:59:12 +02:00
damocles
0c1c06ad76 docs: drop stale hive-m1nd references (single hive binary) 2026-06-10 19:52:19 +02:00
damocles
8792db9424 feat(#551): gate server-side e2ee behind opt-in matrix.allowEncryption (default off) 2026-06-10 19:12:36 +02:00
damocles
f51402a867 feat(#551): enable matrix e2ee -- add e2e-encryption feature, wire EncryptionSettings, flip tuwunel allow_encryption 2026-06-10 19:12:36 +02:00
atlas
7eb1cef62b fix(#1595): rename effort env to HIVE_DEFAULT_EFFORT
Match the harness reader landed in #1600 (configured_effort reads
HIVE_DEFAULT_EFFORT, mirroring HIVE_DEFAULT_MODEL). Was
HYPERHIVE_EFFORT_LEVEL in the first cut; damocles standardized the
name on the HIVE_DEFAULT_* convention.
2026-06-10 01:26:54 +02:00
atlas
004df7a1c9 feat(#1595): add hyperhive.effortLevel baseline default option
Per-agent enum option (medium|high|xhigh, default medium) rendered into
the HYPERHIVE_EFFORT_LEVEL env var. The harness resolves effort as
operator-override-file -> this env -> medium and passes it to
claude --effort at turn launch (harness read+apply tracked separately).

Same declarative-default + runtime-override shape as hyperhive.model.
Umbrella: operator-controlled claude effort.
2026-06-10 01:26:54 +02:00
atlas
d6b95d22f0 fix(forge): make Forgejo's signing key actually resolve
Forgejo reported "does not have a signing key" on PRs despite the
forgejo-gpg-init service generating one. Two causes, both fixed:

- SIGNING_KEY = "default" resolves through the forgejo process's git
  config (user.signingkey), not by scanning GNUPGHOME — and the keygen
  never set it, so "default" found no key. forgejo-gpg-init now sets the
  forgejo user's git user.signingkey to the generated key (+ commit and
  tag gpgsign), with HOME pinned to the state dir so the global config
  lands where forgejo reads it.
- The keygen guard was stamp-file based, so a partial state wipe that
  lost the key while keeping the stamp would never regenerate. It's now
  keyed on the actual secret key (regenerate iff gpg shows none) and
  runs idempotently before forgejo on each start.

Also drops the heredoc for the gpg params in favour of printf (avoids
nix-string indentation fragility) and corrects the stale comment that
claimed "default" scans GNUPGHOME.
2026-06-09 14:53:04 +02:00
atlas
6734cab382 feat(ci): expose the runner job timeout as a tunable option
The runner hardcoded a 3h per-job timeout. Surface it as
services.hyperhive.forge.ci.jobTimeout so a stuck or runaway job is
bounded by a sane default while staying overridable for operators who
legitimately run longer jobs.

Default drops to 1h (comfortably covers a cold-cache nix build while
bounding a hang far sooner than the old 3h); raise it via the option
for genuinely long jobs. Accepts a Go duration string.

Resolves the stuck-runner concern from the CI-outage follow-up with a
runner-enforced job timeout rather than an external watchdog, per
operator direction.
2026-06-09 14:51:29 +02:00
atlas
eb61660d35 chore(nix): replace tracker tags with prose in nix comments
Part of the tracker-tag cleanup: the hive convention is prose, not
issue-tracker tags, in code. Reword the 21 tags in the nix tree
(flake.nix + the hive-c0re/ci/gateway/network modules) to describe
the thing they pointed at, preserving the context without the tag.

Comment-only — no eval or logic change. Validated with nix fmt
(no reformatting) and nix flake check --no-build (all checks
evaluate clean); the full build check was skipped locally because
the shared remote builder is degraded, so CI will exercise the
build derivations once the runner recovers.
2026-06-09 11:25:56 +02:00
iris
09cb705738 refactor(frontend): move ST4TS to its own /stats.html page (#1464 step 2)
Extracts the hive-wide turn-stats rollup out of the dashboard tab strip
into a standalone /stats.html page, reached from the H0M3 hub — same
minimal-chrome pattern as /flow.html and /logs.html. The dashboard tab
strip is now purely operational.

- new stats.{html,css,js}; stats.js holds the moved render JS and
  fetches /api/stats-hive on load + window change.
- migrate the window selector (#hive-stats-windows) from a bespoke
  data-w/.active toggle to the shared createTabStrip — now hash-routed
  (#1h / #24h / …) and deep-linkable, matching the per-agent /stats page.
- drop the ST4TS tab + pane from dashboard.html and the hive-stats render
  block + the stats->refreshHiveStats lazy-load from tabs.js.
- move the shared .hive-stats-table to common.css (the dashboard SYST3M >
  C0NT41N3R L04D table still uses it); the ST4TS-only window/chip/bar
  styles go to stats.css.
- add a Stats tile to the H0M3 hub (and drop the now-stale "stats" from
  the Dashboard tile desc); wire build.mjs + the nix/frontend.nix manifest.

Second slice of #1464 step 2; follows the /settings.html extraction.
2026-06-09 00:11:43 +02:00
atlas
fdf05c1673 refactor(gateway): make the gateway unconditional — remove gateway.enable
The gateway container starts alongside every hyperhive deployment, so
gating it behind a separate enable flag was a footgun: an operator who
set it false lost the only thing exposed to the outside while the
agent containers kept running. Re-gate the gateway config on the
top-level services.hyperhive.enable instead.

- hive-gateway.nix: drop the gateway.enable mkOption; gate the config
  block on config.services.hyperhive.enable.
- hive-forge.nix: behindGateway now defaults to services.hyperhive.enable;
  remove the behindGateway-requires-gateway assertion (now vacuous).
- hive-network.nix: remove both gateway.enable assertions (vacuous).
- hive-c0re.nix: drop the firewall.allowedTCPPortRanges 8100-8999
  fallback that opened agent ports when the gateway was off (the
  gateway is now the sole entry point); HIVE_GATEWAY_ENABLED is always
  set since the gateway always runs.
- nix/docs/default.nix: remove the gateway.enable = mkForce false stub
  (would be an eval error against the removed option; the gateway is
  already re-gated on hyperhive.enable, which docs force false).
- hive-matrix.nix, dashboard.rs: comment/prose updates only.

BREAKING: operators relying on services.hyperhive.gateway.enable = false
to suppress the gateway must instead point their own reverse proxy at
the gateway's port. NixOS errors clearly on the now-unknown option.
2026-06-09 00:11:10 +02:00
iris
d9c66de069 refactor(frontend): move S3TT1NGS to its own /settings.html page (#1464 step 2)
Extracts the operator-local preferences (browser-notification toggle)
out of the dashboard tab strip into a standalone /settings.html page,
reached from the H0M3 hub — same minimal-chrome pattern as /flow.html
and /logs.html. The dashboard tab strip is now purely operational.

- new settings.{html,css,js}; settings.js binds NOTIF + renders the
  shared server-warnings banner (matching the other standalone pages).
- drop the S3TT1NGS tab + pane from dashboard.html; the NOTIF.bind()
  toggle wiring moves to settings.js. The dashboard keeps NOTIF.show()
  (approvals / questions) — it reads the same browser permission +
  localStorage mute flag the settings page sets, so firing still works.
- move .notif-row / .btn-notif from dashboard.css to settings.css.
- add a Settings tile to the H0M3 hub; wire the new entries into
  build.mjs and update the nix/frontend.nix asset manifest comment.

First slice of #1464 step 2; the ST4TS page extraction follows separately.
2026-06-08 23:44:22 +02:00
atlas
8006dd2809 feat(c0re): extend stylix theming to the gateway-served agent UIs
Builds on the merged dashboard theming: the themed-frontend overlay now
swaps colors.css in both the dashboard/ and agent/ dist subtrees, and the
agent frontend dir (HIVE_AGENT_FRONTEND_DIR, which the gateway serves agent
static files from) points at the themed tree too. So when stylix is enabled
on the host, both the dashboard and the gateway-served agent UIs re-theme
from the host palette — still zero-op auto-detect, still a no-op (both dirs
on the unthemed dist) when stylix isn't imported.

Not covered: an agent reached directly on its own harness web server (no
gateway) serves from its per-agent mergedDist, built in the agent's own
nixosSystem with no host stylix access — that path needs the base16 palette
forwarded host->agent and is tracked separately.
2026-06-08 23:20:11 +02:00
atlas
4471adfa27 feat(c0re): auto-theme the dashboard from stylix when present
When the operator's host config has stylix enabled, generate a base16
colors.css from its palette and overlay it onto the bundled frontend dist,
then serve that themed tree as the dashboard's HIVE_STATIC_DIR. Zero-op
auto-detect — no flake input, no operator action, no npm/esbuild rebuild
(a pure file-copy over the prebuilt dist). colors.css is the whole swap
contract; theme.css derives the semantic vars from the 16 base16 slots.

Guarded access (config.lib.stylix / config.stylix.enable via 'or' fallbacks)
makes it a clean no-op when stylix isn't imported — HIVE_STATIC_DIR stays
on the unthemed dist, which is what every non-stylix deployment + CI gets.

Dashboard surface only for now; the agent surface needs the base16 palette
forwarded host->agent (the per-agent harness builds its own dist) and is a
separate follow-up.
2026-06-08 22:09:01 +02:00
damocles
58b5434466 fix(#946): drop hive-priv self-bind fallback (require socket activation) + clarify child-state rw is intentional 2026-06-08 21:58:12 +02:00
atlas
98660d134a refactor(c0re): pass hive-c0re serve config via a --config file, shrink ExecStart
The systemd ExecStart carried every host-level setting as its own flag —
nine of them, including two escaped JSON blobs (the context-window map and
the model-price table). Collapse them into a single `--config <file>` JSON.

- Reuse the existing HiveEnv as the container-injected config shape (add
  Deserialize + Default), and add a ServeConfig wrapper = flattened HiveEnv
  plus the hive-c0re-local model_prices table (kept out of HiveEnv since it
  is never injected into containers). serde(default) lets any field be
  omitted and fall back to its canonical default.
- clap: add --config; the per-setting flags become optional overrides
  (config file is the base, explicit flags win — preserves hivectl/debug
  ergonomics and bare `hive-c0re serve`).
- Coordinator::open and cmd_serve now take the bundled HiveEnv, which drops
  their too_many_arguments clippy allows. cmd_serve keeps a single
  too_many_lines allow (inherent daemon-boot orchestration, not arg-driven).
- nix: write the config as JSON to the store + pass --config, so ExecStart
  is one short line.
- Add a round-trip test proving the flatten + per-field defaults work.

Closes the ExecStart-length issue.
2026-06-08 21:57:46 +02:00
iris
09787dd1c3 refactor(frontend): base16 theme contract in a swappable colors.css
Split the palette into two standalone stylesheets:
- colors.css — the 16 base16 slots (--base00..--base0F). This is the
  entire theme swap contract; a generator (e.g. a stylix base16 scheme,
  which is natively base00-base0F) replaces only this file.
- theme.css — the semantic layer (--bg, --purple, …) derived from the
  base16 slots via var()/color-mix. Never changes on a swap.

Every page links colors.css then theme.css; theme.css does NOT @import
colors.css (that would re-bake the slots into it) — they're separate
dist outputs so a swap touches just colors.css. Pixel-identical refactor:
base16 defaults are Catppuccin Mocha and the three off-slot vars
(--crust, --muted, --subtext0) derive via color-mix reproducing their
exact prior hexes.

Wires colors.css through both build.mjs CSS entry lists, the
@hive/shared exports map, and all 7 page templates. css-vars.md + the
frontend.nix output-list comment updated.
2026-06-08 21:24:07 +02:00
iris
bd0b3efd8f chore: post-#1442 cleanup — fix stale price example + drop dead CSS
Two small follow-ups after the modelPrices PR (#1442):
- nix/modules/hive-c0re.nix: the `modelPrices` option `example` still
  showed the old 5-minute sonnet `cache_write = 3.75`; the default is now
  the 1-hour TTL `6.0`. Bump the example to match so it doesn't mislead.
- frontend/packages/agent/agent.css: remove the dead `.stats-empty-note`
  selector (no element uses it — the stats empty state paints on canvas).
2026-06-08 20:24:39 +02:00
iris
b066af010b review: use 1-hour cache-TTL prices (the subscription default) 2026-06-08 20:03:47 +02:00