Problem
The CLI reports a command_executed telemetry event per command, but it is sent from the root command's pre-run hook, before the command body runs. That placement is deliberate: the network round trip overlaps the command, so telemetry never delays the user. It also means the event cannot carry how long the command took, so there is no way to see per-command latency, spot regressions in attestation push, or compare CI and interactive runs.
Reporting the duration from the same process would put a network round trip (roughly 100 ms on a cold connection) on the exit path of every command, which is exactly what the current design avoids. Writing the duration to disk and shipping it with the next invocation loses the last command run on a machine, which in CI is usually attestation push.
Proposed approach
Emit the event at the end of the command and hand delivery to a detached child process running the same binary with a hidden telemetry flush subcommand:
cmd.Execute measures the command, builds a small JSON payload (command path, duration_ms, success, a coarse error_kind such as the gRPC status code name, control plane URL, org name, and the parsed token identity, never the token itself) and spawns chainloop telemetry flush detached with the payload on stdin. The parent releases the child and returns immediately.
- The child rebuilds the event with the existing tracker code, derives OS, arch, CI runner and machine ID itself, and delivers it under the existing 2 s flush deadline.
duration_ms is sent as a number so PostHog can aggregate it (p50, p90, p95 per command).
- Everything stays behind the existing
DO_NOT_TRACK and dev-build gates. The telemetry flush command is excluded from telemetry so it does not report itself.
Known limitations: interrupted commands (Ctrl-C, CI timeout) are not reported, and the child is lost when the CLI is PID 1 of a container that exits right after.
🤖 Posted by Maximus bot (Claude Code) on behalf of @migmartri
Problem
The CLI reports a
command_executedtelemetry event per command, but it is sent from the root command's pre-run hook, before the command body runs. That placement is deliberate: the network round trip overlaps the command, so telemetry never delays the user. It also means the event cannot carry how long the command took, so there is no way to see per-command latency, spot regressions inattestation push, or compare CI and interactive runs.Reporting the duration from the same process would put a network round trip (roughly 100 ms on a cold connection) on the exit path of every command, which is exactly what the current design avoids. Writing the duration to disk and shipping it with the next invocation loses the last command run on a machine, which in CI is usually
attestation push.Proposed approach
Emit the event at the end of the command and hand delivery to a detached child process running the same binary with a hidden
telemetry flushsubcommand:cmd.Executemeasures the command, builds a small JSON payload (command path,duration_ms,success, a coarseerror_kindsuch as the gRPC status code name, control plane URL, org name, and the parsed token identity, never the token itself) and spawnschainloop telemetry flushdetached with the payload on stdin. The parent releases the child and returns immediately.duration_msis sent as a number so PostHog can aggregate it (p50, p90, p95 per command).DO_NOT_TRACKand dev-build gates. Thetelemetry flushcommand is excluded from telemetry so it does not report itself.Known limitations: interrupted commands (Ctrl-C, CI timeout) are not reported, and the child is lost when the CLI is PID 1 of a container that exits right after.
🤖 Posted by Maximus bot (Claude Code) on behalf of @migmartri