telemetry

package
v0.10.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Index

Constants

View Source
const (
	PolicyBlockedHookTypeGit   = "git"
	PolicyBlockedHookTypeAgent = "agent"

	PolicyBlockedReasonUnsupported = "policy_unsupported"
	PolicyBlockedReasonUnreadable  = "policy_unreadable"

	PolicyBlockedOutcomeSkipped = "skipped"
	PolicyBlockedOutcomeBlocked = "blocked"
)

Property values for the checkpoint_policy_blocked event.

View Source
const (
	SearchModeCheckpoint = "checkpoint"
	SearchModeCode       = "code"
)

Search modes for the cli_search_completed event.

View Source
const (
	// SearchErrClassAuth: not logged in, or a cell/control-plane rejected the
	// bearer (401/403).
	SearchErrClassAuth = "auth"
	// SearchErrClassCellSkip: client-side skip — no entire-api cell is
	// configured for the placement's jurisdiction (auth.ErrNoCellForJurisdiction).
	SearchErrClassCellSkip = "cell_skip"
	// SearchErrClassRegionUnavailable: the cell was contacted but its gateway
	// has no query-serve route (search.ErrCellUnavailable). Distinct from
	// SearchErrClassCellSkip — these are the two "region" failure variants.
	SearchErrClassRegionUnavailable = "region_unavailable"
	// SearchErrClassRepoUnavailable: cells answered but the repo is not
	// searchable (not indexed, or not enabled for semantic search).
	SearchErrClassRepoUnavailable = "repo_unavailable"
	// SearchErrClassNetwork: network failure or timeout.
	SearchErrClassNetwork = "network"
	// SearchErrClassServer: a 5xx response, or a 200 whose body was unusable
	// (undecodable, or carrying an application-level error field).
	SearchErrClassServer = "server"
	// SearchErrClassHTTPOther: a non-5xx, non-auth HTTP error status.
	SearchErrClassHTTPOther = "http_other"
	// SearchErrClassOther: everything else.
	SearchErrClassOther = "other"
)

Error classes for the cli_search_completed event. Classification is derived from typed errors only (see classifySearchError in the cli package), never from matching error message text.

Variables

View Source
var (
	// PostHogAPIKey is set at build time for production
	PostHogAPIKey = "phc_development_key"
	// PostHogEndpoint is set at build time for production
	PostHogEndpoint = "https://eu.i.posthog.com"
)

Functions

func IsEnvOptedOut added in v0.10.3

func IsEnvOptedOut() bool

IsEnvOptedOut reports whether the ENTIRE_TELEMETRY_OPTOUT environment opt-out is set. Every tracker honors it internally; callers that do expensive work before tracking (e.g. a git-log probe) should check it first so an opted-out user never pays for signal computation.

func SendEvents added in v0.10.3

func SendEvents(payloadJSON string)

SendEvents processes one or more event payloads in the detached subprocess. This is called by the hidden __send_analytics command.

The argv carries either a single event object or an array of them; both shapes are accepted. Leniency matters beyond convenience: the child is re-executed from os.Executable(), so a self-update that replaces the binary between spawn and exec can hand a payload to a build other than the one that wrote it.

func TrackCheckpointPolicyBlocked added in v0.8.0

func TrackCheckpointPolicyBlocked(event CheckpointPolicyBlockedEvent, version string)

TrackCheckpointPolicyBlocked sends a checkpoint_policy_blocked event by spawning a detached subprocess. Best-effort and non-blocking; callers are responsible for the settings.Telemetry opt-in check. Honors ENTIRE_TELEMETRY_OPTOUT like the other trackers.

func TrackCommandDetached

func TrackCommandDetached(cmd *cobra.Command, agent string, isEntireEnabled bool, version string)

TrackCommandDetached tracks a command execution by spawning a detached subprocess. This returns immediately without blocking the CLI.

func TrackCommitCondensedDetached added in v0.10.3

func TrackCommitCondensedDetached(sig CommitCondensedSignal, isEntireEnabled bool, version string)

TrackCommitCondensedDetached records one condensed checkpoint's adoption signal. Like TrackPluginDetached, it only honors the env opt-out itself — call sites must gate on the user's opt-in telemetry setting.

