From 9edd936a4e5a3762bd6f109cfcb062277f652b26 Mon Sep 17 00:00:00 2001 From: Daedalus Date: Sun, 6 Sep 2026 01:54:11 +0200 Subject: [PATCH] docs(operations): correct the agent telemetry and trailer contract Agent runs never read the shared ~/.claude/settings.json env block, so the identity-independent OTEL vars documented there reached no agent at all - the per-agent ingest header alone neither enables telemetry nor names an endpoint, and cotel recorded zero agent sessions for 28 days. Document that those five vars belong in the Paperclip environment record's env_vars, and add the read-only check that tells a fleet-wide outage apart from one dark agent. Also drop the Paperclip co-author trailer, now prohibited by board order, and fill in the roster additions to the canonical identity table. Co-Authored-By: Daedalus Co-Authored-By: Claude Opus 5 --- docs/operations/agent-identity.md | 95 ++++++++++++++++++++-------- scripts/git-hooks/prepare-commit-msg | 3 +- 2 files changed, 68 insertions(+), 30 deletions(-) diff --git a/docs/operations/agent-identity.md b/docs/operations/agent-identity.md index 2f62cdc..3e71bb4 100644 --- a/docs/operations/agent-identity.md +++ b/docs/operations/agent-identity.md @@ -14,16 +14,21 @@ intentionally **not** a mailbox and **not** linked to any GitHub account. The domain `agents.flopbut.local` is deliberately non-routable so it can never mis-link to a real GitHub user. -| Agent | NAME | Email | -|----------|------------|--------------------------------| -| Prospero | `Prospero` | `prospero@agents.flopbut.local` | -| Daedalus | `Daedalus` | `daedalus@agents.flopbut.local` | -| Wayland | `Wayland` | `wayland@agents.flopbut.local` | -| Aldric | `Aldric` | `aldric@agents.flopbut.local` | -| Soren | `Soren` | `soren@agents.flopbut.local` | -| Lyra | `Lyra` | `lyra@agents.flopbut.local` | -| Iris | `Iris` | `iris@agents.flopbut.local` | -| Orion | `Orion` | `orion@agents.flopbut.local` | +| Agent | NAME | Email | +|-----------|-------------|----------------------------------| +| Prospero | `Prospero` | `prospero@agents.flopbut.local` | +| Daedalus | `Daedalus` | `daedalus@agents.flopbut.local` | +| Wayland | `Wayland` | `wayland@agents.flopbut.local` | +| Aldric | `Aldric` | `aldric@agents.flopbut.local` | +| Soren | `Soren` | `soren@agents.flopbut.local` | +| Lyra | `Lyra` | `lyra@agents.flopbut.local` | +| Iris | `Iris` | `iris@agents.flopbut.local` | +| Orion | `Orion` | `orion@agents.flopbut.local` | +| Robert | `Robert` | `robert@agents.flopbut.local` | +| Pygmalion | `Pygmalion` | `pygmalion@agents.flopbut.local` | +| Argus | `Argus` | `argus@agents.flopbut.local` | +| Clio | `Clio` | `clio@agents.flopbut.local` | +| Vesper | `Vesper` | `vesper@agents.flopbut.local` | If the board later wants a real domain, change the values everywhere — the scheme is unchanged. @@ -67,21 +72,22 @@ It reads the agent's own name from `/api/agents/me`, derives the email, and ## 2. Commit trailers -In addition to the mandatory skill trailer: +Every commit ends with exactly two co-author trailers — the authoring agent, +then the model it runs on: ``` -Co-Authored-By: Paperclip +Co-Authored-By: Wayland +Co-Authored-By: Claude Opus 5 ``` -each commit gets a second co-author line for the authoring agent: +A third trailer is never added. In particular `Co-Authored-By: Paperclip +` is prohibited by board order — it was once described +here as mandatory, and that is no longer true. -``` -Co-authored-by: Wayland -``` - -The robust way to add this is the **`prepare-commit-msg` hook** in +The robust way to get the agent line is the **`prepare-commit-msg` hook** in `scripts/git-hooks/`, which reads `$GIT_AUTHOR_NAME` / `$GIT_AUTHOR_EMAIL` and -appends the trailer idempotently (it never duplicates). Install it per repo: +appends that trailer idempotently (it never duplicates). The model line is the +committing agent's own responsibility. Install the hook per repo: ```bash scripts/install-agent-git-hooks.sh # current repo @@ -146,19 +152,35 @@ despite each process carrying a distinct token in `/proc//environ`. The same precedence trap applies to `GIT_*` — keep those out of the shared `settings.json` too (they already live only in per-agent `adapterConfig.env`). -`settings.json` keeps only the **identity-independent** OTEL config, shared by -everyone: +### The identity-independent half lives in the Paperclip *environment* + +The per-agent header is only half the config. Claude Code exports nothing unless +these five are also present in the run: ```json -"env": { - "CLAUDE_CODE_ENABLE_TELEMETRY": "1", - "CLAUDE_CODE_ENHANCED_TELEMETRY_BETA": "1", - "OTEL_TRACES_EXPORTER": "otlp", - "OTEL_EXPORTER_OTLP_PROTOCOL": "http/json", - "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "https://otlp.aignite.pl/v1/traces" -} +"CLAUDE_CODE_ENABLE_TELEMETRY": "1", +"CLAUDE_CODE_ENHANCED_TELEMETRY_BETA": "1", +"OTEL_TRACES_EXPORTER": "otlp", +"OTEL_EXPORTER_OTLP_PROTOCOL": "http/json", +"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": "https://otlp.aignite.pl/v1/traces" ``` +For agent runs they belong in the **Paperclip environment record's `env_vars`** +(`Local` for this machine), which the adapter merges into the spawn environment +alongside `adapterConfig.env`. + +> A Paperclip-spawned run does **not** read the `env` block of the shared +> `~/.claude/settings.json`. Putting the five vars only there covers the board's +> interactive sessions and no agent at all. + +That asymmetry produced a silent 28-day outage: `settings.json` carried all five +and each agent carried its own header, yet cotel recorded **zero** agent +sessions — a header alone neither enables telemetry nor names an endpoint. +Adding the five to the `Local` environment restored five agents within minutes. + +An environment whose `env_vars` lacks them stays dark no matter what its agents +carry — that is the state of the `robmini` (`ssh` driver) environment. + ### Where the human's interactive default lives The board's **own** interactive `claude` sessions are not spawned by Paperclip, @@ -169,6 +191,23 @@ non-interactive `bash -c`, which returns before reaching the export, so an agent never picks up the human default — it keeps its own injected token. Interactive human shells run the export and report under the default token. +### Checking that agent telemetry actually lands + +cotel runs on `robmini`; read it there, read-only, over the loopback port. The +public host sits behind Cloudflare Access and answers 302, and `--db-query` +fights the server for the DuckDB lock. + +```bash +ssh robmini 'curl -s "http://localhost:8080/api/v1/sessions?limit=500"' +``` + +Group the result by `user_id`: every agent that has run inside the retention +window should appear under its own name. A `user_id` missing entirely means its +runs never exported — check the environment's `env_vars` first (the whole fleet +is dark) and the agent's own header second (only that agent is dark). Spans that +carry an endpoint but no valid header are rejected at ingest, so a +header-less agent fails silently rather than landing in a default bucket. + ## Scope Repositories in scope: `cotel`, `ksef-docs`, and any new repo under diff --git a/scripts/git-hooks/prepare-commit-msg b/scripts/git-hooks/prepare-commit-msg index 6b5c823..6dc226c 100755 --- a/scripts/git-hooks/prepare-commit-msg +++ b/scripts/git-hooks/prepare-commit-msg @@ -6,8 +6,7 @@ # Each local agent runs with GIT_AUTHOR_NAME / GIT_AUTHOR_EMAIL injected by its # Paperclip adapter env. This hook turns those into a second co-author trailer so # the agent is credited in the commit body in addition to the author/committer -# fields. The mandatory `Co-Authored-By: Paperclip ` line -# is added by the agent itself per the skill rule and is left untouched here. +# fields. The model trailer is added by the agent itself and left untouched here. # # Idempotent: re-running never duplicates a trailer. Safe to install in every repo.