entroly

Privacy-Safe Product Health Telemetry

Entroly product-health telemetry is off by default. It starts only after an operator gives explicit consent:

entroly telemetry preview
entroly telemetry on --endpoint https://telemetry.example/v1/events
entroly telemetry status

Without an endpoint, consent creates only a bounded local queue and uploads nothing. ENTROLY_DISABLE_TELEMETRY=1 and ENTROLY_AIR_GAP=1 always override stored consent. CI and test processes are excluded unless separately enabled.

What is collected

The wire format is a closed allowlist. A consenting installation can report:

Command, surface, error, and coarse value categories are deduplicated per UTC day. Savings contributions carry random event IDs so a retried upload cannot be counted twice. The reported savings number is a rounded-down lower bound; event counts must not be interpreted as command or request frequency.

What is never collected

Entroly does not put any of the following into product-health events:

The network endpoint or reverse proxy necessarily sees a connection source IP while accepting a request. The bundled collector does not read or store it and runs with access logging disabled. Operators must also disable upstream access logs or apply an appropriate short retention policy.

Evidence boundaries

A positive token-reduction bucket means Entroly measured fewer estimated tokens after its transformation. SDK and MCP-style local operations remain local_estimate: Entroly cannot prove that their output reached a paid model. Proxy transformations can be provider_bound_estimate; a positive modeled cost signal additionally requires a configured rate for the provider-bound model.

Neither signal is a provider invoice, a billed-usage comparison, or a promise that response quality improved. Reports keep these claims separate:

Storage, transport, and deletion

Remote deletion removes contributions still inside the collector retention window. After a contribution has been folded into the identifier-free archive, it can no longer be linked to an installation or individually subtracted. This is the tradeoff that permits a cumulative counter without indefinitely retaining pseudonymous event rows. Disabling telemetry also removes the unsent local quantization remainder.

Self-host the aggregate collector

The collector binds to loopback and should sit behind an authenticated HTTPS reverse proxy. In PowerShell:

$env:ENTROLY_TELEMETRY_INGEST_TOKEN = "replace-me"
$env:ENTROLY_TELEMETRY_ADMIN_TOKEN = "replace-me-too"
python -m entroly.telemetry_collector --db C:\entroly-data\product-health.db

On macOS or Linux, use export NAME=value. Keep the admin summary endpoint private. If ingest is intentionally tokenless for public clients, enforce request-size limits and rate limiting at the reverse proxy.

The private collector summary exposes only aggregates: active monthly pseudonym counts, activation counts, coarse errors, command reliability, platform-family health, and coarse benefit evidence. It never returns raw events or pseudonyms.

GET /v1/public-savings requires no admin credential and returns only the two cumulative lower-bound totals plus an update timestamp and fixed evidence/privacy labels. It exposes no pseudonym or contribution count. Browser access is allowed only for the configured ENTROLY_TELEMETRY_PUBLIC_ORIGIN (the Entroly GitHub Pages origin by default), and responses are cacheable for 30 seconds.

Telemetry cannot observe a package installation that fails before Entroly first starts. Registry downloads, release CI, and user-submitted diagnostics must cover that blind spot; the report must not misclassify a download as a working install.

To combine those aggregate observations with registry downloads without pretending downloads are users:

python scripts/adoption_report.py \
  --collector-summary-url https://telemetry.example/v1/summary?days=30

The report labels the resulting ratios as observed opt-in diagnostics, never as an actual unique-user adoption rate.

Structured exit feedback

Python and modern npm package managers do not provide a dependable Entroly uninstall callback. Pip documents package removal as a package-manager action, and npm explicitly states that uninstall lifecycle scripts are not implemented:

Entroly therefore provides an honest guided path instead of pretending every removal can be observed:

# Python installation: optional survey, then pip uninstall
entroly uninstall

# Inspect the exact response and command without sending or changing anything
entroly uninstall --dry-run \
  --reason runtime_error --benefit no --surface mcp --duration 1_7d

# npm, Docker, or another removal path: survey only, then use that manager
entroly uninstall --feedback-only
npm uninstall -g entroly

The survey has no free-text field. It contains only:

Interactive sending defaults to No and shows the collector origin first. For non-interactive use, all four fields and --send-feedback are required. ENTROLY_FEEDBACK_ENDPOINT or --endpoint selects the HTTPS collector, but neither causes a submission without the interactive confirmation or explicit flag. Air-gap and hard-disable policies still win.

The response is sent synchronously once and is never queued on failure. When ongoing telemetry is enabled and the destination is the same configured collector, it uses the current monthly pseudonym so the private aggregate report can count how many exiting installations previously observed a benefit or error. A different or one-time collector receives a random one-event pseudonym that is never persisted. The guided flow revokes local telemetry consent before the package is removed, so a later reinstall requires fresh consent.

--delete-remote-telemetry requests deletion of recent linked telemetry before sending any separately confirmed one-time response. Collector retention still applies to that new response. Users who do not want a retained exit response should decline the survey; no uninstall behavior is affected.

The private aggregate summary exposes exit-response counts, fixed reasons, self-reported benefit, primary surfaces, duration buckets, OS-family counts, and counts with prior benefit/error observations. It never exposes response rows, pseudonyms, or cross-tabs containing machine-identifying data. Direct pip uninstall, npm uninstall, deleted containers, and failed installations remain invisible; registry downloads must never be used to fabricate an exit or retention rate.