func TrackPluginDetached added in v0.6.1

func TrackPluginDetached(pluginName string, isEntireEnabled bool, version string)

TrackPluginDetached records a plugin invocation. Call sites must gate on the plugin allowlist — this function does no name filtering itself.

func TrackSearchOutcomeDetached added in v0.10.3

func TrackSearchOutcomeDetached(outcome SearchOutcome, isEntireEnabled bool, version string)

TrackSearchOutcomeDetached records one search request's outcome by spawning a detached subprocess. Best-effort and non-blocking; call sites must gate on the user's opt-in telemetry setting. Honors ENTIRE_TELEMETRY_OPTOUT like the other trackers.

func TrackSkillInvocationsDetached added in v0.10.3

func TrackSkillInvocationsDetached(invocations []SkillInvocation, isEntireEnabled bool, version string)

TrackSkillInvocationsDetached records skill invocations, batching every event into a single detached send (split only if it would exceed maxDetachedPayloadBytes). Like TrackPluginDetached, it only honors the env opt-out itself — call sites must gate on the user's opt-in telemetry setting.

No per-call cap: an earlier version truncated to 10 events, which silently dropped real invocations once condensation began extracting from transcript offset 0 — the first condensation of a session drains its whole skill-event backlog in one call, and a dropped event is never re-reported because the dedupe in session state has already recorded it.

Types

type CheckpointPolicyBlockedEvent added in v0.8.0

type CheckpointPolicyBlockedEvent struct {
	Hook                 string
	HookType             string
	Reason               string
	Outcome              string
	Agent                string
	CheckpointVersion    string
	CheckpointMinVersion string
}

CheckpointPolicyBlockedEvent carries the gate-derived fields for a checkpoint_policy_blocked telemetry event. Agent, CheckpointVersion, and CheckpointMinVersion are optional and omitted from the payload when empty.

type CommitCondensedSignal added in v0.10.3

type CommitCondensedSignal struct {
	// Agent is the session-owning agent's registry key (e.g. "claude-code"),
	// matching the agent property on skill and command events.
	Agent string
	// UsedSearch reports whether the session invoked `entire search`. Nil means
	// the question was not answerable for this agent's transcript format, and
	// the property is then OMITTED from the payload rather than sent as false —
	// so a consumer filtering on `used_search = false` excludes unknowns instead
	// of silently counting them as "did not search". UsedSearchSource always
	// says which case this is.
	UsedSearch *bool
	// UsedSearchSource records how UsedSearch was determined: "unsupported",
	// "none", "command", or "subagent". Always present.
	UsedSearchSource string
	// PriorAIHistory reports whether any committed file was touched by a
	// recent AI checkpoint commit before this one. Nil means the git-log probe
	// could not run (git unavailable, cancelled ctx, shallow-clone failure) and
	// the property is then OMITTED from the payload rather than sent as false —
	// same rationale as UsedSearch: a fabricated "no prior history" deflates
	// the very miss rate this event exists to measure. A commit that landed no
	// files is a measured false, not an omission.
	PriorAIHistory *bool
	// FilesCommitted is the number of files this checkpoint touched.
	FilesCommitted int
}

CommitCondensedSignal is the content-free adoption signal emitted when a commit condenses a session checkpoint: whether the session consulted entire search, and whether the committed files already carried AI checkpoint history. Together these give the "sessions that edited history-dense files without searching" denominator that raw command counts cannot. Content-free metadata only — booleans, a count, and the agent identifier; never file paths, prompts, or transcript content.

A commit is part of the event's identity, not an incidental trigger, which is why it is named for one. FilesCommitted and PriorAIHistory are commit-scoped: the former counts that commit's files, the latter asks whether commits *before* this one already touched them. UsedSearch is deliberately SESSION-scoped — the metric asks whether the session EVER consulted search before landing this commit, so one search early in a session rightly covers its later commits. The condensation paths that run without a commit (doctor repair, session-end leftovers) deliberately emit nothing — see newCommitCondensedSignal for why folding them in would corrupt the denominator rather than complete it.

