Documentation
¶
Index ¶
- Constants
- Variables
- func IsEnvOptedOut() bool
- func SendEvents(payloadJSON string)
- func TrackCommandDetached(cmd *cobra.Command, agent string, isEntireEnabled bool, version string)
- func TrackCommitCondensedDetached(sig CommitCondensedSignal, isEntireEnabled bool, version string)
- func TrackPluginDetached(pluginName string, isEntireEnabled bool, version string)
- func TrackSearchOutcomeDetached(outcome SearchOutcome, isEntireEnabled bool, version string)
- func TrackSkillInvocationsDetached(invocations []SkillInvocation, isEntireEnabled bool, version string)
- type CommitCondensedSignal
- type EventPayload
- func BuildCommitCondensedPayload(sig CommitCondensedSignal, isEntireEnabled bool, version string) *EventPayload
- func BuildEventPayload(cmd *cobra.Command, agent string, isEntireEnabled bool, version string) *EventPayload
- func BuildPluginEventPayload(pluginName string, isEntireEnabled bool, version string) *EventPayload
- func BuildSearchOutcomePayload(outcome SearchOutcome, isEntireEnabled bool, version string) *EventPayload
- func BuildSkillEventPayload(inv SkillInvocation, isEntireEnabled bool, version string) *EventPayload
- type SearchOutcome
- type SkillInvocation
Constants ¶
const ( SearchModeCheckpoint = "checkpoint" SearchModeCode = "code" )
Search modes for the cli_search_completed event.
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" // has no query-serve route (search.ErrCellUnavailable). Distinct from // SearchErrClassCellSkip — these are the two "region" failure variants. SearchErrClassRegionUnavailable = "region_unavailable" 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 ¶
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 TrackCommandDetached ¶
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
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 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 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.