analytics-review — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited analytics-review (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Pull live data from PostHog and the project's database, compare against saved baselines in memory, and surface actionable insights.
funnel: PostHog funnel metrics onlyusage: Database message/usage volume onlyusers: Per-user activity breakdownsave: Save current snapshot as a new baseline to memoryLook for credentials in this order:
env | grep POSTHOG.envrc filesphx_ (personal API key, not the project key phc_)PostHog API base: https://us.i.posthog.com (US) or https://eu.i.posthog.com (EU)
server/.env or .env.local for DATABASE_DSN, DATABASE_URL, POSTGRES_URL, or SUPABASE_URLpostgresql://postgres:<password>@db.<project-ref>.supabase.co:5432/postgresuv run python3) with asyncpg to queryIf credentials are missing, ask the user.
Check the project's PostHog events doc (usually POSTHOG_EVENTS.md) or memory for the event architecture. This tells you which events exist, what properties they carry, and what funnels they power.
Use the HogQL query endpoint (legacy insight endpoints may be blocked):
curl -s 'https://us.i.posthog.com/api/projects/<PROJECT_ID>/query/' \
-H "Authorization: Bearer <POSTHOG_API_KEY>" \
-H 'Content-Type: application/json' \
-d '{"query": {"kind": "HogQLQuery", "query": "<HOGQL>"}}'1. Event counts by period — Compare current period vs previous baseline:
SELECT event, count() as cnt, count(DISTINCT person_id) as users,
multiIf(
toDate(timestamp) < toDate('SPLIT_DATE_1'), 'period_1',
toDate(timestamp) < toDate('SPLIT_DATE_2'), 'period_2',
'period_3'
) as period
FROM events
WHERE timestamp >= toDateTime('START_DATE')
AND event IN ('$pageview', 'cta_click', ... )
GROUP BY event, period
ORDER BY event, period2. Pageview breakdown by path:
SELECT properties.$pathname as path, count() as cnt, count(DISTINCT person_id) as users
FROM events
WHERE timestamp >= toDateTime('START_DATE') AND event = '$pageview'
GROUP BY path ORDER BY cnt DESC LIMIT 253. All custom events (to check what's firing):
SELECT event, count() as cnt
FROM events
WHERE timestamp >= toDateTime('START_DATE')
AND event NOT IN ('$pageview', '$pageleave', '$autocapture', '$feature_flag_called', '$web_vitals', '$identify', '$rageclick')
GROUP BY event ORDER BY cnt DESC LIMIT 30Query the project's database for:
Adapt queries to the project's schema. Common patterns:
-- Daily volume
SELECT DATE(created_at) as day, COUNT(*) as total, COUNT(DISTINCT user_id) as users
FROM <activity_table>
WHERE created_at >= '<START_DATE>'
GROUP BY DATE(created_at) ORDER BY day
-- Per-user breakdown
SELECT u.email, u.plan, u.status,
COUNT(*) FILTER (WHERE a.created_at < '<SPLIT>') as before,
COUNT(*) FILTER (WHERE a.created_at >= '<SPLIT>') as after,
MAX(a.created_at) as last_active
FROM <users_table> u
JOIN <activity_table> a ON a.user_id = u.id
GROUP BY u.email, u.plan, u.status
ORDER BY after DESCRun git log --oneline --since="<BASELINE_DATE>" --merges (or without --merges if no merge commits) to see what shipped since the last baseline. For each PR/commit that touched user-facing code:
This becomes the "what changed" context for interpreting metric movements. Structure as:
### Changes since last baseline
| Date | PR/Commit | Category | Summary |When comparing metrics, correlate timing: if a metric spiked on Mar 30 and PR #11 merged Mar 31, note the connection. Metric changes without a corresponding code change suggest external factors (marketing, organic growth, seasonality).
Check memory for previous analytics snapshots (files matching *analytics* or *baseline*). If a baseline exists:
If no baseline exists, this IS the baseline — note that in the output.
Always structure output as:
Focus on:
Specific actions the user can take based on the data.
If the user passes save argument, or if no baseline exists in memory:
<project>_analytics_<date>.md) with:Keep baselines concise — just the numbers needed for future comparison, not the full analysis.
count(DISTINCT person_id) gives unique users, count() gives total eventsuv run python3 with asyncpg in the server directoryPOSTHOG_EVENTS.md, read it first to understand the event architecture~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.