Commit graph hyperhive/nix/templates
Author SHA1 Message Date
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
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
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
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
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
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
atlas
309879dba0 docs: extract 3 substantive harness-base.nix prose blocks (#718, first pass)
iris's #718 scope: move substantive design context from `#` comment
blocks in `nix/` to corresponding `docs/` files, leave short
references in code. iris handed it back to me on #10114 since
nix/ is my lane + #775 established the pattern.

First pass — three highest-density blocks in harness-base.nix:

1. **First-boot agent-user migration** (~70 lines → `~20 lines code +
   short ref` in the activation script). Substantive prose moves to
   new `docs/persistence.md::First-boot agent-user migration (post-#658)`
   section explaining the 4 steps the script performs + the eventual
   removability of the marker-guarded body.

2. **nix-daemon `sandbox-fallback = true`** (10-line block → 5-line
   ref). New `docs/gotchas.md::Containerized nix-daemon needs
   sandbox-fallback = true` section covers the user-namespaces
   rationale + nixpkgs-default override.

3. **Matrix daemon + token-arrival trigger** (~50 lines across two
   systemd units → ~10 lines code + short refs). New
   `docs/persistence.md::Matrix per-agent daemon + token-arrival
   trigger` covers the socket-path rationale, the runtime-dir
   ownership story, and the first-boot ordering pattern.

Net: harness-base.nix -84 lines, docs +74 lines. Substantive design
context moves to durable docs; in-code refs follow iris's pattern
from her #712 batches (`see docs/<file>::<section>`).

Follow-ups: hive-c0re.nix, hive-forge.nix, hive-matrix.nix (already
trimmed via #775 but a couple of remaining blocks could go), and
the smaller files in #718's scope table. Shipping this first to get
the pattern reviewed before larger batches.

Verified: `nix eval` on agent-base toplevel still resolves.
2026-05-31 14:44:12 +02:00
damocles
4526e40a49 lifecycle: drop manager port special case (#753) — manager hashes into 8100..8999 like every other agent 2026-05-31 13:25:13 +02:00
iris
b714ba15c2 harness: drop trailing /bin from systemd path entries so wrapper sudo resolves (#672 fixup)
systemd.services.<name>.path appends /bin to each entry, so the
literal '/run/wrappers/bin' here was being expanded to
'/run/wrappers/bin/bin' inside the unit's PATH — a path that
doesn't exist. 'which sudo' then fell back to
'/run/current-system/sw/bin/sudo' (the non-setuid nix-store binary)
and refused with 'must be owned by uid 0 and have the setuid bit
set' on every agent, despite hyperhive.user.passwordlessSudo = true.

Verified on this container post-rebuild:
  PATH includes /run/wrappers/bin/bin (non-existent)
  /run/wrappers/bin/sudo exists with mode r-s--x--x (real setuid)
  but `sudo` resolves to /run/current-system/sw/bin/sudo and fails.

Fix: drop the trailing /bin from both entries. systemd appends it.

The /run/current-system/sw entry was already correctly
expanding to /run/current-system/sw/bin (because of the same
auto-append), which is why everything else on PATH worked despite
the broken wrappers entry — only sudo (the one binary that needs
the wrapper dir) was affected.
2026-05-31 11:29:18 +02:00
damocles
fcb5fae345 docs: catch up post-#658/#604/#660 + add operator hivectl section (#124) 2026-05-31 10:13:33 +02:00
damocles
dcaf1838e1 harness: unify hive-ag3nt + hive-m1nd into one binary picking role from HIVE_ROLE (#598) 2026-05-31 03:21:06 +02:00
atlas
d23fd8847d nix/templates: actually collapse agent-base + manager to role shims (#671 fixup)
The merge of #676 (commit 0951cd1) landed the role-driven harness service
in `harness-base.nix` but the rebase resolution accidentally kept the
legacy `systemd.services.hive-ag3nt` / `hive-m1nd` blocks in
agent-base.nix and manager.nix. Module merging silently accepts the
duplicate definitions because they evaluate to identical attrs — but
the whole point of #671 was to single-source the systemd unit + manager
forge defaults.

Collapses both templates to bare role-setters as originally intended:

    { ... }: {
      imports = [ ./harness-base.nix ];
      hyperhive.role = "agent";  # or "manager"
    }

Verified post-collapse:
- `nixosConfigurations.agent-base.config.systemd.services.hive-ag3nt
  .serviceConfig.ExecStart` -> `.../bin/hive-ag3nt serve`
- `nixosConfigurations.manager.config.systemd.services.hive-m1nd
  .serviceConfig.ExecStart` -> `.../bin/hive-m1nd serve`
- `agent-base` `.path` is `[ /run/wrappers/bin /run/current-system/sw ... ]`
- `manager` `.environment.HIVE_PORT` is `"8000"`

Follow-up to #671 (#676). No behaviour change — the duplicate
definitions were merging to the same values; this just deletes the
redundant copies so `harness-base.nix` is the true single source.
2026-05-31 00:07:55 +02:00
atlas
2e9c50ecc7 nix/harness-base: prepend /run/wrappers/bin to PATH (argus #676 / #672 fixup)
argus on #676 🔴: this PR deletes agent-base.nix + manager.nix and
moves the harness service to harness-base.nix without carrying
forward damocles's #672 fix (which adds `/run/wrappers/bin` to the
service PATH so the setuid sudo wrapper resolves before the bare
nix-store binary).

Pull the #672 fix forward: prepend `/run/wrappers/bin` to the unified
harness service's path list. Same shape as damocles's diff on
agent-base + manager, but applied once in harness-base.nix.

Without this, post-#658 `sudo` inside the container resolves to the
un-setuid nix-store binary and refuses with "must be owned by uid 0
and have the setuid bit set" even when
`hyperhive.user.passwordlessSudo = true` is configured.

Verified via `nix eval`:
- agent-base.systemd.services.hive-ag3nt.path[0] = "/run/wrappers/bin" ✓
- manager.systemd.services.hive-m1nd.path[0]    = "/run/wrappers/bin" ✓

#672 (damocles) supersedes when this lands — the two changes are
equivalent and the consolidated harness-base.nix is now the canonical
home for the fix.
2026-05-30 23:41:13 +02:00
atlas
0951cd1b3d nix/templates: merge manager + agent harness into harness-base.nix (#671)
mara on #671: "manager should not be as special anymore."

Single `harness-base.nix` now declares the harness systemd unit + the
manager-only forge defaults, driven by a new `hyperhive.role` option
(`"agent"` | `"manager"`, default `"agent"`). The two child templates
collapse to thin role-setters.

Mechanics:
- `hyperhive.role = "agent"` → `systemd.services.hive-ag3nt` running
  `hive-ag3nt serve`, default forge notification surface.
- `hyperhive.role = "manager"` → `systemd.services.hive-m1nd` running
  `hive-m1nd serve`, forge `keepSubscriptions = false` +
  `skipNotifyReasons = [ "subscribed" "participating" ]` (mentions-
  only inbox), plus standalone-eval fallbacks `HIVE_PORT = "8000"` +
  `HIVE_LABEL = "hm1nd"` (meta.rs overrides via the generated
  `applied/hm1nd/flake.nix`).

`agent-base.nix` (62 → 9 lines) and `manager.nix` (79 → 18 lines) are
now thin shims that just set the role and import `harness-base.nix`.

External surface unchanged: `nixosModules.{agent-base, manager}` +
`nixosConfigurations.{agent-base, manager}` still resolve identically.
meta.rs's role selection (`if isManager then hyperhive.nixosConfigurations.manager
else hyperhive.nixosConfigurations.agent-base`) keeps working without
edits.

Verified via `nix eval`:
- agent-base: role="agent", services=["hive-ag3nt"], forge.keepSubscriptions=true
- manager:    role="manager", services=["hive-m1nd"], forge.keepSubscriptions=false,
              forge.skipNotifyReasons=["subscribed","participating"],
              ExecStart=hive-m1nd/bin

Closes #671.
2026-05-30 23:41:13 +02:00
damocles
c73c8389ec harness: prepend /run/wrappers/bin to service path so sudo wrapper resolves (#658 fixup) 2026-05-30 23:40:16 +02:00
müde
b8647cf7dc harness: write claude configs to systemd RuntimeDirectory + chown ~/.claude on activation (#658 fixup) 2026-05-30 22:57:26 +02:00
müde
113e64e481 nix/harness: recursive chown of /run/hive (stale root-owned files survive container restart) 2026-05-30 22:19:22 +02:00
müde
de3f541729 nix/harness: ExecStartPre chown /run/hive to agent user (#658 fixup) 2026-05-30 22:14:32 +02:00
müde
ed046787e0 nix/harness: chown /run/hive to agent user (#658 fixup) 2026-05-30 22:08:06 +02:00
damocles
6b6c6775ee agents: drop root, run as per-agent unix user with passwordless sudo (#658) 2026-05-30 21:45:09 +02:00
atlas
3b500bba1b nix: pivot to services.hyperhive.* per mara directive (#612)
Per [mara on PR #615 comment 7349](http://localhost:3000/hyperhive/hyperhive/pulls/615#issuecomment-7349):
> follow nix conventions, services.hyperhive it is. the earlier we
> change this, the less breakage.

Renames the entire host-side option tree under `services.hyperhive.*`:

- `services.hive-c0re.*` → `services.hyperhive.c0re.*`
- `hyperhive.enable` → `services.hyperhive.enable`
- `hyperhive.domain` → `services.hyperhive.domain`
- `hyperhive.forge.*` → `services.hyperhive.forge.*`
- `hyperhive.matrix.*` → `services.hyperhive.matrix.*`

Per mara's "earlier = less breakage", the previous `services.hive-c0re.enable`
deprecation alias is dropped. Operators get a clear eval error on the
old paths pointing at the rename. Single migration moment.

Per-agent options in `nix/templates/harness-base.nix` (`hyperhive.model`,
`hyperhive.allowedRecipients`, etc.) stay at `hyperhive.*` — they're
container-level config, not services in the NixOS sense.

Verified via `nix flake check --no-build` + an end-to-end NixOS eval
exercising every renamed path.

Follow-up needed: rust source comments referencing the old NixOS
option names (`hive-c0re/src/{meta,coordinator,main,dashboard}.rs`)
should be updated in a separate pure-rust PR to keep this one
strictly nix-only.
2026-05-30 11:07:57 +02:00
atlas
32148179e6 refactor: move hive-c0re options to hyperhive namespace (#612)
- Move options.services.hive-c0re → options.hyperhive.c0re
- Add options.hyperhive.enable to auto-enable c0re + subsystems
- Add deprecation alias for services.hive-c0re.enable (backward compat)
- Update doc references in README, flake.nix, docs, harness-base.nix
- Simplifies config: 'hyperhive.enable = true' now enables everything

Existing operator configs using services.hive-c0re.enable will
continue to work but emit a deprecation warning. Aligns the option
namespace with the existing hyperhive.* family (matrix, forge, domain).

fixes #612
2026-05-30 11:07:57 +02:00
damocles
dc99e64b2d drop legacy /state mount for manager (#604) 2026-05-29 21:21:44 +02:00
damocles
30c9eed562 matrix-mcp: drop dual-line PathExists, trim watcher comments (mara nag) 2026-05-29 20:51:01 +02:00
damocles
688058c429 matrix-mcp: reframe state-mount comments as #604 migration fallback (mara nag) 2026-05-29 20:51:01 +02:00
damocles
b4bcd3da05 matrix-mcp: copy state-mount comment to hive-matrix-daemon.path (iris #603 suggestion) 2026-05-29 20:51:01 +02:00
damocles
e6c53045ad matrix: hive-matrix-mcp crate (daemon+stdio bridge) + harness wiring (#548 phase 3) 2026-05-29 20:51:01 +02:00
damocles
558511827c harness-base: systemd.paths trigger for matrix-avatar-sync (closes #571) 2026-05-29 16:35:33 +02:00
müde
c53640040a fix agent crash on start 2026-05-29 16:19:46 +02:00
damocles
7e041e6079 harness-base: matrix-avatar-sync oneshot mirroring forge avatar (#548 phase 2.5) 2026-05-29 13:18:23 +02:00
iris
73684fb00a rust+nix: load static assets at runtime, drop build.rs (#555)
Cuts every `include_bytes!`/`include_str!` of a non-rust path in
the workspace over to runtime file loads from `$HIVE_ASSETS_DIR`
(the `hyperhive-assets` derivation introduced in the previous
commit). After this commit the rust derivation has no compile-time
dependency on `branding/*` or `hive-ag3nt/prompts/*` anymore.

Call-site flips:

- `hive-c0re/src/forge.rs::CORE_AVATAR_PNG` /
  `CONFIG_ORG_AVATAR_PNG`: were `include_bytes!` of
  `branding/hyperhive.png` and `$OUT_DIR/agent-configs.png`. Now
  `ensure_core_avatar` / `ensure_config_org_avatar` `tokio::fs::read`
  via `hive_sh4re::assets::{core_avatar_png, config_org_avatar_png}`
  at startup. The `agent-configs.png` is now rendered by the
  `hyperhive-assets` derivation's rsvg-convert step (was
  `hive-c0re/build.rs` + librsvg on the rust derivation's
  nativeBuildInputs — both gone in the next commit).
- `hive-ag3nt/src/prompt.rs::TEMPLATE`: `render` now takes the
  template as an argument; `write_system_prompt` reads it once from
  `$HIVE_ASSETS_DIR/prompts/system.md` before calling render. The
  test module still `include_str!`s the production template so
  `cargo test --workspace` doesn't need `HIVE_ASSETS_DIR` set —
  this is the only remaining compile-time reference to the file
  from the rust workspace, gated to `#[cfg(test)]`.
- `hive-ag3nt/src/turn.rs::CLAUDE_SETTINGS`: was `include_str!`'d
  and written via `tokio::fs::write`; now `tokio::fs::copy` from
  `$HIVE_ASSETS_DIR/prompts/claude-settings.json` into the
  per-agent socket dir.
- `hive-ag3nt/src/web_ui.rs::DEFAULT_ICON`: was `include_str!`'d;
  now read on-demand from `$HIVE_ASSETS_DIR/branding/hyperhive.svg`
  inside `serve_icon`. Falls back to an empty body if missing so
  the endpoint never panics on a misconfigured container (matches
  the existing "per-agent icon.svg override" fallthrough).

`HIVE_ASSETS_DIR` wiring:

- Inside containers: `nix/templates/harness-base.nix`
  `environment.variables` sets it to
  `${pkgs.hyperhive-assets}/share/hyperhive` (resolved through
  the default overlay applied in `mkContainer`). Verified by
  building `agent-base-toplevel` and grepping the resulting
  `/etc/set-environment`.
- Host-side: `nix/modules/hive-c0re.nix` adds an `assets` option
  defaulting to `hyperhive.packages.${system}.assets`, threaded
  in from the flake's nixosModules wiring, and sets the same env
  var on the `hive-c0re` systemd unit so the daemon's
  `forge::ensure_*_avatar` startup hooks find the PNGs.

`hive-c0re/build.rs` deleted entirely; `[package].build` removed
from `hive-c0re/Cargo.toml`; rsvg-convert dependency lives in the
assets derivation only.

Validated: `nix build .#default .#checks.x86_64-linux.clippy
.#agent-base-toplevel .#manager-toplevel --fallback` all succeed.
`/etc/set-environment` in the toplevel shows
`HIVE_ASSETS_DIR="/nix/store/.../hyperhive-assets-0.1.0/share/hyperhive"`.
2026-05-29 12:59:48 +02:00
iris
65532e8387 frontend: tighten extraFiles target type to strMatching regex
damocles suggested using lib.types.strMatching for the target option
itself rather than relying solely on the post-hoc assertion. Pattern:
`^[A-Za-z0-9_][A-Za-z0-9_./-]*$` — first char alphanumeric/_, then
alphanumerics + _ + . + / + - allowed (so nested layouts like
"games/bitburner" still work).

This rejects at type-check time:
- leading `/` (absolute paths)
- leading `.` (so `..` as a full string blocked, also `./foo`)
- leading `-` (would parse as flag by some tools)
- spaces, control chars, weird unicode

The existing assertion stays — it catches mid-path `..` segments
(`foo/../bar`) that the regex can't reject without lookahead. POSIX
regex (which nix uses) doesn't support lookahead, so the
type-and-assertion split is the cleanest expression.

Refs #273.
2026-05-23 14:51:01 +02:00
iris
2951da32e7 frontend: tighten extraFiles target validation per damocles review
Follow-up to PR #350 review:

1. New assertion: hyperhive.frontend.extraFiles[*].target must be a
   relative path inside the static dir — leading '/' and '..'
   segments rejected at config eval time. Belt-and-braces against
   string-concat-into-paths escapes (the boundary doc flags this
   pattern even though agent.nix goes through operator review).

2. Documented overwrite semantics in the option doc: collision with
   a default-dist path or with a prior entry's target is a hard-fail
   (`refusing to overwrite existing path …`). To override a default
   file, fork `hyperhive.frontend.dist` instead — extraFiles is
   pure additions.

The collision-hard-fail behaviour was already implemented in
`mergedDist` (in commit a19e156); this commit just makes the
contract explicit in the docstring.

Refs #273, addresses damocles' notes on PR #350.
2026-05-23 14:51:01 +02:00
iris
892e034908 frontend: wire static-dir env var + per-agent extraFiles option
Phase 3 of #273. Container plumbing for the bundled frontend dist:

- flake.nix overlay: `pkgs.hyperhive-frontend` exposed for the
  agent / manager containers (mirrors the existing `pkgs.hyperhive`
  pattern); module argument `hyperhiveFrontend = system: self
  .packages.${system}.frontend` threads the package into the host
  hive-c0re module without forcing operators to apply the overlay
  on their host pkgs.

- `services.hive-c0re.frontend` option: pinned to the flake's
  frontend package by default, overridable for custom dashboard
  SPAs. The hive-c0re systemd service gets `HIVE_STATIC_DIR =
  ${cfg.frontend}/dashboard` — the Rust binary will pick it up
  in Phase 4.

- `hyperhive.frontend.dist` option: per-container, defaults to
  `pkgs.hyperhive-frontend`. Override to ship a fully custom
  agent SPA (advanced; the default + extraFiles flow handles the
  common 'add files' case).

- `hyperhive.frontend.extraFiles` option: attrsOf submodule
  (mirroring the `hyperhive.extraMcpServers` shape per damocles'
  request so existing #322-style assertions keep their grip).
  Each entry has `source` (path relative to agent.nix) and
  `target` (URL/disk prefix within the merged static tree,
  defaulting to the attribute name). Operator-named example:
  the bitburner agent drops `bitburner-dist` into
  `/bitburner/` alongside the default agent UI at `/`.

- `hyperhive.frontend.mergedDist` (readOnly): the runCommand
  derivation that composes `agent/` from the default dist plus
  every `extraFiles` entry. Aborts on overwrite so a filename
  collision becomes a build error rather than a silent dist swap.
  agent-base.nix + manager.nix set their respective systemd
  service `HIVE_STATIC_DIR` to this merged path.

Until Phase 4 lands, the env var is set but unused — the Rust
binaries still serve assets via `include_str!`. The cutover
happens in the next commit on this branch.

Refs #273.
2026-05-23 14:51:01 +02:00
damocles
e70ae7776c harness-base: add assertions for common agent config mistakes (closes #318) 2026-05-23 02:05:12 +02:00
damocles
77b249076f events: HIVE_DEFAULT_MODEL takes priority over persisted model (closes #319) 2026-05-23 00:38:17 +02:00
damocles
cd9831b39e forge-avatar-sync: fix data URI prefix and add jq to service path (closes #197) 2026-05-23 00:17:38 +02:00
damocles
a94b504883 forge_notify: skip-reasons drop-list filter, configurable via agent.nix 2026-05-22 22:29:32 +02:00
damocles
56d0b02c2f nix: drop unused weston-rdp.nix (closes #263) 2026-05-22 17:30:32 +02:00
damocles
4bc5237bea harness: fix sandbox-fallback conflict with lib.mkForce (closes #247) 2026-05-22 15:24:48 +02:00
damocles
6ca72074c4 docs: move sandbox threat model to docs/security.md, add code reference 2026-05-22 12:28:04 +02:00
damocles
a6bd4cf502 harness: document sandbox threat model and credential permission requirements 2026-05-22 10:57:13 +02:00
damocles
6974634326 harness: set sandbox-fallback = true to fix nix builds in containers (fixes #196) 2026-05-22 10:51:10 +02:00
damocles
8d3be74fd2 harness: fix hive-dashboard-links state dir — drop legacy /state, use /agents/*/state 2026-05-21 23:20:13 +02:00
damocles
66c481a07a harness+dashboard: declarative dashboardLinks option (closes #191) 2026-05-21 23:20:13 +02:00
damocles
317d580405 harness: fix tea-login using getent (not in PATH) — hardcode /root 2026-05-21 23:05:13 +02:00