From d516bb890c515f4a7989e2018b0175896f98a0bd Mon Sep 17 00:00:00 2001 From: iris Date: Sat, 7 Nov 2026 12:44:07 +0100 Subject: [PATCH] remove the forge links from the hive dashboard and the agent page Each agent row on the hive dashboard, and the agent page's link menu, linked to the agent's forge profile and its config repo. Both are gone, with what only they used: - hive-agent no longer builds the two links, the `Forge` link kind, or the `forge_public_url` field of its state, and no longer reads `HIVE_FORGE_PUBLIC_URL`. The agent page's link menu and the dashboard row's icon strip (which skips a forge link an agent not yet rebuilt still sends) drop their forge handling. - hive-c0re's dashboard state no longer carries `forge_public_url`. - `HIVE_FORGE_PUBLIC_URL` is no longer forwarded to agents through the meta flake (the forwarded-variable list, its test fixture, the controller's settings and the VM test), so the next meta flake render differs by that one line. hive-c0re still reads it for the forge URL a hive publishes, so `swarm.forge.publicUrl` stays, with its description corrected. - The docs stop describing the links. --- docs/2-handbook/agents/web-page.md | 7 +-- docs/2-handbook/hives/README.md | 4 +- docs/2-handbook/hives/dashboard.md | 13 ++--- docs/4-implementation/networking/gateway.md | 4 +- frontend/packages/agent/src/Root.tsx | 3 +- frontend/packages/agent/src/agent.css | 2 +- .../packages/agent/src/components/MetaNav.tsx | 47 ++++++---------- frontend/packages/agent/src/types.ts | 5 +- frontend/packages/dashboard/src/agents.js | 27 +++------ hive-agent/src/web_ui/state.rs | 55 +++---------------- hive-c0re/src/dashboard/state_snapshot.rs | 12 ---- hive-meta-flake/src/lib.rs | 1 - .../testdata/meta-flake-swarm.nix.in | 1 - nix/host-modules/hive-forge/service.nix | 12 +--- nix/host-modules/swarm-controller.nix | 3 - nix/vm-tests/full-setup.nix | 1 - 16 files changed, 49 insertions(+), 148 deletions(-) diff --git a/docs/2-handbook/agents/web-page.md b/docs/2-handbook/agents/web-page.md index 0fd2805c..bf37ec21 100644 --- a/docs/2-handbook/agents/web-page.md +++ b/docs/2-handbook/agents/web-page.md @@ -81,14 +81,11 @@ at a given viewport width. Two columns: - **Links badge** (`πŸ”—`): opens a popover listing `↑ dashboard` (back-link to the host dashboard, `${dashboardBase}`) followed by this agent's `agent_links()`-sourced navigation (stats, - screen when VNC is enabled, forge profile + config-repo mirror when - the agent has a forge account, any `services.hyperhive.agent.dashboardLinks` + screen when VNC is enabled, any `services.hyperhive.agent.dashboardLinks` extras) β€” all as real `` elements, not a `Dropdown`-style command list, so ctrl/middle-click and "copy link address" keep working. Each `AgentLink.kind` resolves differently: `container` β†’ - same-origin path; `forge` β†’ `state.forge_public_url + url`, and - hive-agent drops the link entirely when that's unset (never guessed from - `:3000`); `external` β†’ already absolute. Same source + same-origin path; `external` β†’ already absolute. Same source (`GET /api/state`'s `links` field) also feeds `DashboardState.links` for the dashboard card's icon strip β€” `agent_links()` in hive-agent is the single source of truth for diff --git a/docs/2-handbook/hives/README.md b/docs/2-handbook/hives/README.md index e1ca2d04..7082ad2c 100644 --- a/docs/2-handbook/hives/README.md +++ b/docs/2-handbook/hives/README.md @@ -45,8 +45,8 @@ covers it. **Check on an agent.** 4G3NTS shows every container as a row: name, whether it's running, what it's doing (a live status pill such as `rebuilding…` or -`starting…` while something's in flight), and quick links (stats, screen, -forge profile). Select the name to open its terminal and watch it work. +`starting…` while something's in flight), and quick links (stats, screen). +Select the name to open its terminal and watch it work. **Review a config change.** Agent config changes (new packages, env vars, MCP servers) are pull requests on the agent's `agent-configs` repo. Review and diff --git a/docs/2-handbook/hives/dashboard.md b/docs/2-handbook/hives/dashboard.md index ef6a5143..1ec23330 100644 --- a/docs/2-handbook/hives/dashboard.md +++ b/docs/2-handbook/hives/dashboard.md @@ -197,9 +197,8 @@ fetch entirely. **icon-only nav strip** plus live agent-owned state, all populated async from a single `GET /api/dashboard-state` call to the agent's own hive-agent. The response (`DashboardState`) carries: `links` (nav -strip entries β€” `πŸ“Š stats`, `πŸ–₯ screen` when GUI is enabled, `⬑ forge -profile`, `↳ agent-configs mirror`, plus any agent-declared -`dashboardLinks` extras), `status_text` / `status_set_at` (agent +strip entries β€” `πŸ“Š stats`, `πŸ–₯ screen` when GUI is enabled, plus any +agent-declared `dashboardLinks` extras), `status_text` / `status_set_at` (agent self-reported status β€” the `(set N ago)` chip carries a `data-set-at` stamp and ticks every 30s to stay fresh across the long-lived keyed row cache), `rate_limited`, `ctx_tokens` / `context_window_tokens` @@ -216,11 +215,9 @@ per-agent harness β€” TCP or unix-domain depending on the agent's `docs/4-implementation/networking/gateway.md::Per-agent unix-socket upstream`). Gateway-off is the flag-absent fallback (a dashboard served outside a hyperhive deploy): base URL is -`http://:` (direct TCP). Forge -links resolve against `state.forge_public_url` (sourced from -`services.hyperhive.swarm.forge.publicUrl`) and disappear entirely when -that's unset β€” never guessed from `:3000`. External links are -already absolute. The same base URL drives the primary agent-name +`http://:` (direct TCP). External links are +already absolute. The row has no forge links: an agent's forge profile +and config repo are on the forge itself. The same base URL drives the primary agent-name link + favicon fetch, so the whole row routes through the gateway as a unit. diff --git a/docs/4-implementation/networking/gateway.md b/docs/4-implementation/networking/gateway.md index 833730a3..0a153759 100644 --- a/docs/4-implementation/networking/gateway.md +++ b/docs/4-implementation/networking/gateway.md @@ -431,9 +431,7 @@ when `StateSnapshot.gateway_enabled` is true, and direct every hive, so the direct shape is a fallback for the variable being unset. Three render sites follow it: the agent-name link, the favicon fetch (`/icon`), and the nav-strip `container`-kind links from -`DashboardState.links` (`GET /api/dashboard-state`). Forge links come from -`swarm.forge.publicUrl`; with it unset the dashboard hides them rather than -guess. See `docs/2-handbook/hives/dashboard.md::Container row` for the frontend side. +`DashboardState.links` (`GET /api/dashboard-state`). See `docs/2-handbook/hives/dashboard.md::Container row` for the frontend side. ### Dialing another vhost by name (`verifiedProxyTo`) diff --git a/frontend/packages/agent/src/Root.tsx b/frontend/packages/agent/src/Root.tsx index 61266b49..50e6a907 100644 --- a/frontend/packages/agent/src/Root.tsx +++ b/frontend/packages/agent/src/Root.tsx @@ -141,7 +141,7 @@ export function Root() { count={todos.length} onClick={() => setOpenPanel("todos")} /> - {/* Needs a loaded snapshot for its data (links/forge_public_url, + {/* Needs a loaded snapshot for its data (links, * dashboard_port) β€” omitted until the first /api/state resolves, * same as the old page's populateOverflowMenu (now deleted β€” * dashboard-link moved here, rebuild removed outright, see @@ -149,7 +149,6 @@ export function Root() { {state ? ( ) : null} diff --git a/frontend/packages/agent/src/agent.css b/frontend/packages/agent/src/agent.css index 3094417e..6e471724 100644 --- a/frontend/packages/agent/src/agent.css +++ b/frontend/packages/agent/src/agent.css @@ -196,7 +196,7 @@ h3 { object-fit: cover; } -/* Meta-nav links (stats / screen / forge / dashboard / extras) β€” +/* Meta-nav links (stats / screen / dashboard / extras) β€” no underline; hover lights with cyan glow + subtle background tint. Reads as a row of soft tabs rather than default-styled inline anchors. */ diff --git a/frontend/packages/agent/src/components/MetaNav.tsx b/frontend/packages/agent/src/components/MetaNav.tsx index 585d5acd..23b8cf0c 100644 --- a/frontend/packages/agent/src/components/MetaNav.tsx +++ b/frontend/packages/agent/src/components/MetaNav.tsx @@ -2,7 +2,7 @@ // (`@hive/shared/icons.js`'s `LinkIcon` β€” an emoji glyph can't match a // neighbouring icon's size/weight on any platform, see that file's // comment) in the pills cluster that opens a popover listing -// stats/screen/forge/config + any `services.hyperhive.agent.dashboardLinks` extras, +// stats/screen + any `services.hyperhive.agent.dashboardLinks` extras, // sourced from the backend's `agent_links()` (the single source of // truth β€” same list also feeds the dashboard card's icon strip) β€” plus // a `🧭 dashboard` back-link. @@ -28,17 +28,12 @@ import "./MetaNav.css"; export interface MetaNavProps { links: AgentLink[]; - forgePublicUrl: string | null; /** Absolute base URL of the host dashboard (`resolveDashboardBase`) * β€” the `🧭 dashboard` item links to `${dashboardBase}`. */ dashboardBase: string; } -export function MetaNav({ - links, - forgePublicUrl, - dashboardBase, -}: MetaNavProps) { +export function MetaNav({ links, dashboardBase }: MetaNavProps) { const [open, setOpen] = useState(false); const rootRef = useRef(null); @@ -64,11 +59,7 @@ export function MetaNav({ }; }, [open]); - // Same kind -> URL resolution as app.js's old refreshState meta-links - // loop: `forge` needs `forgePublicUrl` set or the link is dropped - // entirely (never guessed from `:3000`); `external` is already - // absolute; `container` is a same-origin path. - const visible = links.filter((lnk) => lnk.kind !== "forge" || forgePublicUrl); + // `external` is already absolute; `container` is a same-origin path. // No early-return-on-empty: the dashboard link below is always // present, so the trigger always has at least one item. @@ -93,24 +84,20 @@ export function MetaNav({ > 🧭 dashboard - {visible.map((lnk) => { - const href = - lnk.kind === "forge" ? `${forgePublicUrl}${lnk.url}` : lnk.url; - return ( - setOpen(false)} - > - {lnk.icon ? : null} - {lnk.label} - - ); - })} + {links.map((lnk) => ( + setOpen(false)} + > + {lnk.icon ? : null} + {lnk.label} + + ))} ) : null} diff --git a/frontend/packages/agent/src/types.ts b/frontend/packages/agent/src/types.ts index e5487757..390fee76 100644 --- a/frontend/packages/agent/src/types.ts +++ b/frontend/packages/agent/src/types.ts @@ -28,11 +28,10 @@ export interface AgentState { paused: boolean; inbox: InboxRow[]; links: AgentLink[]; - forge_public_url: string | null; } // Mirrors `hive_agent::web_ui::state::AgentLink` β€” one meta-nav entry -// in the agent page header (stats/screen/forge/config + any +// in the agent page header (stats/screen + any // `services.hyperhive.agent.dashboardLinks` extras). `agent_links()` on the backend // is the single source of truth for what links an agent exposes; see // docs/2-handbook/agents/web-page.md::Header for the kind β†’ URL resolution table. @@ -40,7 +39,7 @@ export interface AgentLink { url: string; icon: string; label: string; - kind: "container" | "forge" | "external"; + kind: "container" | "external"; } export interface TokenUsage { diff --git a/frontend/packages/dashboard/src/agents.js b/frontend/packages/dashboard/src/agents.js index 33da89a9..9344ba65 100644 --- a/frontend/packages/dashboard/src/agents.js +++ b/frontend/packages/dashboard/src/agents.js @@ -270,8 +270,7 @@ function containerRowFingerprint( // changed (keyed cache), skipping the build + async dashboard-state // fetch for stable rows. function buildContainerLi(c, opts) { - const { pending, opRunning, selected, url, containerBase, forgeBase, s } = - opts; + const { pending, opRunning, selected, url, containerBase, s } = opts; // A single `pending-running` class covers any active transient // badge state (see the pending-badge derivation comment in // renderContainers). @@ -342,8 +341,7 @@ function buildContainerLi(c, opts) { // `GET /api/dashboard-state` (via gateway when enabled, direct // TCP otherwise). The agent is the single source of truth for its // link list: stats / screen (GUI agents only β€” c0re's disk-based - // fallback cannot detect this) / forge profile / agent-configs / - // extras. DOM-built β€” link strings come from the agent's process + // fallback cannot detect this) / extras. DOM-built β€” link strings come from the agent's process // and must never reach the HTML parser. const navStrip = el("span", { class: "nav-strip" }); head.append(navStrip); @@ -363,15 +361,13 @@ function buildContainerLi(c, opts) { // -- nav strip ----------------------------------------------- if (Array.isArray(ds.links)) { for (const lnk of ds.links) { - // No public forge URL to link to β€” hide rather than build - // a broken/guessed href (see forgeBase above). - if (lnk.kind === "forge" && !forgeBase) continue; + // An agent not yet rebuilt still sends forge links, which no + // page links to any more. + if (lnk.kind === "forge") continue; const href = - lnk.kind === "forge" - ? forgeBase + (lnk.url || "") - : lnk.kind === "external" - ? lnk.url || "" - : /* container */ containerBase + "/" + (lnk.url || ""); + lnk.kind === "external" + ? lnk.url || "" + : /* container */ containerBase + "/" + (lnk.url || ""); const a = el("a", { class: "nav-link", href, @@ -634,12 +630,6 @@ export function renderContainers(s) { // loopback port while the socket marker is absent). See // `docs/2-handbook/hives/dashboard.md::Container row` + `docs/4-implementation/networking/gateway.md::Vhost map`. const gatewayLinks = !!(s && s.gateway_enabled); - // Forge public URL: state.forge_public_url (set by the NixOS module - // from services.hyperhive.swarm.forge.publicUrl) or null β€” never guessed - // from ":3000". `null` propagates down to - // buildContainerLi/buildAgentMenu, which already hide forge links - // rather than emit a possibly-wrong one. - const forgeBase = (s && s.forge_public_url) || null; const ul = existingUl ?? el("ul", { class: "containers" }); const rows = sortedContainerRows(containers); @@ -691,7 +681,6 @@ export function renderContainers(s) { selected, url, containerBase, - forgeBase, s, }); containerRowCache.set(c.name, { el: li, fingerprint: fp }); diff --git a/hive-agent/src/web_ui/state.rs b/hive-agent/src/web_ui/state.rs index e9daa204..7713d448 100644 --- a/hive-agent/src/web_ui/state.rs +++ b/hive-agent/src/web_ui/state.rs @@ -47,10 +47,7 @@ pub(super) async fn api_state(State(state): State) -> axum::Json, - /// Public URL of the forge (e.g. - /// `"https://forge.pr1ma.darkest.space"`). Sourced from - /// `HIVE_FORGE_PUBLIC_URL` (set from - /// `services.hyperhive.swarm.forge.publicUrl`); `None` when unset. The frontend uses this to build - /// forge nav-strip links, and **hides** the forge link entirely - /// when absent rather than guessing `:3000`. - forge_public_url: Option, /// Human name of this hive instance (e.g. `"pr1ma"`). Sourced /// from `HYPERHIVE_HIVE_NAME`; `None` when unset. The frontend /// uses this for the page `` and header label so browser @@ -190,7 +180,7 @@ pub(super) struct StateSnapshot { /// of truth for what links an agent exposes. #[derive(Serialize)] struct AgentLink { - /// `kind = Container | Forge` β†’ path; `kind = External` β†’ full URL. + /// `kind = Container` β†’ path; `kind = External` β†’ full URL. /// The frontend prepends the right base before rendering. url: String, icon: String, @@ -209,10 +199,6 @@ enum AgentLinkKind { /// `/screen`). Agent page: same-origin path. Dashboard: /// `http://<host>:<container.port><url>`. Container, - /// `url` is a path on the local Forgejo (`/<label>`, - /// `/agent-configs/<label>`). Both surfaces: - /// `http://<host>:3000<url>`. - Forge, /// `url` is already a fully-qualified absolute URL β€” use as-is. /// Agent-declared `services.hyperhive.agent.dashboardLinks` extras arrive here. External, @@ -272,7 +258,7 @@ fn read_own_status() -> (Option<String>, Option<i64>) { } /// Build the navigation link list for the agent page header. URLs -/// are paths (relative) for `Container`/`Forge` targets and absolute +/// are paths (relative) for `Container` targets and absolute /// for `External`; the frontend resolves each against its `kind` /// against the right base so the backend never has to guess the /// operator's browser host. See @@ -282,16 +268,9 @@ fn read_own_status() -> (Option<String>, Option<i64>) { /// Icons are real emoji, not unicode arrow/geometric glyphs β€” mara: /// operator-declared `dashboardLinks` extras are already free-choice /// emoji, so the built-ins should read as the same family rather than -/// mixing in plain text glyphs (which also don't reliably render as a -/// hexagon/arrow across fonts to begin with). `config` went through two -/// rounds on this: gear (`βš™`, with and without a variation selector) -/// still rendered broken in mara's browser either way β€” same -/// font-unreliable codepoint `icons.tsx` already documents avoiding. -/// Landed on the wrench (`πŸ”§`) instead: a supplementary-plane pictograph -/// with `Emoji_Presentation=Yes`, same category as every other icon -/// here (`πŸ“Š`/`πŸ–₯`/`πŸ”¨`/`🧭`), so it doesn't need a variation selector to -/// render as color emoji in the first place. -fn agent_links(label: &str, gui_enabled: bool) -> Vec<AgentLink> { +/// mixing in plain text glyphs (which also don't reliably render across +/// fonts to begin with). +fn agent_links(gui_enabled: bool) -> Vec<AgentLink> { let mut links = Vec::new(); links.push(AgentLink { @@ -310,26 +289,6 @@ fn agent_links(label: &str, gui_enabled: bool) -> Vec<AgentLink> { }); } - // Either copy of the forge token: the one fetched from the swarm secret - // store (`HIVE_FORGE_TOKEN_FILE`), or the state-dir file the hive used - // to write. - let fetched_token = std::env::var_os("HIVE_FORGE_TOKEN_FILE") - .is_some_and(|p| std::path::Path::new(&p).is_file()); - if fetched_token || crate::paths::state_dir().join("forge-token").is_file() { - links.push(AgentLink { - url: format!("/{label}"), - icon: "πŸ”¨".to_owned(), - label: "forge".to_owned(), - kind: AgentLinkKind::Forge, - }); - links.push(AgentLink { - url: format!("/agent-configs/{label}"), - icon: "πŸ”§".to_owned(), - label: "config".to_owned(), - kind: AgentLinkKind::Forge, - }); - } - // Agent-declared extras (`services.hyperhive.agent.dashboardLinks` β†’ the // `hive-dashboard-links` NixOS oneshot writes them to // `{state_dir}/hyperhive-dashboard-links.json`). Shape on disk diff --git a/hive-c0re/src/dashboard/state_snapshot.rs b/hive-c0re/src/dashboard/state_snapshot.rs index d8a825d0..5fe0e52e 100644 --- a/hive-c0re/src/dashboard/state_snapshot.rs +++ b/hive-c0re/src/dashboard/state_snapshot.rs @@ -66,15 +66,6 @@ pub(super) struct StateSnapshot { /// `http://<hostname>:<port>/` TCP links) is retained as a defensive /// fallback for the env being unset. See `docs/4-implementation/networking/gateway.md::Vhost map`. gateway_enabled: bool, - /// Public URL of the forge (e.g. - /// `"https://forge.pr1ma.darkest.space"`). Sourced from the - /// `HIVE_FORGE_PUBLIC_URL` env var, which the c0re NixOS module - /// sets from `services.hyperhive.swarm.forge.publicUrl` (defaults to - /// the gateway vhost URL). `None` when absent β€” the frontend **hides** - /// forge links rather than guessing `http://<hostname>:3000`, - /// which is only right by accident on deployments that aren't - /// plain localhost. - forge_public_url: Option<String>, /// Browser URL of the swarm UI (the swarm apex domain). Sourced from /// `HIVE_SWARM_PUBLIC_URL`, which the c0re NixOS module sets from /// `services.hyperhive.swarm.domain`. `None` when the domain is unset β€” @@ -197,9 +188,6 @@ pub(super) async fn api_state( let s = v.to_string_lossy().to_ascii_lowercase(); matches!(s.as_str(), "1" | "true" | "yes") }), - forge_public_url: std::env::var("HIVE_FORGE_PUBLIC_URL") - .ok() - .filter(|s| !s.is_empty()), swarm_public_url: std::env::var("HIVE_SWARM_PUBLIC_URL") .ok() .filter(|s| !s.is_empty()), diff --git a/hive-meta-flake/src/lib.rs b/hive-meta-flake/src/lib.rs index 2f9ec8e4..1d0aac1d 100644 --- a/hive-meta-flake/src/lib.rs +++ b/hive-meta-flake/src/lib.rs @@ -69,7 +69,6 @@ pub const FORWARDED_VARS: &[&str] = &[ // The metrics store's origin, for `swarm-metrics`, for the same reason. "HIVE_AGENT_METRICS_URL", "HIVE_FORGE_URL", - "HIVE_FORGE_PUBLIC_URL", "HIVE_MATRIX_URL", "HYPERHIVE_SWARM_NAME", ]; diff --git a/hive-meta-flake/testdata/meta-flake-swarm.nix.in b/hive-meta-flake/testdata/meta-flake-swarm.nix.in index ab8865a0..c7df8a2f 100644 --- a/hive-meta-flake/testdata/meta-flake-swarm.nix.in +++ b/hive-meta-flake/testdata/meta-flake-swarm.nix.in @@ -33,7 +33,6 @@ HIVE_AGENT_LOGS_QUERY_URL = "@HIVE_AGENT_LOGS_QUERY_URL@"; HIVE_AGENT_METRICS_URL = "@HIVE_AGENT_METRICS_URL@"; HIVE_FORGE_URL = "@HIVE_FORGE_URL@"; - HIVE_FORGE_PUBLIC_URL = "@HIVE_FORGE_PUBLIC_URL@"; HIVE_MATRIX_URL = "@HIVE_MATRIX_URL@"; }; in diff --git a/nix/host-modules/hive-forge/service.nix b/nix/host-modules/hive-forge/service.nix index 98a90ebe..7c083bcc 100644 --- a/nix/host-modules/hive-forge/service.nix +++ b/nix/host-modules/hive-forge/service.nix @@ -78,17 +78,11 @@ in defaultText = lib.literalExpression ''"https://''${domain}"''; example = "https://forge.example.com"; description = '' - Browser-facing forge URL the dashboard uses to build clickable - forge links (the per-agent-row forge links) β€” - sourced into every agent container + hive-c0re as - `HIVE_FORGE_PUBLIC_URL`. + Browser-facing forge URL, sourced into hive-c0re as + `HIVE_FORGE_PUBLIC_URL` and published with the hive's URLs. Defaults to `https://''${cfg.domain}`, the gateway vhost. When - `null`, the dashboard **hides** forge links rather than - guessing one β€” see `docs/2-handbook/hives/dashboard.md::Container row` for - the rationale (a link built from the operator's own browser - hostname + a container port is only an accident away from - wrong on any deployment that isn't plain localhost). + `null`, the hive publishes no forge URL rather than guessing one. ''; }; diff --git a/nix/host-modules/swarm-controller.nix b/nix/host-modules/swarm-controller.nix index c87ad023..20b0c406 100644 --- a/nix/host-modules/swarm-controller.nix +++ b/nix/host-modules/swarm-controller.nix @@ -267,9 +267,6 @@ let vars = { HIVE_FORGE_URL = "http://${forgeCfg.domain}"; } - // lib.optionalAttrs (forgeCfg.publicUrl != null) { - HIVE_FORGE_PUBLIC_URL = forgeCfg.publicUrl; - } // lib.optionalAttrs (matrixCfg.gatewayHost != null) { HIVE_MATRIX_URL = "http://${matrixCfg.gatewayHost}"; } diff --git a/nix/vm-tests/full-setup.nix b/nix/vm-tests/full-setup.nix index a8bf4353..85bfacf1 100644 --- a/nix/vm-tests/full-setup.nix +++ b/nix/vm-tests/full-setup.nix @@ -49,7 +49,6 @@ let "HIVE_AGENT_BAO_SERVICES_PKI_MOUNT" "HIVE_AGENT_LOGS_QUERY_URL" "HIVE_AGENT_METRICS_URL" - "HIVE_FORGE_PUBLIC_URL" "HIVE_FORGE_URL" "HIVE_MATRIX_URL" ];