Telemetry
Releases from v0.9.3 onward report one event when serve or the daemon runs
for the first time on a machine, and the installers report a second,
independent event when they finish. Builds that include supervisor telemetry
send a third when kivgraph daemon install successfully registers a supervisor
entry. The contract is tied to the first release that shipped it rather than a
hand-maintained “latest release” label that can go stale.
The one thing it reports
Section titled “The one thing it reports”A single event: this version arrived here, and what it just did. For one address, version and UTC day, the collector accepts at most one row per emitter, so up to three emitter types can be present. The installer has no local marker and can report again on another day. The rows are never added together: a bundle can be installed and never launched, and a daemon can be run once without ever being installed as a service.
It carries up to five fields and nothing else:
| field | values | what it says |
|---|---|---|
emitter | installer, binary, supervisor | which of the three just happened |
version | MAJOR.MINOR.PATCH, as in 0.9.5 | which version |
platform | linux-amd64, darwin-arm64, windows-amd64 | which build |
channel | installer, mcpb, archive | how it got there |
transport | stdio, daemon | which arrangement served, on binary rows only; absent otherwise |
That is the entire payload. There is no field for anything else, so there is no version of it that carries more.
What is never reported
Section titled “What is never reported”- Nothing about your code. No repository name, no path, no file name, no symbol, no query, no result. The graph never leaves your machine, and this ping is not a channel that could carry part of it.
- No identifier minted by us. Kivgraph does not generate a machine id, an install id or a user id, and does not store one.
- No hostname, no user name, no environment.
- No address stored by us. The Cloudflare edge sees an address, as it does for every HTTP request. It combines that address with a secret salt, the UTC day, version and emitter, stores only the SHA-256 result, and rotates the result every day. For one emitter and version on one UTC day, everyone behind one NAT counts as one machine.
- A country code, and only that rough location, is stored. Cloudflare derives it before the event reaches the database. No city, street, coordinates or address are kept.
Why the ping exists at all
Section titled “Why the ping exists at all”Download counts cannot answer it. GitHub counts a download when a URL is fetched, and some of every release’s downloads are our own: the release job publishes three bundles to a package registry, which fetches each one back to verify the checksum it was given. A directory mirroring a registry looks exactly like a person installing, and a bundle can be downloaded and never run.
How many machines ran it is a different question from how many files were fetched, and only the binary can answer it.
What never reports at all
Section titled “What never reports at all”A binary that is not sitting in the layout a release unpacks into does not
report — it looks for that layout around itself, and the output of go build
or go install is not in one. That is a check on the surroundings and not on
who compiled the binary: your own build, dropped into an unpacked release,
would report. It also keeps our own continuous integration, which builds and
runs Kivgraph on every push, out of a number that is supposed to be about you.
The binary reports only when it starts serving: kivgraph serve and the
daemon. Running kivgraph index in a terminal sends nothing, and neither does
kivgraph daemon status or kivgraph daemon remove — only install
registers the entry that the third fact reports.
Turning it off
Section titled “Turning it off”Fetching an installer from kivgraph.dev records one delivery request before
the shell starts: timestamp, the observed User-Agent, its parsed client
family and version, whether it names a known CI runner, and the country code
Cloudflare supplies. It stores no address, cookie or query string. The request
then redirects to the unmodified installer asset on GitHub, and a storage
failure never blocks that redirect.
That delivery fact cannot read KIVGRAPH_TELEMETRY, because the environment
belongs to the shell that has not started yet. To avoid it, fetch the same
published asset directly:
curl -fsSL https://github.com/Luqueee/kivgraph/releases/latest/download/install.sh | KIVGRAPH_TELEMETRY=0 bashKivgraph’s published release assets are public, and this fallback is an unauthenticated public-release download. A private GitHub release would require an authenticated download before starting the installer.
The switch below controls the installer-completed, first-run and supervisor events.
export KIVGRAPH_TELEMETRY=0Set anywhere the process can see it — your shell, the MCP client’s env
block, the systemd unit — and nothing is sent. There is no second switch on
your side and no partial mode.
The installers take the same variable. It has to reach the shell, not the download:
curl -fsSL https://kivgraph.dev/install.sh | KIVGRAPH_TELEMETRY=0 bashTurning it off costs you nothing: no feature checks it, and no behaviour changes.
Where it goes
Section titled “Where it goes”The exact /api/telemetry/first-run route terminates in a Cloudflare Worker.
The Worker validates the closed payload, replaces the address with the daily
hash described above and writes the event to the project’s Cloudflare D1
database. The internal dashboard reads daily aggregates from that database.
It does not go to the website’s Umami property, a third-party analytics vendor
or an ad network.
When it changes
Section titled “When it changes”This page changes in the same commit as the code, or the change does not ship. If a field is ever added, it is described here first.