diff --git a/docs/observability.md b/docs/observability.md index a1f16a7c..139b6e08 100644 --- a/docs/observability.md +++ b/docs/observability.md @@ -64,89 +64,13 @@ closed by this design, and nothing here should be read as closing it. ## Options reference -### `services.hyperhive.otel.enable` — bool, default `false` - -Master switch. When true, all other options below take effect. - -### `services.hyperhive.otel.endpoint` — string, default `""` - -Upstream OTLP endpoint URL, read by the swarm's collector. Example: -`"https://collector.example.com/otel"`. - -Leave it empty on a swarm running its own metrics store — that store is then -the destination. With neither, the swarm collector is refused at eval: -telemetry with nowhere to go is a misconfiguration, not a quiet no-op. - -Not what agents are handed. Their endpoint is this hive's own collector, -derived from the bridge address, so setting this changes where telemetry -*ends up* and never what a container is told. - -### `services.hyperhive.otel.protocol` — enum, default `"http/protobuf"` - -Wire protocol for the **upstream** link, honoured by the swarm collector's -exporter. Accepted values: -- `"http/protobuf"` (default) -- `"http/json"` -- `"grpc"` - -Agents are not affected: their first hop is this hive's collector, whose -OTLP/HTTP receiver takes protobuf whatever the upstream wants. - -### `services.hyperhive.otel.headersCredential` — string or null, default `null` - -Absolute path to a secret file on the host holding the upstream auth header as -`NAME=value` (e.g. `Authorization=Bearer `). - -**Only the swarm's collector reads it** — the one tier that talks to the -upstream. It arrives as an `EnvironmentFile` on that unit, so the value is -never read by nix, never copied into the store or the generated config, never -passed in argv — and reaches **neither an agent container nor a hive's own -collector**. An agent cannot read the upstream credential because it is never -given one. - -Set it on the host running the swarm's services; a hive that only forwards has -no use for it. - -Leave `null` if the upstream needs no auth header; the collector then sends -none rather than an empty one. - -```nix -services.hyperhive.otel = { - enable = true; - endpoint = "https://collector.example.com/otel"; - headersCredential = "/run/secrets/otel-headers"; -}; -``` - -### `services.hyperhive.otel.extraResourceAttributes` — string, default `""` - -Extra comma-separated entries appended to `OTEL_RESOURCE_ATTRIBUTES` after the -built-in labels (`service.name`, `agent`, `hive`, `swarm`). Example: - -```nix -extraResourceAttributes = "deployment.environment=prod,team=platform"; -``` - -### `services.hyperhive.otel.debug` — bool, default `false` - -When `true`, sets `CLAUDE_CODE_OTEL_DIAG_STDERR=1` in every agent container, -causing the OTEL SDK to emit diagnostic messages to stderr. Useful when -troubleshooting collector connectivity or endpoint config errors. Leave `false` -in normal operation — SDK errors from a misconfigured endpoint would otherwise -appear in every agent's journal unconditionally. - -Only meaningful when `enable` is true. - -### `services.hyperhive.otel.metricIntervalMs` — positive int or null, default `null` - -Metric export interval in milliseconds, set as `OTEL_METRIC_EXPORT_INTERVAL` -for every agent. Claude Code's default is 60000 (60 s). Leave `null` to keep -that default. - -Each agent runs claude as a short-lived per-turn process; claude force-flushes -metrics on process exit, so interval tuning is not required for metrics to be -exported. A lower value gives more frequent intermediate flushes within -long-running turns — cosmetic, not a correctness knob. +Every `services.hyperhive.otel.*` option's full type/default/description/ +example is generated straight from the nix module (`nix/host-modules/ +otel.nix`) into [`/options/`](/options/) (host options — `nix build +.#docs-host` for a local render). That page is kept honest by the build in a +way a hand-copied version here cannot be, so it is the reference, not this +doc. What follows is what a flat per-option listing can't express: the +two-tier architecture, the security model, and how the options interact. ## The two collectors @@ -211,19 +135,6 @@ belongs to exactly one hive. Getting the secret wrong shows up as the hive's collector logging 401s from the swarm tier and no metrics appearing for that hive. -### `services.hyperhive.otel.collector.port` — port, default `4318` - -The OTLP/HTTP port the hive tier listens on, bound to the bridge IP only. The -swarm tier has its own (`swarm.otel.port`, default `4319`) — they share a -network namespace when co-located, so the two must differ. - -### `services.hyperhive.otel.collector.upstreamHeaderName` — string, default `"Authorization"` - -Name of the header the swarm tier sends upstream. The **value** comes from the -credential file at runtime (`EnvironmentFile` → `${env:}`), never from -nix — so header names are config and header values are secrets, which is the -only split a static header map can express. - ⚠️ **`endpoint` must be valid for `protocol`.** The upstream exporter follows `otel.protocol` (`grpc` → the gRPC exporter, otherwise OTLP/HTTP), and the gRPC exporter takes an *address*: `https://host/path` is a legal