From 65fd59cccc26e894e9397735fd92c55a97a1e1bf Mon Sep 17 00:00:00 2001 From: Kishore Kumar Date: Wed, 2 Sep 2026 09:08:42 +0530 Subject: [PATCH 1/3] docs(m181): the daemon exports traces, metrics and logs over OTLP One changelog entry for the Rust daemon's OTLP export: the four standard knobs with their defaults and refusals, the vendor aliases that survive the cutover, the 5 s collection interval, and the counted, never retried, loss. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01FunBrR9BdRLDeRrmpeEbGC --- changelog.mdx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/changelog.mdx b/changelog.mdx index e455af7..5b70d8d 100644 --- a/changelog.mdx +++ b/changelog.mdx @@ -7,6 +7,24 @@ description: "Stay up to date with the latest agentsfleet product updates, new f agentsfleet is in **stealth-mode testing** and pre-production. APIs and agent behavior may change between releases without long deprecation windows. Email [agentsfleet@agentmail.to](mailto:agentsfleet@agentmail.to) if you want a hand calibrating an agent or to join as a design partner. + + ## The daemon exports traces, metrics, and logs over OTLP + + `agentsfleetd` now sends all three signals to one OpenTelemetry Protocol (OTLP) endpoint, named by the OpenTelemetry specification's own variables. With no endpoint set, the daemon starts, serves, and exports nothing. With an unreachable endpoint, requests are unaffected: batches drop and a counter records the loss. + + ## What's new + + - **`OTEL_EXPORTER_OTLP_ENDPOINT` names the collector** — traces post to `/v1/traces`, metrics to `/v1/metrics`, and logs to `/v1/logs` under it. No default. Unset means no export. + - **`OTEL_EXPORTER_OTLP_HEADERS` adds request headers** — comma-separated `key=value` pairs. A pair without `=` stops the daemon from starting. No default. + - **`OTEL_EXPORTER_OTLP_PROTOCOL` picks the encoding** — `http/protobuf` (default) or `http/json`. Any other value, `grpc` included, stops the daemon from starting. + - **`OTEL_EXPORTER_OTLP_TIMEOUT` bounds one export** — whole milliseconds, default `10000`. Zero or an unreadable value stops the daemon from starting. + - **`GRAFANA_OTLP_ENDPOINT`, `GRAFANA_OTLP_INSTANCE_ID`, and `GRAFANA_OTLP_API_KEY` still work** — the endpoint is read when the standard variable is unset, and the pair becomes a basic `Authorization` header. A standard header of the same name replaces it. These names retire with the previous daemon. + - **Metrics are collected every 5 seconds** — the interval the previous daemon used, so a series keeps its rate across the switch. + - **Lost telemetry is counted, never retried** — spans in a batch that failed to send and metric collection cycles that failed to send are counted in the process. A resent window would double-count delta families. + - **A family this build does not produce is named at start-up** — each is logged once, at `debug` level, with the reason, rather than exported as zeros. + - **The start-up line names where the endpoint came from, never its value** — `startup_otel_enabled` carries `source=OTEL_EXPORTER_OTLP_ENDPOINT` or `source=GRAFANA_OTLP_ENDPOINT`, because the header beside the endpoint carries a credential. + + ## Every command answers a mistyped invocation the same way From 05b7e5f525351b9c017f0e6db6f44d7fb60bd530 Mon Sep 17 00:00:00 2001 From: Kishore Kumar Date: Wed, 2 Sep 2026 11:43:34 +0530 Subject: [PATCH 2/3] docs(m181): the log signal counts its losses too The loss bullet was written when only spans and metric cycles were counted. The log exporter now counts refused records onto the same family, so the bullet names all three signals. A second bullet for the one thing that is not symmetric: the log exporter raises no warning, because a warning about a failed log export becomes a log record handed back to the exporter that just failed it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HCTMYYb9kuy7uQopcysyZJ --- changelog.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog.mdx b/changelog.mdx index 5b70d8d..c42ef03 100644 --- a/changelog.mdx +++ b/changelog.mdx @@ -20,7 +20,8 @@ description: "Stay up to date with the latest agentsfleet product updates, new f - **`OTEL_EXPORTER_OTLP_TIMEOUT` bounds one export** — whole milliseconds, default `10000`. Zero or an unreadable value stops the daemon from starting. - **`GRAFANA_OTLP_ENDPOINT`, `GRAFANA_OTLP_INSTANCE_ID`, and `GRAFANA_OTLP_API_KEY` still work** — the endpoint is read when the standard variable is unset, and the pair becomes a basic `Authorization` header. A standard header of the same name replaces it. These names retire with the previous daemon. - **Metrics are collected every 5 seconds** — the interval the previous daemon used, so a series keeps its rate across the switch. - - **Lost telemetry is counted, never retried** — spans in a batch that failed to send and metric collection cycles that failed to send are counted in the process. A resent window would double-count delta families. + - **Lost telemetry is counted, never retried** — spans, log records, and metric collection cycles that failed to send are counted in the process. A resent window would double-count delta families. + - **The log signal counts without logging** — a warning about a failed log export would become a log record handed back to the exporter that just failed it. For logs the count is the whole report. - **A family this build does not produce is named at start-up** — each is logged once, at `debug` level, with the reason, rather than exported as zeros. - **The start-up line names where the endpoint came from, never its value** — `startup_otel_enabled` carries `source=OTEL_EXPORTER_OTLP_ENDPOINT` or `source=GRAFANA_OTLP_ENDPOINT`, because the header beside the endpoint carries a credential. From c94de973f5dc6f593e61f0f604d4bdfa711b2d58 Mon Sep 17 00:00:00 2001 From: Kishore Kumar Date: Thu, 3 Sep 2026 23:14:53 +0530 Subject: [PATCH 3/3] docs(api-reference): the navigation matches the operations the daemon serves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The API reference lists every operation by method and path, and the drift check compares that list against the generated document on main IN BOTH DIRECTIONS. It fires on a documented path nobody serves and on a served operation nobody documented. M181_003 caused both kinds, so every open docs PR failed a check that had nothing to do with its own change. Nine paths moved. The approval decision left the gate id's segment, because the router refuses a literal after a parameter inside one segment, and its two verbs collapse into one templated entry. The schedule sync took the same treatment. Runner paths name `{runner_id}` where they said `{id}`, secrets name `{name}` where they said `{secret_name}`, and the Slack events route generalised to `{provider}`. Eleven operations were served and undocumented. The ten `/v1/runners/me/*` routes are the runner plane — what a runner calls about ITSELF, which is a different reader from the operator-facing group that reads runners by id, so they get their own group rather than swelling that one. The fleet-messages read joins the write already beside it. Two entries go rather than move, and neither is a rename. `GET /metrics` is served by neither daemon. `POST /v1/webhooks/{fleet_id}/grant-approval` is a real Zig route never ported to Rust, so it left the generated document without anyone deciding to drop the endpoint; that gap is filed as an issue rather than left implied by a documentation entry nobody can call. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_015QmpDqyQoc7YUWDs7oTNgE --- docs.json | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/docs.json b/docs.json index 5014d0c..d77a87b 100644 --- a/docs.json +++ b/docs.json @@ -119,8 +119,7 @@ "group": "Health", "pages": [ "GET /healthz", - "GET /readyz", - "GET /metrics" + "GET /readyz" ] }, { @@ -181,11 +180,26 @@ "pages": [ "POST /v1/runners", "GET /v1/fleets/runners", - "GET /v1/fleets/runners/{id}", - "PATCH /v1/fleets/runners/{id}", - "DELETE /v1/fleets/runners/{id}", - "GET /v1/fleets/runners/{id}/leases", - "GET /v1/fleets/runners/{id}/events" + "GET /v1/fleets/runners/{runner_id}", + "PATCH /v1/fleets/runners/{runner_id}", + "DELETE /v1/fleets/runners/{runner_id}", + "GET /v1/fleets/runners/{runner_id}/leases", + "GET /v1/fleets/runners/{runner_id}/events" + ] + }, + { + "group": "Runner plane", + "pages": [ + "GET /v1/runners/me", + "POST /v1/runners/me/heartbeats", + "POST /v1/runners/me/leases", + "POST /v1/runners/me/leases/{lease_id}/renew", + "POST /v1/runners/me/leases/{lease_id}/activity", + "POST /v1/runners/me/reports", + "POST /v1/runners/me/credentials/mint", + "GET /v1/runners/me/bundles/{content_hash}", + "GET /v1/runners/me/memory/{fleet_id}", + "POST /v1/runners/me/memory/{fleet_id}" ] }, { @@ -215,8 +229,8 @@ "pages": [ "GET /v1/workspaces/{workspace_id}/secrets", "POST /v1/workspaces/{workspace_id}/secrets", - "PUT /v1/workspaces/{workspace_id}/secrets/{secret_name}", - "DELETE /v1/workspaces/{workspace_id}/secrets/{secret_name}" + "PUT /v1/workspaces/{workspace_id}/secrets/{name}", + "DELETE /v1/workspaces/{workspace_id}/secrets/{name}" ] }, { @@ -228,7 +242,7 @@ "DELETE /v1/workspaces/{workspace_id}/connectors/{provider}", "GET /v1/connectors/{provider}/callback", "POST /v1/connectors/{provider}/callback", - "POST /v1/connectors/slack/events" + "POST /v1/connectors/{provider}/events" ] }, { @@ -236,8 +250,7 @@ "pages": [ "GET /v1/workspaces/{workspace_id}/approvals", "GET /v1/workspaces/{workspace_id}/approvals/{gate_id}", - "POST /v1/workspaces/{workspace_id}/approvals/{gate_id}:approve", - "POST /v1/workspaces/{workspace_id}/approvals/{gate_id}:deny" + "POST /v1/workspaces/{workspace_id}/approvals/{gate_id}/{decision}" ] }, { @@ -265,6 +278,7 @@ { "group": "Fleet messages", "pages": [ + "GET /v1/workspaces/{workspace_id}/fleets/{fleet_id}/messages", "POST /v1/workspaces/{workspace_id}/fleets/{fleet_id}/messages" ] }, @@ -283,7 +297,7 @@ "GET /v1/workspaces/{workspace_id}/fleets/{fleet_id}/schedules/{schedule_id}", "PATCH /v1/workspaces/{workspace_id}/fleets/{fleet_id}/schedules/{schedule_id}", "DELETE /v1/workspaces/{workspace_id}/fleets/{fleet_id}/schedules/{schedule_id}", - "POST /v1/workspaces/{workspace_id}/fleets/{fleet_id}/schedules/{schedule_id}:sync", + "POST /v1/workspaces/{workspace_id}/fleets/{fleet_id}/schedules/{schedule_id}/sync", "POST /v1/ingress/qstash/schedules" ] }, @@ -309,8 +323,7 @@ "POST /v1/webhooks/svix/{fleet_id}", "POST /v1/webhooks/{fleet_id}", "POST /v1/webhooks/{fleet_id}/approval", - "POST /v1/webhooks/{fleet_id}/github", - "POST /v1/webhooks/{fleet_id}/grant-approval" + "POST /v1/webhooks/{fleet_id}/github" ] }, {