chore(telemetry): drop per-load skill_loaded beacons, send anonymous events

Report the distinct set of skills used once on scan_ended instead of one
skill_loaded event per skill per prompt render. Mark PostHog events with
$process_person_profile=false (distinct_id is a throwaway session id, so
person profiles were never useful) and tag them with $lib/$lib_version.
This commit is contained in:
Ahmed Allam 2026-09-05 00:05:06 +00:00 committed by Ahmed Allam
parent 9cc9de8cdc
commit bb7e82b6ea
4 changed files with 22 additions and 28 deletions

View file

@ -8,7 +8,6 @@ from typing import TypeGuard
import yaml
from strix.telemetry import posthog, scarf
from strix.utils.resource_paths import get_strix_resource_path
@ -241,16 +240,22 @@ def validate_requested_skills(skill_list: list[str], max_skills: int = 5) -> str
return None
_LOADED_SKILLS: set[str] = set()
_LOADED_SKILLS_LOCK = threading.Lock()
def _track_skill_loaded(skill_name: str, file_path: Path) -> None:
builtin = get_strix_resource_path("skills")
if not file_path.is_relative_to(builtin):
skill_name = "custom"
with _LOADED_SKILLS_LOCK:
_LOADED_SKILLS.add(skill_name)
def _send() -> None:
posthog.skill_loaded(skill_name)
scarf.skill_loaded(skill_name)
threading.Thread(target=_send, daemon=True).start()
def get_loaded_skill_names() -> list[str]:
"""Distinct skills loaded so far in this process (custom skills collapse to ``"custom"``)."""
with _LOADED_SKILLS_LOCK:
return sorted(_LOADED_SKILLS)
def _candidate_skill_files(skill_name: str) -> list[Path]:

View file

@ -16,7 +16,7 @@ We collect only very **basic** usage data including:
**System Context:** OS type, architecture, Strix version\
**Scan Context:** Scan mode (quick/standard/deep), scan type (whitebox/blackbox)\
**Model Usage:** Which LLM model is being used and whether it runs via an API key or a model subscription (not prompts or responses)\
**Feature Usage:** Which built-in skills are loaded\
**Feature Usage:** Which built-in skills were used during a scan (reported once, at scan end)\
**Aggregate Metrics:** Vulnerability counts by severity and weakness category (CWE)
### What We **Never** Collect

View file

@ -4,10 +4,12 @@ from typing import TYPE_CHECKING, Any
import requests
from strix.config import load_settings
from strix.skills import get_loaded_skill_names
from strix.telemetry._common import (
SEND_TIMEOUT,
SESSION_ID,
base_props,
get_version,
is_first_run,
)
@ -35,7 +37,12 @@ def _send(event: str, properties: dict[str, Any]) -> bool:
"api_key": _POSTHOG_PUBLIC_API_KEY,
"event": event,
"distinct_id": SESSION_ID,
"properties": properties,
"properties": {
**properties,
"$lib": "strix-cli",
"$lib_version": get_version(),
"$process_person_profile": False,
},
}
with requests.post(f"{_POSTHOG_HOST}/capture/", json=payload, timeout=SEND_TIMEOUT):
pass
@ -82,16 +89,6 @@ def finding(severity: str, cwe: str | None = None, is_cve: bool = False) -> None
)
def skill_loaded(skill_name: str) -> None:
_send(
"skill_loaded",
{
**base_props(),
"skill": skill_name,
},
)
def end(report_state: "ReportState", exit_reason: str = "completed") -> None:
if report_state.posthog_scan_ended_sent:
return
@ -130,6 +127,7 @@ def end(report_state: "ReportState", exit_reason: str = "completed") -> None:
"vulnerabilities_total": len(report_state.vulnerability_reports),
**{f"vulnerabilities_{k}": v for k, v in vulnerabilities_counts.items()},
**llm_props,
"skills": get_loaded_skill_names(),
},
)

View file

@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, Any
import requests
from strix.config import load_settings
from strix.skills import get_loaded_skill_names
from strix.telemetry._common import (
SEND_TIMEOUT,
SESSION_ID,
@ -90,17 +91,6 @@ def finding(severity: str, cwe: str | None = None, is_cve: bool = False) -> None
)
def skill_loaded(skill_name: str) -> None:
_send(
"skill_loaded",
{
**base_props(),
"session": SESSION_ID,
"skill": skill_name,
},
)
def end(report_state: ReportState, exit_reason: str = "completed") -> None:
if report_state.scarf_scan_ended_sent:
return
@ -140,6 +130,7 @@ def end(report_state: ReportState, exit_reason: str = "completed") -> None:
"vulnerabilities_total": len(report_state.vulnerability_reports),
**{f"vulnerabilities_{k}": v for k, v in vulnerabilities_counts.items()},
**llm_props,
"skills": ",".join(get_loaded_skill_names()),
},
)