Commit graph hyperhive/nix
Author SHA1 Message Date
damocles
1d0d52b85f rename(162): update manager.nix comments for root 2026-06-01 17:33:09 +02:00
damocles
7772e29ec2 rename(162): hive-m1nd -> hive-root, HIVE_LABEL/PORT for root 2026-06-01 17:33:09 +02:00
damocles
2f25131403 fix(947): strip prose/issue-tags from harness-base.nix 2026-06-01 16:49:41 +02:00
damocles
0ac05f0638 fix(#947): set HIVE_WEB_SOCKET for manager unconditionally 2026-06-01 16:49:41 +02:00
atlas
f8c0f64fd4 feat: socket-activate the hive-c0re admin socket
Add a systemd.sockets.hive-c0re unit that holds /run/hyperhive/host.sock
before hive-c0re starts. hive-c0re serve() detects LISTEN_FDS via the
listenfd crate and accepts the systemd-handed fd instead of calling bind().
Falls back to the existing bind path when LISTEN_FDS is absent so direct
invocation and CI are unaffected.

Benefits: hivectl can connect the moment the socket unit activates (no
racy window), and a hive-c0re restart never drops the socket inode.
2026-06-01 16:29:41 +02:00
iris
188f3ea5ec chore: scrub #NNN issue references from code comments and nix descriptions
Part of the docs-migration chore (issue #708). Remove GitHub issue
numbers from inline comments, option descriptions, and rustdoc —
these are contextless noise for anyone reading the code without
access to the original discussions. Replace with prose that captures
the same rationale directly.

No functional change. Build still clean (cargo check passes).
2026-06-01 13:30:52 +02:00
damocles
89030ff1e1 docs: clarify per-agent user comment in harness-base.nix 2026-06-01 11:21:47 +02:00
atlas
2fd6de7bab fix: address argus review nits — tmpfiles dir comment, drop redundant chmod 2026-06-01 00:18:19 +02:00
atlas
f0bd572b35 fix: correct runner registration ordering — oneshot + tmpfiles
The nixpkgs gitea-actions-runner module uses tokenFile as a systemd
EnvironmentFile, loaded before any ExecStartPre. Our previous
ExecStartPre override was too late — file didn't exist yet.

Fix: tmpfiles pre-creates /run/hive-ci/runner-token with a placeholder
on every boot. A new hive-ci-register.service oneshot (gated on
ConditionPathExists=!/var/lib/gitea-runner/hive/.runner) fetches the
real token and overwrites before gitea-runner-hive.service starts,
wired via After/Wants. On subsequent boots the placeholder is harmless
— nixpkgs register step exits early when .runner already exists.

Closes #918.
2026-06-01 00:13:00 +02:00
atlas
4df65deb20 fix: move gitea-actions-runner package to top-level option
Per-instance package option does not exist in the nixpkgs module.
Package is configured at services.gitea-actions-runner.package.
Fixes build failure on main. Closes #916.
2026-05-31 23:55:49 +02:00
damocles
52cfc3ea1c reshape swarm peers: domain-as-key, certFingerprint field 2026-05-31 23:55:34 +02:00
atlas
a8e8c50a30 refactor: move ci options to services.hyperhive.forge.ci 2026-05-31 23:52:57 +02:00
atlas
45cbf2eded fixup: trim systemPackages to git only
nix flake check pulls rust tools hermetically. curl/jq in preStart
use absolute store paths. nix is part of any NixOS system by default.
git is the only package genuinely needed at runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:44:12 +02:00
atlas
61565e3c3a fixup: drop stale docs/ci.md forward-ref in module comment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:44:12 +02:00
atlas
0fa0e821d9 fixup: stateVersion 26.05, drop ubuntu labels, simplify CI workflow
- stateVersion: 25.11 → 26.05 (match hive-gateway + hive-matrix)
- default labels: drop ubuntu-latest/ubuntu-22.04 aliases — misleading
  since this isn't Ubuntu; hive-ci:host is the correct label
- ci.yml: collapse to single `nix flake check` job — flake checks.* already
  covers formatting (treefmt+rustfmt), cargo test, and clippy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:44:12 +02:00
atlas
bf350df442 fixup: hive-ci auto-registers runner via forge admin API
Removes the manual runnerTokenFile operator step. On first boot the
container fetches a runner registration token from Forgejo's admin
API using hive-c0re's existing admin token
(/var/lib/hyperhive/forge-core-token). A preStart script writes the
token to /run/hive-ci/runner-token; on subsequent boots it writes a
dummy (registered .runner creds take precedence anyway).

Operator bootstrap is now just `services.hyperhive.ci.enable = true`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:44:12 +02:00
atlas
aa7ebbcd3b feat: add hive-ci module — Forgejo Actions runner for CI
Adds `services.hyperhive.ci` NixOS module that spins up a `hive-ci`
nixos-container running `gitea-actions-runner` against the hive-forge
Forgejo instance. Off by default; opt in with `ci.enable = true` after
generating a runner registration token in Forgejo.

Also adds `.forgejo/workflows/ci.yml` with four jobs: nix flake check,
formatting (nix fmt + cargo fmt), cargo test, and cargo clippy. Jobs
target the `hive-ci` runner label.

Container design mirrors hive-forge (shared host netns, non-ephemeral
state, loopback reach to forge). sandbox-fallback = true since nspawn
containers can't create user-namespaces for nix sandbox.

Closes #175.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:44:12 +02:00
atlas
d45b2f0293 chore: scrub issue/PR cookies from gateway + network nix modules and gateway_nginx.rs 2026-05-31 23:09:46 +02:00
damocles
4093f4fdb4 fixup: remove issue tags from code, use plain prose 2026-05-31 23:06:38 +02:00
damocles
348fb3792a feat(#589): swarm peers option + HYPERHIVE_PEERS env wire v0
nix: services.hyperhive.peers attrset-of-submodules option; serialises
to HYPERHIVE_PEERS JSON ([{label,domain}]); forwarded to containers via
FORWARDED_VARS. dashboard.rs: peer_hives: Vec<PeerHiveView> in
StateSnapshot, derived as {name:label, url:"http://domain/"}.
identity.rs: PeerHive struct + peers() accessor for agent-side use.
2026-05-31 23:06:38 +02:00
iris
cce85a6c1b fix(#540): use systemd.globalEnvironment instead of environment.variables
environment.variables writes to /etc/environment (PAM sessions only)
and is not visible to systemd service units. The correct path for
env vars that need to reach all systemd services is
systemd.globalEnvironment (sets DefaultEnvironment in systemd.conf),
which is the pattern established by #608 for HYPERHIVE_STATE_DIR.

Also update the inline comment reference from environment.variables
to systemd.globalEnvironment.
2026-05-31 22:59:46 +02:00
iris
8a97277f20 fix(#540): pin weston socket + inject WAYLAND_DISPLAY globally
Services started by systemd in a gui-enabled container didn't have
WAYLAND_DISPLAY set, so Wayland clients couldn't find the compositor.
libwayland would fall back to a headless display or error out, leaving
apps running invisibly while the VNC session showed a blank weston
desktop (the double-screen problem).

Fix in weston-vnc.nix:
- Pass --socket=wayland-0 to weston so the socket name is
  deterministic (weston normally picks any free wayland-N name).
- Set WAYLAND_DISPLAY=wayland-0 and XDG_RUNTIME_DIR=/run/user/0 as
  global environment.variables gated on hyperhive.gui.enable, so
  every service in the container inherits them automatically.
- Update gui.json to include wayland_display for tooling that reads it.

Update docs/gotchas.md with the rationale and pointer to #540.
2026-05-31 22:59:46 +02:00
atlas
01d7c37af2 gateway: fix nginx reload — trigger from host via systemd-run (#889)
The #872 path-unit approach was silently broken: IN_MOVED_TO from an
atomic rename on the host does not propagate across the nspawn
mount-namespace boundary into the container, so the watcher inside
the gateway container never fired.

Fix: after each agents.conf write, c0re calls
`systemd-run --machine=hive-gateway -- nginx -s reload` from the host.
The reload is best-effort (logged on failure, not fatal).

Remove the now-unused `hive-gateway-agents-conf.path` +
`hive-gateway-nginx-reload.service` from the gateway container config.
Update docs/gateway.md + comments to reflect the host-side approach.
2026-05-31 22:42:52 +02:00
iris
d3ca857659 fix(#888): use gateway forge URL in dashboard links
Dashboard links to the forge were hardcoded as http://<hostname>:3000,
which breaks when the operator accesses the dashboard through
hive-gateway (forge is served at forge.<domain> with no port).

- nix/modules/hive-c0re.nix: inject HIVE_FORGE_PUBLIC_URL when
  forge.behindGateway = true (e.g. http://forge.pr1ma.darkest.space)
- hive-c0re/src/dashboard.rs: expose forge_url: Option<String> in
  StateSnapshot, reading from HIVE_FORGE_PUBLIC_URL
- frontend/packages/dashboard/src/tabs.js: use state.forge_url when
  present; fall back to http://<hostname>:3000 for gateway-off /
  local-dev deploys
2026-05-31 22:04:52 +02:00
iris
c7360cf0bb docs(#727): split docs/web-ui.md into shape / dashboard / agent
docs/web-ui.md (1315 lines) split into three sub-files:
- docs/web-ui/shape.md   — shared SPA skeleton, SSE multiplexing,
  Worker-death self-heal, terminal pane, listener bind, relative
  paths, atomic repaint, side panel
- docs/web-ui/dashboard.md — SW4RM/Y3R/SYST3M/SCH3DUL3S/S3TT1NGS
  tabs, container row, topology tree, selection bar, approval card,
  dashboard endpoints + event channel
- docs/web-ui/agent.md   — header, terminal, composer, inbox, live
  view, slash commands, per-agent endpoints, stats page

docs/web-ui.md replaced with a thin index linking all three.

Section anchors in docs (gateway.md, gotchas.md), Rust doc comments
(hive-ag3nt/src/web_ui.rs), and nix/templates/weston-vnc.nix updated
to point at the correct sub-file. README and CLAUDE.md file-map
updated with sub-file links. Inline // comments in frontend source
left unchanged (they reference the index which redirects to the right
sub-file).
2026-05-31 21:37:04 +02:00
atlas
9eb8012c9b gateway: scope bind-mount to gateway/ subdir, scrub #869 cookie (argus 🟡)
- gateway_nginx.rs: HOST_CONF_PATH → /var/lib/hyperhive/gateway/agents.conf
- hive-gateway.nix: hostPath = /var/lib/hyperhive/gateway (not whole parent
  dir — avoids exposing forge tokens or other credentials to the gateway
  container)
- tmpfiles: add /var/lib/hyperhive/gateway/ dir rule + seed agents.conf there
- scrub "(#869)" from hive-gateway-nginx-reload service description
2026-05-31 20:29:56 +02:00
atlas
07434e8f50 gateway: hot-reload agents.conf at runtime (#869)
Replace eval-time per-agent nginx location baking with a runtime
include file. c0re writes /var/lib/hyperhive/agents.conf (nginx
location blocks, UDS or TCP per agent) on every topology change and
on the 10s marker poll. The gateway container bind-mounts
/var/lib/hyperhive/ at /run/hive-state/ and nginx includes
/run/hive-state/agents.conf. A systemd path unit inside the container
watches the file for changes and fires `nginx -s reload` on each
atomic rename from c0re — no nixos-rebuild switch needed when agents
start, stop, or flip useUnixSocket.

  - new hive-c0re/src/gateway_nginx.rs: write() + render()
  - lib.rs + meta.rs + agent_sockets::spawn_poll: hook in write()
  - hive-gateway.nix: drop agentPortsTable/agentSocketsTable/
    agentUpstreamFor/lib.mapAttrs', add /run/hive-state bind-mount,
    include directive, systemd path unit + reload service, tmpfiles
    for /var/lib/hyperhive + agents.conf seed
  - docs/gateway.md: update vhost table + Per-agent UDS section
2026-05-31 20:29:56 +02:00
müde
adf89a1f25 hive-gateway: chown key.pem root:nginx 0640 for pre-start nginx -t
nginx-pre-start runs the config test as the nginx user; a 0600
root-owned key fails that check with BIO_new_file Permission denied
even though the master process would later load it as root.
2026-05-31 19:50:43 +02:00
müde
d10f7d4c13 hive-gateway: chmod cert parent dir so nginx worker can traverse
Parent /var/lib/hive-gateway came out 0700, blocking the nginx-user
worker from reaching the 0755 tls/ subdir and surfacing as a generic
cert-load failure at nginx start.
2026-05-31 19:44:16 +02:00
damocles
80dd4babd4 hive-gateway: also gate cert gen on key existence (argus 🟡 on #865) 2026-05-31 17:55:20 +02:00
damocles
0aa0e5b95a hive-gateway: idempotent cert oneshot, always-run + parse check (#856 follow-up) 2026-05-31 17:55:20 +02:00
damocles
50a1eb41cf hive-gateway: nginx Requires= cert oneshot (fixes #856 from #848) 2026-05-31 17:34:23 +02:00
atlas
604146992a nix/hive-c0re: trim duplicate identity + flag prose (#718 batch 7)
Three blocks in `nix/modules/hive-c0re.nix` duplicated content that
already exists in extracted docs since iris's #717 batch (identity
section) and earlier #718 batches landed:

- `services.hyperhive.domain` option intro — collapsed to a short
  purpose statement + pointer to
  `docs/conventions.md::Hive identity (label + domain + display names)`
  (iris's section covering the full env-var propagation chain).
- `hiveName` / `swarmName` option intros (display names) — same.
- `HYPERHIVE_HIVE_DOMAIN` / `HIVE_NAME` / `SWARM_NAME` env-var
  injection comments (three near-identical blocks) — collapsed to
  a single shared pointer block + dropped the per-var redundant
  explanation.
- `HIVE_MATRIX_GUI_ENABLED` + `HIVE_GATEWAY_ENABLED` flag comments
  — tightened to one-line purpose statements; the gateway routing
  detail already lives in `docs/gateway.md::Vhost map`.
- Dropped the trailing "Matrix GUI static serving lives entirely
  on the gateway" comment block — duplicates docs/gateway.md
  content.

`description = ''…''` blocks (operator-facing options docs)
preserved per iris #718 unchanged.

Net: ~30 lines removed from hive-c0re.nix, no docs additions
needed — extracted prose already exists from prior batches.

`nix flake check` clean.
2026-05-31 17:25:14 +02:00
damocles
c7777f3d58 hive-gateway: hoist publicScheme/Port helpers to outer let (argus 🟡 on #848) 2026-05-31 17:17:58 +02:00
damocles
314f1774d8 hive-gateway: self-signed TLS for matrix-client well-known fetch (closes #837) 2026-05-31 17:17:58 +02:00
iris
fbc41d42a6 dashboard: build same-origin /agent/<name>/ links when gateway is up (closes #842)
When `services.hyperhive.gateway.enable` is on (default), the c0re
NixOS module now sets `HIVE_GATEWAY_ENABLED=1` on the service env.
`/api/state` exposes the flag as `gateway_enabled`; the SW4RM tab's
container-row renderer flips three link sites (primary agent-name
link, favicon fetch, `container`-kind nav-strip links) from the
legacy `http://<host>:<port>/` direct TCP shape to same-origin
`/agent/<name>/` URLs — the gateway proxies them to the per-agent
harness via `agent-ports.json` or `agent-sockets.json` (#784 / #815).
Gateway-off deploys keep the direct TCP fallback so local-dev /
operator opt-out keeps working.

`forge`-kind nav-strip links still resolve against `:3000` (separate
sub-domain transition, tracked by `forge.behindGateway`);
`external`-kind links are already absolute.

Mirrors the `HIVE_MATRIX_GUI_ENABLED` env→snapshot-flag pattern.
Docs updated: `docs/web-ui.md::Container row` + new
`docs/gateway.md::Dashboard link shape` section.
2026-05-31 17:16:53 +02:00
atlas
b50f182396 hive-gateway: note common-case dnsmasq address redundancy (argus 🟡 on #845)
forge/matrix subdomain address rules are redundant when those are
sub-domains of hyperhive.domain (dnsmasq's /<domain>/ matches
sub-domains). Keep explicit for the cross-domain case (e.g.
forge.domain = "git.example.com") + add a comment explaining
the trade-off.
2026-05-31 16:56:59 +02:00
atlas
ed3b9d853e nix/hive-network: bridge + dnsmasq resolver, opt-in (#805 v1)
Stand up the host-side bridge interface + per-agent DNS resolver
ahead of #14 (netns isolation). Mara on #805#11541: "we need it
before #14 so nothing breaks when we switch over". v1 ships the
endpoint live but containers stay on shared host netns — when #14
flips them to private netns the DNS contract is already there.

Shape:

- new `nix/modules/hive-network.nix` with `services.hyperhive.network.*`
  options (enable + bridgeName + bridgeIp + bridgePrefixLength +
  upstreamDns). Default off. Imported from `hive-c0re.nix`.
- bridge interface via `networking.bridges` (no slave NICs at v1;
  per-agent veth pairs attach once #14 lands).
- bridge IP assigned via `networking.interfaces`.
- `networking.firewall.interfaces.<bridge>.allowed{UDP,TCP}Ports =
  [ 53 ]` opens the resolver on the bridge interface only —
  other interfaces stay closed.
- dnsmasq config added to the existing `hive-gateway` container
  (mara on #805:10957: "put the resolver into the gateway container").
  Listens only on `bridgeName` + `lo`; authoritative for
  `<hive-domain>`, `forge.<hive>`, `matrix.<hive>` answering with
  the bridge IP; forwards everything else to upstream.
  `resolveLocalQueries = false` keeps the gateway container's own
  resolver untouched.

Asserts `services.hyperhive.domain != null` + `gateway.enable =
true` — both required for the resolver to be meaningful.

Docs: new `docs/network.md` covering v1 vs v2 split, container shape
rationale, default addressing, resolver behaviour, firewall posture.

`nix flake check` clean.
2026-05-31 16:56:59 +02:00
atlas
3958079a8e harness-base: pin hive-dashboard-links doc ref to section anchor (argus 🟡 on #823) 2026-05-31 16:14:38 +02:00
atlas
a043c61828 docs: extract best-effort oneshot service contract + matrix-avatar (#718 batch 6)
Two new sections housing rationale that was inline in
`harness-base.nix`:

- `docs/conventions.md::Best-effort oneshot services` — shape
  contract shared by `tea-login`, `forge-avatar-sync`, and
  `matrix-avatar-sync`: always exit 0, no `set -e`, skip silently
  on missing prerequisites, wired to multi-user.target,
  re-runnable. Plus the artefact-under-agent-home + service-stays-
  root posture and the operator-visible-via-journalctl trade-off.

- `docs/persistence.md::matrix-avatar-sync` — the two-step `media
  upload` → `set avatar_url` matrix-spec dance + why
  `RemainAfterExit = false` (so the `.path` watcher's re-fire on
  token appearance actually re-executes the unit).

In-code comments trim to one-liner purpose + pointers; the script
bodies stay (they're the actual implementation) but their inline
`#` rationale comments collapse where the docs cover them.

`description = ''…''` blocks (operator-facing options docs)
preserved per iris #718.

`nix flake check` clean; `nix fmt` clean.
2026-05-31 16:14:38 +02:00
atlas
e1bc9e42f1 hive-gateway: tmpfiles rule for /run/hive-agent (argus 🟡 on #829)
Defensive against the fresh-boot-before-any-agent-spawn window where
the bind-mount source wouldn't exist from c0re's per-agent
`set_nspawn_flags` mkdir chain yet. nspawn auto-creates missing
sources, so this is intent-explicit rather than functional fix.
2026-05-31 16:14:02 +02:00
atlas
3a29aee001 nix/hive-gateway: UDS upstream for /agent/<name>/ (#784 phase 2 step 3)
Switch per-agent gateway upstreams from TCP loopback to unix-domain
socket when the agent has opted in via `hyperhive.web.useUnixSocket`
(#822). Coexists with the TCP path during rollout.

Changes:

- New `agentSocketsFile` option (default
  `/var/lib/hyperhive/agent-sockets.json`) — c0re writes the map
  there via `hive_c0re::agent_sockets::write` (#809).
- `agentSocketsTable = lib.importJSON ...` (graceful empty when
  file missing).
- `agentUpstreamFor name port` picks `http://unix:<path>:/` when the
  socket has a JSON entry AND the file exists at eval time; else
  `http://127.0.0.1:<port>/`. Path-exists gate guards against
  c0re's blanket-emit shape during the canary window (agents in
  `agent-sockets.json` who haven't actually flipped have no
  bound socket on disk → fall back to TCP). Damocles will ship a
  `.bound` marker filter on the c0re side (#784 step 2d
  follow-up); once that's in, the path-exists check is redundant
  but harmless. Step 4 drops it entirely along with the TCP
  fallback.
- `containers.hive-gateway.bindMounts."/run/hive-agent"` —
  read-only, unconditional. Inert when no agents have opted in.
  Required so nginx inside the gateway container can `connect(2)`
  to the per-agent sockets damocles's #813 bind-mounts into agent
  containers at the same paths.

Docs:

- `docs/gateway.md::Per-agent UDS upstream (#784)` — full rollout
  flow, subdir-bind rationale (damocles #813), eval-time gate
  explainer, step 4 drop plan.

`nix flake check` clean; `nix fmt` clean.

Canary plan: once #822 (`useUnixSocket` option) lands + this PR
merges, manager flips atlas's agent.nix to `useUnixSocket = true`
via the config-update flow. End-to-end validation against atlas
before broader rollout.
2026-05-31 16:14:02 +02:00
damocles
e04b6075e5 harness-base: hyperhive.web.useUnixSocket option to flip HIVE_WEB_SOCKET (#815)
closes #815. last harness-side piece of the #784 phase 2 rollout.

new option `hyperhive.web.useUnixSocket` (default false). When true,
the harness service env gets HIVE_WEB_SOCKET set to the canonical
/run/hive-agent/${userName}/web.sock path — making web_ui::serve
bind a UnixListener (PR #800) instead of TCP. Path matches
hive_c0re::agent_sockets::socket_path_for(name) so the c0re
bind-mount (#813) and the gateway's eventual upstream config all
derive from the same canonical shape (no triangulation drift).

Default false so an agent's web UI keeps binding TCP until the
per-agent flip is explicit. Rollout shape:
1. flip one canary agent (atlas volunteered) to true via agent.nix
2. validate atlas's gateway-side step 3 against that canary
3. flip remaining agents per-agent as the gateway side soaks
4. eventually drop this option once everyone's on unix (step 4 of #784)

Sub-agent-only by design — manager UI serves at / via the c0re
dashboard upstream, never via /agent/<name>/, so the per-agent
unix path is irrelevant for it (the env var is set unconditionally
for code simplicity; the manager's bind socket would just sit
unused).
2026-05-31 16:09:31 +02:00
atlas
8a50f36c0c docs/agent-hierarchy.md: extract harness systemd unit shape (#718 batch 4)
Move the harness systemd unit rationale (role-driven unit name,
manager-only forge defaults, PATH wrapper-dir trick, env vars,
standalone-eval fallbacks, RuntimeDirectory + User= reasoning)
from `nix/templates/harness-base.nix` to a new
`docs/agent-hierarchy.md::Harness systemd unit shape (per-role)`
section.

In-code comments trim to short purpose statements + pointers; the
PATH /bin auto-append behaviour is already documented in
docs/gotchas.md, so the harness file just cross-refs both.

`description = ''…''` blocks (operator-facing options docs)
preserved per iris #718.

`nix flake check` clean; `nix fmt` clean (after formatter pass).
2026-05-31 15:44:41 +02:00
atlas
a8d8159038 docs/matrix.md: extract hive-matrix prose (#718 batch 5)
New top-level matrix doc covering everything that doesn't fit
elsewhere:

- Container shape (nixos-container, shared host netns, name choice,
  state persistence) — sibling to gateway.md::hive-forge container shape.
- Identity vs API listener: serverName vs gatewayHost split with the
  #660 breaking change.
- Default-closed firewall + federation port 8448 caveat.
- Provisioning flow: registration token activation, bind-mount,
  LoadCredential, hive-c0re's per-agent register + access_token
  persistence. Captures #565 first-boot race + #644 / iris 8043
  ownership shape.
- Assertion rationale (serverName, gatewayHost == "").
- fluffychat-web build fixes (#685): Imaging.{js,wasm} emscripten
  derivation + dart compile worker fixup, build-CWD path lesson
  from #685 / #733.
- Sequencing history.

In-code # comments trim to short purpose statements + docs pointers.
description = '' blocks (operator-facing options docs) preserved per
iris #718. ~140 lines removed from hive-matrix.nix.

`nix flake check` clean; `nix fmt` clean.
2026-05-31 15:38:43 +02:00
atlas
db2a48cde6 docs/gotchas.md: extract nix/{assets,docs,templates/weston-vnc} prose (#718 batch 3)
- assets.nix: cargo-cache-invalidation rationale → "Split asset
  derivations away from the rust workspace" section.
- templates/weston-vnc.nix: port allocation, weston bind-address
  quirk, PAM service name, Type=simple choice, idle-time=0 →
  "Weston VNC compositor (per-agent hyperhive.gui.enable)" section.
- docs/default.nix: rendering pipeline + subtree-pick + output-tree
  history → "Nix options reference" section.

In-code comments trimmed to short purpose statements + docs pointers.
description = '' blocks (operator-facing options docs) preserved per
iris #718.

`nix flake check` + `nix build .#docs` clean.
2026-05-31 15:24:39 +02:00
atlas
24775845a3 nix/hive-gateway: static not-found + unreachable pages for /agent/<name>/ (#755)
mara on #755: "e.g. /agent/name should show an error page stating
that the agent could not be found if missing in json or that it is
not reachable if we get a connection error. we dont want a fully
generic fallback, only for routes already special cased in the
nginx config."

Adds two static HTML pages built at deploy time via
`pkgs.runCommand "hyperhive-agent-error-pages"`:

- **not-found.html** — served when `/agent/<unknown>/...` hits the
  bare `/agent/` catch-all. The catch-all `return 404`s, and
  `error_page 404 = /__hive_agent_not_found` rewrites to the static
  page.
- **unreachable.html** — served when `/agent/<known>/...` proxy_pass
  to the harness returns 502 / 503 / 504. `proxy_intercept_errors
  on` + `error_page 502 503 504 = /__hive_agent_unreachable` on each
  per-agent location block rewrites to the static page.

Mechanics:

- `agentErrorPagesDir` (in the `let` block) is a `runCommand` that
  emits two HTML files using a `<<EOF` heredoc — no template engine
  needed.
- Two `internal` nginx locations (`= /__hive_agent_not_found`,
  `= /__hive_agent_unreachable`) `alias` the exact files. `internal`
  keeps the URIs unreachable from direct operator request — only
  nginx's own error-handling can hit them.
- Per-agent location blocks pick up the `error_page` directive
  through the existing `lib.mapAttrs'` over `agentPortsTable`. No
  per-agent generated content; same static page for all.
- `/agent/` catch-all generates from a tiny optionalAttrs alongside
  the per-agent block — both are no-op when the agent table is
  empty (matches the pre-#15 shape).

Pages: minimal inline CSS, catppuccin palette matching the
dashboard (`#1e1e2e` bg, `#cdd6f4` text, `#cba6f7` not-found heading,
`#f9e2af` unreachable heading). No frontend-dist dependency — render
even when hive-c0re is down. Both link back to `/`.

Per mara's "only for routes already special cased" — scope stays
narrow. Forge / matrix / fluffychat keep nginx defaults; extending
the custom-error pattern to other vhosts is a separate follow-up
if/when needed.

Verified:
- nginx location attrset has `["/", "/agent/", "= /__hive_agent_not_found", "= /__hive_agent_unreachable"]`
- container toplevel builds clean (`nixos-system-hive-gateway-26.05pre-git`)
- `docs/gateway.md::Per-agent error pages` section captures the
  design + rationale + intentional narrowness

Closes #755.
2026-05-31 15:04:54 +02:00
atlas
ea90814809 docs/gateway.md: extract hive-c0re + hive-forge prose blocks (#718 batch 2)
Continues #718 docs-extraction. Three more blocks moved to
`docs/gateway.md` (which already houses the gateway architecture
story from #775):

1. **Firewall posture (gateway on vs off)** — was a 22-line block
   above `networking.firewall = lib.mkIf ...` in hive-c0re.nix.
   Trimmed to 3-line ref. New `docs/gateway.md::Firewall posture
   (host-level)` section covers the gateway-on / gateway-off
   trade-off + why dashboard port stays loopback-only.

2. **`HIVE_FORGE_URL` loopback rationale** — was a 14-line block
   above the env-var assignment. Trimmed to 5-line ref. New
   `docs/gateway.md::HIVE_FORGE_URL: loopback for in-cluster,
   sub-domain for the operator` section covers the in-cluster vs
   external split + why agent containers can't use the sub-domain.

3. **hive-forge container shape** — was a 15-line top-of-`config`
   block in hive-forge.nix explaining the nixos-container + host
   netns choices. Trimmed to 4-line ref. New
   `docs/gateway.md::hive-forge container shape` section captures
   the same content with state-dir + wipe-via-destroy notes.

Net: hive-c0re.nix -29 lines, hive-forge.nix -11 lines, gateway.md
+44 lines. Same pattern as #782 (first pass) per iris's #10114
guidance — substantive WHY moves to docs as named sub-paragraphs,
in-code shrinks to `// see docs/<file>::<section>` refs.

Verified: `nix eval` on agent-base toplevel still resolves
cleanly; firewall posture unchanged (still 0 ports opened in the
gateway-on case + the same 8100..8999 range in the gateway-off
case).

Continues #718. Follow-up batches: remaining harness-base.nix
blocks, nix/docs/default.nix, nix/assets.nix, nix/templates/weston-vnc.nix.
2026-05-31 14:57:50 +02:00
damocles
ea5f70629c harness-base: generic bash-env.sh + _bashEnvFragments accumulator (mara on #779)
mara: 'if we replace it with one thing, that should be named more
generic so we dont have to change it for future additions'.

extract the BASH_ENV plumbing into a shared shape:

- new internal option `hyperhive._bashEnvFragments` (types.lines)
  accumulates shell snippets across feature modules.
- file path is now `/etc/hyperhive/bash-env.sh` (was the
  cargo-specific bash-cargo-short.sh).
- the file + BASH_ENV + interactiveShellInit are gated on
  `_bashEnvFragments != """ so a fully feature-disabled agent has
  no overhead.

cargo function moves to a `lib.mkIf cargo.shortMessages` contribution
to `_bashEnvFragments` — same behaviour, no rename when the next
hook (nix-env helper, claude-cmd helpers, whatever) lands.
2026-05-31 14:46:29 +02:00
damocles
5f61528133 harness-base: cargo --message-format short by default (#777)
closes #777. saves tokens by collapsing per-crate progress lines into
warning/error summaries when claude (or the operator) runs cargo
inside an agent container.

implementation: /etc/hyperhive/bash-cargo-short.sh defines a 'cargo'
bash function that injects '--message-format short' on compile
subcommands (build/check/clippy/test/run/doc/bench/install/rustc/fix).
loaded via BASH_ENV in non-interactive shells (claude's Bash tool
runs 'bash -c') and via programs.bash.interactiveShellInit in
interactive shells (operator SSH inside the container).

handles the '+toolchain' selector (cargo +nightly build), skips
injection when the caller already passes --message-format (any
form), leaves third-party cargo-* subcommands alone.

new option: hyperhive.cargo.shortMessages (default true) — agents
that parse cargo json output should set false.
2026-05-31 14:46:29 +02:00