diff --git a/docs/networking/gateway.md b/docs/networking/gateway.md index 80adc2db..6d9caa36 100644 --- a/docs/networking/gateway.md +++ b/docs/networking/gateway.md @@ -87,7 +87,7 @@ The issuer is a **host-held hive CA**, not a bare self-signed leaf. `hive-tls-ca **Rotation**: `hive-tls-ca.service` re-signs the leaf when it's missing, within 30 days of expiry, or no longer covers the configured names, always under the same CA. It regenerates the CA only if missing or expired. To force a leaf rotation, delete `gateway.pem` under the state dir, restart the unit, then reload `nginx`. -**Cert prompts**: browsers warn once per host until you add the hive's `trust-bundle.pem` (the anchor, not the leaf) to the browser or OS trust store. +**Cert prompts**: browsers warn once per host until you add the hive's `trust-bundle.pem` (the anchor, not the leaf) to the browser or OS trust store. A container that needs to trust it for its own outbound TLS gets the bundle a different way, bind-mounted read-only at `/run/hive-ca/trust-bundle.pem` (`nix/host-modules/lib/hive-ca-trust.nix`). ### Operator-provided cert (`tls.certDir`) @@ -261,14 +261,12 @@ How the gateway does what the sections above describe. Read before changing `hiv ### SPA fallback (Accept-header pattern) -The per-agent UIs and the `chat.` vhost serve a flutter/SPA bundle via the Accept-header pattern below. The dashboard instead routes by **path** — see [Dashboard: path-based routing](#dashboard-path-based-routing-not-accept-header) below. Two requirements collide: +The `chat.` vhost (fluffychat) serves a flutter/SPA bundle via the Accept-header pattern below. Per-agent UIs solve the same two requirements differently, with file-existence `try_files` — see [Per-agent static frontend split](#per-agent-static-frontend-split). The dashboard routes by **path** — see [Dashboard: path-based routing](#dashboard-path-based-routing-not-accept-header) below. Two requirements collide for a vhost whose client-side router owns every route under `/`: - hard-refresh on a sub-route must serve `index.html` (SPA's client-side router takes over after JS bootstrap) - a non-navigation request that isn't an on-disk asset must NOT get HTML with the wrong content-type -Solution: an `nginx http`-context `map $http_accept $_spa_target { ... }` keyed on the request's Accept header. Browser navigations (`Accept: text/html,...`) get `index.html`; everything else (`Accept: image/*`, `*/*`, `application/json`, `text/event-stream`, …) gets a sentinel nonexistent path, so `try_files $uri $_spa_target ` falls through to ``. No extension allowlist, no `if` block, no regex heuristics. - -For matrix and per-agent static assets, `` is `=404` (a missing asset is just missing). +Solution: an `nginx http`-context `map $http_accept $matrix_spa_target { ... }` keyed on the request's Accept header. Browser navigations (`Accept: text/html,...`) get `index.html`; everything else (`Accept: image/*`, `*/*`, `application/json`, `text/event-stream`, …) gets a sentinel nonexistent path, so `try_files $uri $uri/ $matrix_spa_target =404` falls through to a plain `404` — a missing asset is just missing. No extension allowlist, no `if` block, no regex heuristics. #### Dashboard: path-based routing (not Accept-header) diff --git a/docs/scheduler/observability.md b/docs/scheduler/observability.md index c328d813..fcaaf4ce 100644 --- a/docs/scheduler/observability.md +++ b/docs/scheduler/observability.md @@ -59,10 +59,11 @@ the control plane, so degraded telemetry isn't degraded operation. ### Why two tiers **The hive tier isn't optional.** Exporting straight to `endpoint` would mean -every agent needs the credential — and the harness delivers that token into -the agent's own `~/.claude/settings.json`, a file the agent can read. `0600` -protects it from other containers, not from the agent itself. An option that -could select the direct path would reopen that hole. +every agent needs the credential — and the only place to hand it to an agent +container is somewhere the agent itself can read, its own claude settings +among them. `0600` protects a secret from other containers, not from the +agent it belongs to. An option that could select that path would reopen the +hole. **The tiers stay separate on one box.** An all-local hive is a statement about _where_ processes run, not about the shape of the deployment. A boundary that