type EventPayload

type EventPayload struct {
	Event      string         `json:"event"`
	DistinctID string         `json:"distinct_id"`
	Properties map[string]any `json:"properties"`
	Timestamp  time.Time      `json:"timestamp"`
}

EventPayload represents the data passed to the detached subprocess. Note: APIKey and Endpoint are intentionally excluded to avoid exposing them in process listings (ps/top). SendEvent reads them from package-level vars.

func BuildCheckpointPolicyBlockedPayload added in v0.8.0

func BuildCheckpointPolicyBlockedPayload(event CheckpointPolicyBlockedEvent, version string) *EventPayload

BuildCheckpointPolicyBlockedPayload constructs the event payload. Exported for testing. Returns nil if the machine ID cannot be resolved.

func BuildCommitCondensedPayload added in v0.10.3

func BuildCommitCondensedPayload(sig CommitCondensedSignal, isEntireEnabled bool, version string) *EventPayload

BuildCommitCondensedPayload constructs the telemetry payload for one condensed checkpoint. Exported for testing. Returns nil if the payload cannot be built.

func BuildEventPayload

func BuildEventPayload(cmd *cobra.Command, agent string, isEntireEnabled bool, version string) *EventPayload

BuildEventPayload constructs the event payload for tracking. Exported for testing. Returns nil if the payload cannot be built.

func BuildPluginEventPayload added in v0.6.1

func BuildPluginEventPayload(pluginName string, isEntireEnabled bool, version string) *EventPayload

BuildPluginEventPayload deliberately omits plugin args/flags — only the allowlisted plugin name is recorded. Returns nil on failure.

func BuildSearchOutcomePayload added in v0.10.3

func BuildSearchOutcomePayload(outcome SearchOutcome, isEntireEnabled bool, version string) *EventPayload

BuildSearchOutcomePayload constructs the cli_search_completed payload. Exported for testing. Returns nil if the machine ID cannot be resolved.

func BuildSkillEventPayload added in v0.10.3

func BuildSkillEventPayload(inv SkillInvocation, isEntireEnabled bool, version string) *EventPayload

BuildSkillEventPayload constructs the telemetry payload for one skill invocation. Exported for testing. Returns nil if the payload cannot be built.

type SearchOutcome added in v0.10.3

type SearchOutcome struct {
	// Command is the invoked cobra command path ("entire search" or
	// "entire checkpoint search").
	Command string
	// Mode is SearchModeCheckpoint or SearchModeCode.
	Mode string
	// ErrorClass is the coarse failure class (SearchErrClass*); empty means
	// the search succeeded.
	ErrorClass string
	// ResultCount is the number of results returned; only meaningful on
	// success (zero results is a distinct signal from failure) and omitted
	// from the payload on failure.
	ResultCount int
	// CoverageIncomplete reports that a successful response warned results
	// may be missing (failed regions, skipped repos, truncated index) —
	// without it a degraded success is indistinguishable from a genuine
	// zero-or-low-result search. Omitted from the payload on failure.
	CoverageIncomplete bool
	// DurationMS is the wall-clock duration of the search request.
	DurationMS int64
}

SearchOutcome carries the outcome of one search request (ENT-1938). Content-free by construction: booleans, enums, counts, and durations only — never query text, result snippets, or repo names. Success is derived — ErrorClass empty means success — so the two can never disagree.

type SkillInvocation added in v0.10.3

type SkillInvocation struct {
	// Skill is the invoked skill's name (e.g. "entire"). Names outside the
	// official allowlist are reported as "custom".
	Skill string
	// Agent is the agent that surfaced the signal (e.g. "claude-code").
	Agent string
	// Signal is the detection signal (e.g. "prompt_slash_command",
	// "skill_tool_use").
	Signal string
	// EventType is the skill event type ("prompt_invocation" or
	// "tool_invocation").
	EventType string
}

SkillInvocation is the content-free view of one recorded skill event: which skill fired, on which agent, and how it was detected. Deliberately no prompt text, arguments, or transcript content — and the skill name itself is only sent verbatim when allowlisted (see skillNameForTelemetry), because custom slash-command names are user content too.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL