From 433c972db1d18e288a5fc69ef5fc327f1f6632a9 Mon Sep 17 00:00:00 2001 From: damocles Date: Sat, 30 May 2026 14:41:21 +0200 Subject: [PATCH 1/3] matrix: default gui.enable to matrix.enable + patch fluffychat-web base href for /matrix/ subpath (#634) --- nix/modules/hive-matrix.nix | 46 ++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/nix/modules/hive-matrix.nix b/nix/modules/hive-matrix.nix index a2ef7abe..3b0a820d 100644 --- a/nix/modules/hive-matrix.nix +++ b/nix/modules/hive-matrix.nix @@ -159,14 +159,17 @@ in gui = { enable = lib.mkOption { type = lib.types.bool; - default = false; + default = cfg.enable; + defaultText = lib.literalExpression "config.services.hyperhive.matrix.enable"; description = '' Mount a matrix web client (default `pkgs.fluffychat-web`) as a static sibling of the dashboard at `/matrix/`, served by hive-c0re's own axum router via the `HIVE_MATRIX_GUI_DIR` - env var (#607 v0). Off by default; flip to `true` once the - operator wants matrix chat one tab away from the dashboard - without standing up a separate gateway. + env var (#607). Defaults to whatever + `services.hyperhive.matrix.enable` is — turning on the + homeserver gives you the web client by default; set to + `false` explicitly to opt out of the GUI while keeping + the homeserver running for agents. Same-origin via hive-c0re is the simplest single-host shape; the post-#15 nginx-front re-root (`https://matrix.''${services.hyperhive.domain}`) @@ -178,15 +181,36 @@ in package = lib.mkOption { type = lib.types.package; - default = pkgs.fluffychat-web; - defaultText = lib.literalExpression "pkgs.fluffychat-web"; + default = pkgs.fluffychat-web.overrideAttrs (old: { + # fluffychat-web ships with `` baked into its + # index.html — that's the placeholder flutter would replace + # via `--base-href` at build time. Since hyperhive serves the + # dist at `/matrix/` (not the document root), the literal + # `` would resolve every relative asset path + # (`Imaging.js`, `flutter.js`, `splash/*`, etc.) against the + # ROOT of the origin, leading to 404s on every load (#634). + # Patch the placeholder to `` at install + # time so the SPA boots correctly under the sub-path mount. + # If/when we move to subdomain routing (#609 − + # `matrix.${hyperhiveDomain}`), drop this override and revert + # to upstream `pkgs.fluffychat-web` — it'll be at the root + # again. + postInstall = (old.postInstall or "") + '' + ${pkgs.gnused}/bin/sed -i \ + 's|||' \ + $out/index.html + ''; + }); + defaultText = lib.literalExpression "pkgs.fluffychat-web (patched for /matrix/ base href)"; description = '' Static web client dist to serve at `/matrix/`. Defaults to - `pkgs.fluffychat-web` — first-class threads support, e2ee - + voice + spaces, full feature surface in the flutter→web - build. Override to swap for `hydrogen-web` (lightest), - `cinny` (no threads), `element-web` (heaviest, full - features), or an out-of-tree client dist. + `pkgs.fluffychat-web` (with the `` patched to + `/matrix/` so relative asset paths resolve under the + sub-path mount, #634). Override to swap for `hydrogen-web` + (lightest), `cinny` (no threads), `element-web` (heaviest, + full features), or an out-of-tree client dist — any + replacement also needs its `` aligned with the + mount path. ''; }; }; From effe00889fa18cdb10e5e829a121d3e7069fb5a2 Mon Sep 17 00:00:00 2001 From: damocles Date: Sat, 30 May 2026 14:56:52 +0200 Subject: [PATCH 2/3] matrix: drop c0re /matrix mount, use targetFlags --base-href, surface availability via env (mara on #634) --- hive-c0re/src/dashboard.rs | 40 +++++++++++--------------------- nix/modules/hive-c0re.nix | 9 ++++++++ nix/modules/hive-matrix.nix | 46 +++++++++++++++++-------------------- 3 files changed, 44 insertions(+), 51 deletions(-) diff --git a/hive-c0re/src/dashboard.rs b/hive-c0re/src/dashboard.rs index c1bb2158..05b19f62 100644 --- a/hive-c0re/src/dashboard.rs +++ b/hive-c0re/src/dashboard.rs @@ -51,17 +51,6 @@ pub async fn serve(port: u16, coord: Arc) -> Result<()> { ); } tracing::info!(static_dir = %static_dir.display(), "dashboard static dir resolved"); - // Optional matrix-GUI static dist (#607). When `HIVE_MATRIX_GUI_DIR` - // is set and the dir exists, mount it at `/matrix/` as a sibling - // ServeDir before the SPA fallback. Pre-#15 (nginx front) this - // is the simplest way to put fluffychat-web on the same origin as - // the dashboard so the operator has matrix chat one tab away. - let matrix_gui_dir: Option = std::env::var_os("HIVE_MATRIX_GUI_DIR") - .map(PathBuf::from) - .filter(|p| p.is_dir()); - if let Some(dir) = &matrix_gui_dir { - tracing::info!(matrix_gui_dir = %dir.display(), "matrix GUI mount enabled at /matrix"); - } let app = Router::new() .route("/api/state", get(api_state)) .route("/approve/{id}", post(post_approve)) @@ -103,14 +92,6 @@ pub async fn serve(port: u16, coord: Arc) -> Result<()> { // /static/dashboard.css → dist/static/dashboard.css, etc.). .fallback_service(ServeDir::new(&static_dir)) .with_state(AppState { coord }); - // Sibling static mount for the optional matrix GUI dist. Layered - // before the SPA fallback so `/matrix/...` resolves there instead - // of falling through to the dashboard. - let app = if let Some(dir) = matrix_gui_dir { - app.nest_service("/matrix", ServeDir::new(dir)) - } else { - app - }; let addr = SocketAddr::from(([0, 0, 0, 0], port)); let listener = bind_with_retry(addr).await?; tracing::info!(%port, "dashboard listening"); @@ -242,10 +223,13 @@ struct StateSnapshot { /// links each container's config + each approval's commit into the /// forge's `agent-configs` repos. forge_present: bool, - /// Whether the matrix GUI static dist is mounted at `/matrix/` - /// (`HIVE_MATRIX_GUI_DIR` set + dir exists). Drives the dashboard's - /// `M4TR1X →` tab-strip entry so it doesn't flash a dead link when - /// the operator hasn't opted in (#607). + /// Whether the matrix GUI is reachable at `/matrix/`. Sourced from + /// `HIVE_MATRIX_GUI_ENABLED` env var (set by the c0re NixOS module + /// when `services.hyperhive.matrix.gui.enable` is on). The gateway + /// (hive-gateway.nix) does the actual `/matrix/` static serving; + /// this flag is just an availability signal for iris's dashboard + /// chrome so the `M4TR1X →` tab doesn't flash when the GUI is off + /// (#607, #634). matrix_gui_enabled: bool, } @@ -439,9 +423,13 @@ async fn api_state(headers: HeaderMap, State(state): State) -> axum::J port_conflicts, rebuild_queue: state.coord.rebuild_queue.snapshot(), forge_present: crate::forge::is_present().await, - matrix_gui_enabled: std::env::var_os("HIVE_MATRIX_GUI_DIR") - .map(PathBuf::from) - .is_some_and(|p| p.is_dir()), + matrix_gui_enabled: std::env::var_os("HIVE_MATRIX_GUI_ENABLED").is_some_and(|v| { + // Accept any truthy string ("1", "true", "yes") since the + // env var is set by NixOS module wiring with the literal + // "1"; defensive parse so manual overrides also work. + let s = v.to_string_lossy().to_ascii_lowercase(); + matches!(s.as_str(), "1" | "true" | "yes") + }), }) } diff --git a/nix/modules/hive-c0re.nix b/nix/modules/hive-c0re.nix index c5aeacce..9492f015 100644 --- a/nix/modules/hive-c0re.nix +++ b/nix/modules/hive-c0re.nix @@ -241,6 +241,15 @@ in # Agents poll this URL for Forgejo notifications. Derived from # services.hyperhive.forge.{domain,httpPort} so it tracks forge config changes. HIVE_FORGE_URL = "http://${config.services.hyperhive.forge.domain}:${toString config.services.hyperhive.forge.httpPort}"; + } + // lib.optionalAttrs config.services.hyperhive.matrix.gui.enable { + # Availability flag for `/api/state.matrix_gui_enabled`. The + # gateway (hive-gateway.nix) does the actual static serving of + # fluffychat-web at `/matrix/`; c0re doesn't host the dist + # itself (#634, mara on PR #620). This env var just tells the + # dashboard chrome whether the GUI is reachable so iris's + # `M4TR1X →` tab doesn't show when the GUI is off. + HIVE_MATRIX_GUI_ENABLED = "1"; }; # Matrix GUI static serving lives entirely on the hive-gateway # nginx since #609 — when gateway is off the operator opts out diff --git a/nix/modules/hive-matrix.nix b/nix/modules/hive-matrix.nix index 3b0a820d..fc9087b5 100644 --- a/nix/modules/hive-matrix.nix +++ b/nix/modules/hive-matrix.nix @@ -183,34 +183,30 @@ in type = lib.types.package; default = pkgs.fluffychat-web.overrideAttrs (old: { # fluffychat-web ships with `` baked into its - # index.html — that's the placeholder flutter would replace - # via `--base-href` at build time. Since hyperhive serves the - # dist at `/matrix/` (not the document root), the literal - # `` would resolve every relative asset path - # (`Imaging.js`, `flutter.js`, `splash/*`, etc.) against the - # ROOT of the origin, leading to 404s on every load (#634). - # Patch the placeholder to `` at install - # time so the SPA boots correctly under the sub-path mount. - # If/when we move to subdomain routing (#609 − - # `matrix.${hyperhiveDomain}`), drop this override and revert - # to upstream `pkgs.fluffychat-web` — it'll be at the root - # again. - postInstall = (old.postInstall or "") + '' - ${pkgs.gnused}/bin/sed -i \ - 's|||' \ - $out/index.html - ''; + # index.html — flutter's `--base-href` build flag replaces + # that placeholder. Default upstream build is `--base-href "/"` + # which is wrong for hyperhive's `/matrix/` sub-path mount: + # the browser resolves relative asset paths (`Imaging.js`, + # `flutter.js`, `splash/*`) against the document ROOT, + # producing 404s for every asset (#634). Inject the right + # base-href into the build via nixpkgs's `buildFlutterApplication` + # targetFlags. When subdomain routing lands (#609 — + # `matrix.${hyperhiveDomain}`), drop this override; upstream's + # `/` base-href is correct at the root of a dedicated subdomain. + targetFlags = (old.targetFlags or [ ]) ++ [ + "--base-href" + "/matrix/" + ]; }); - defaultText = lib.literalExpression "pkgs.fluffychat-web (patched for /matrix/ base href)"; + defaultText = lib.literalExpression "pkgs.fluffychat-web with --base-href /matrix/"; description = '' Static web client dist to serve at `/matrix/`. Defaults to - `pkgs.fluffychat-web` (with the `` patched to - `/matrix/` so relative asset paths resolve under the - sub-path mount, #634). Override to swap for `hydrogen-web` - (lightest), `cinny` (no threads), `element-web` (heaviest, - full features), or an out-of-tree client dist — any - replacement also needs its `` aligned with the - mount path. + `pkgs.fluffychat-web` rebuilt with `--base-href "/matrix/"` + so relative asset paths resolve under the sub-path mount + (#634). Override to swap for `hydrogen-web` (lightest), + `cinny` (no threads), `element-web` (heaviest, full + features), or an out-of-tree client dist — any replacement + also needs its `` aligned with the mount path. ''; }; }; From 2bea5d80b529c2551b8871a546682bd53344f927 Mon Sep 17 00:00:00 2001 From: damocles Date: Sat, 30 May 2026 14:59:24 +0200 Subject: [PATCH 3/3] matrix: reword gui.enable description, use literalMD for package defaultText (argus #635 nits) --- nix/modules/hive-matrix.nix | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/nix/modules/hive-matrix.nix b/nix/modules/hive-matrix.nix index fc9087b5..3c17d271 100644 --- a/nix/modules/hive-matrix.nix +++ b/nix/modules/hive-matrix.nix @@ -162,20 +162,22 @@ in default = cfg.enable; defaultText = lib.literalExpression "config.services.hyperhive.matrix.enable"; description = '' - Mount a matrix web client (default `pkgs.fluffychat-web`) as - a static sibling of the dashboard at `/matrix/`, served by - hive-c0re's own axum router via the `HIVE_MATRIX_GUI_DIR` - env var (#607). Defaults to whatever + Serve a matrix web client (default `pkgs.fluffychat-web`) as + a static dist at `/matrix/` via the hive-gateway nginx + (#607 / #634). Defaults to whatever `services.hyperhive.matrix.enable` is — turning on the homeserver gives you the web client by default; set to `false` explicitly to opt out of the GUI while keeping - the homeserver running for agents. + the homeserver running for agents. Requires + `services.hyperhive.gateway.enable` (default on); when + gateway is off no one hosts the GUI and the + `M4TR1X →` dashboard tab is hidden. - Same-origin via hive-c0re is the simplest single-host - shape; the post-#15 nginx-front re-root (`https://matrix.''${services.hyperhive.domain}`) - is tracked separately in #609. fluffychat-web supports - per-login server pick — point it at the in-host tuwunel URL - (`http://localhost:8008` by default) the first time. + fluffychat-web supports per-login server pick — point it at + the in-host tuwunel URL (`http://localhost:8008` by + default) the first time. The post-#15 nginx-front re-root + (`https://matrix.''${services.hyperhive.domain}`) is tracked + separately in #609. ''; }; @@ -198,7 +200,7 @@ in "/matrix/" ]; }); - defaultText = lib.literalExpression "pkgs.fluffychat-web with --base-href /matrix/"; + defaultText = lib.literalMD "`pkgs.fluffychat-web` rebuilt with `--base-href /matrix/` via `targetFlags`."; description = '' Static web client dist to serve at `/matrix/`. Defaults to `pkgs.fluffychat-web` rebuilt with `--base-href "/matrix/"`