Module: Clacky::Telemetry

Defined in:
lib/clacky/telemetry.rb

Overview

Telemetry — lightweight, anonymous usage reporting for the OpenClacky gem.

Privacy-first design (modeled after Homebrew’s opt-out analytics):

- Anonymous device identification (SHA256 of hostname + user + platform)
- No IP collection, no user-input collection, no file paths
- Fire-and-forget (background thread, no retry, silent failure)
- Opt-out via CLACKY_TELEMETRY=0 environment variable

Event types:

startup — sent on every CLI startup; server deduplicates by device_hash for unique devices
task    — sent after each agent.run completes (tracks usage & active users)

Platform endpoints:

POST /api/v1/telemetry/startup
POST /api/v1/telemetry/task

Constant Summary collapse

LAUNCH_SOURCES =
{
  "installer" => "installer",
  nil         => "cli"
}.freeze

Class Method Summary collapse

Class Method Details

.startup!Object

Called on every CLI startup (agent and server mode). No local dedup — the server deduplicates by device_hash for unique device counting, while raw event count tracks total startup volume.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/clacky/telemetry.rb', line 35

def startup!
  return unless enabled?

  brand = Clacky::BrandConfig.load
  payload = {
    device_id:     resolve_device_id(brand),
    version:       Clacky::VERSION,
    os:            RbConfig::CONFIG["host_os"],
    ruby_version:  RUBY_VERSION,
    brand:         brand.branded? ? brand.package_name : nil,
    launch_source: LAUNCH_SOURCES.fetch(ENV["CLACKY_LAUNCHED_BY"], "cli")
  }.compact

  fire_and_forget("/api/v1/telemetry/startup", payload)
end

.task!(result: nil) ⇒ Object

Called after every agent.run completes (CLI and server mode). Tracks usage activity and daily task volume. No client-side dedup — the server keeps every event for task counting, and derives DAU from distinct devices per day.

Parameters:

  • result (Hash, nil) (defaults to: nil)

    optional build_result hash from Agent#run. When present, enriches the payload with model/provider/tokens/cost/duration/status.



58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/clacky/telemetry.rb', line 58

def task!(result: nil)
  return unless enabled?

  brand = Clacky::BrandConfig.load
  payload = {
    device_id: resolve_device_id(brand),
    version:   Clacky::VERSION,
    brand:     brand.branded? ? brand.package_name : nil
  }
  payload.merge!(extract_task_metrics(result)) if result.is_a?(Hash)

  fire_and_forget("/api/v1/telemetry/task", payload.compact)
end