infer-insights
Infer Insights — Automated Discovery
Update Check (non-blocking)
Run this at the start. It checks if an update is available using a 6-hour cache so it doesn't hit npm on every invocation:
_INFER_CACHE=~/.infer/last-update-check.json
_NEEDS_CHECK="yes"
# Skip check if cache is fresh (less than 6 hours old)
if [ -f "$_INFER_CACHE" ]; then
_CACHE_AGE=$(( $(date +%s) - $(stat -f '%m' "$_INFER_CACHE" 2>/dev/null || stat -c '%Y' "$_INFER_CACHE" 2>/dev/null || echo 0) ))
[ "$_CACHE_AGE" -lt 21600 ] && _NEEDS_CHECK="no"
fi
if [ "$_NEEDS_CHECK" = "yes" ]; then
_SDK_LATEST=$(npm view @inferevents/sdk version 2>/dev/null || echo "unknown")
_MCP_LATEST=$(npm view @inferevents/mcp version 2>/dev/null || echo "unknown")
_SDK_INSTALLED=$(npm ls @inferevents/sdk --json 2>/dev/null | grep '"version"' | head -1 | sed 's/[^0-9.]//g' || echo "none")
mkdir -p ~/.infer
echo "{\"checked\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"sdk_latest\":\"$_SDK_LATEST\",\"mcp_latest\":\"$_MCP_LATEST\",\"sdk_installed\":\"$_SDK_INSTALLED\"}" > "$_INFER_CACHE"
echo "INFER_SDK_INSTALLED=$_SDK_INSTALLED INFER_SDK_LATEST=$_SDK_LATEST INFER_MCP_LATEST=$_MCP_LATEST"
else
cat "$_INFER_CACHE"
echo "INFER_CHECK=cached"
fi
If installed SDK version differs from latest, append this line at the END of your response:
Infer update available — run /infer-upgrade to get the latest.
Do NOT block or interrupt the workflow. Continue normally.
STEP ZERO: Always call get_insights first
Before running any manual queries, call get_insights() to check for pre-computed
anomalies and notable patterns. The Infer backend detects these automatically every hour.
If insights exist, present them first, then decide whether the manual query sequence
is still needed.
If get_insights returns "No new insights", proceed to the manual query sequence below.
If it returns findings, present them and only run additional queries if the user asks
for deeper analysis.
When invoked, you run a structured query sequence against the Infer MCP tools, score each finding by impact, and surface the top 5. No questions asked. Just insights.
The Query Sequence
You have 3 tools. Run these 7 queries in order. Each builds on what you learn from the previous one.
Round 1: What's happening? (volume + trend)
Query 1 — Current activity
get_event_counts(event_name="page_view", time_range="last_7d")
This tells you: is anyone using the app at all? If zero, stop and say "No events recorded in the last 7 days. Either no users visited, or the SDK isn't set up correctly."
Query 2 — Core action volume
get_event_counts(event_name="signup", time_range="last_7d")
Then repeat for other likely core events: "purchase", "create", "submit",
"invite", "complete". Use the event names you learned from the app's SDK
integration (check src/lib/analytics.ts or similar). If you don't know
the event names, try the common auto-tracked ones: "page_view", "session_start",
"click", "form_submit", "error".
Query 3 — Previous period comparison Run the same queries from Q1 and Q2 but with the PREVIOUS 7 days:
get_event_counts(event_name="page_view", time_range={"start": "14 days ago ISO", "end": "7 days ago ISO"})
Calculate week-over-week change: ((current - previous) / previous) * 100
Round 2: Are users sticking? (retention)
Query 4 — Weekly retention
get_retention(start_event="signup", return_event="page_view", time_range="last_30d", granularity="week")
If "signup" returns empty, try "session_start" as the start event. This is the most important query. Retention is the single best proxy for product-market fit.
Query 5 — Activation check
get_event_counts(event_name="<core_action>", time_range="last_30d")
Compare to signup count in the same period. The ratio is your activation rate. activation_rate = core_action_users / signup_users
Round 3: What's broken? (errors + friction)
Query 6 — Error volume
get_event_counts(event_name="error", time_range="last_7d")
If count > 0, this is always worth surfacing. Errors are silent killers.
Query 7 — Churned user investigation Pick 2-3 users from the retention data who signed up but didn't return.
get_user_journey(user_id="<churned_user>", limit=30)
Look for: where did their journey end? What was the last thing they did? Did they hit an error? Did they bounce after one page?
Scoring Each Finding
After running the queries, you'll have raw data. Score each finding:
Impact Score = Surprise x Leverage x Confidence
Surprise (1-5): How unexpected is this?
- 5: Completely unexpected (retention dropped 50% overnight)
- 3: Notable but not shocking (signup rate up 20%)
- 1: Expected / normal fluctuation
Leverage (1-5): Can someone act on this?
- 5: Clear action ("users who complete onboarding retain 3x better" → improve onboarding)
- 3: Directional ("traffic is growing" → keep doing what you're doing)
- 1: Informational only ("most users are on Chrome")
Confidence (1-5): Is the data solid?
- 5: Large sample (>100 users), consistent pattern
- 3: Medium sample (30-100), clear signal
- 1: Small sample (<30), noisy data
Multiply: Impact = Surprise x Leverage x Confidence. Rank. Take top 5.
Presenting Tool Output
CRITICAL: Do NOT reformat MCP tool results into markdown tables. The Infer tools return pre-formatted text with Unicode bar charts (█░), sparklines (▁▂▃▅▆█), and structured layouts designed for terminal readability. Always include the tool's formatted output verbatim, then add your interpretation below it.
Bad (don't do this):
| Event | Count | Users |
|-------|-------|-------|
| page_view | 9 | 6 |
Good (do this):
page_view ████████████████████ 8,420 (57%)
click ████████████░░░░░░░░ 3,210 (22%)
The bar charts, sparklines, and visual formatting ARE the product. Preserve them.
Output Format
Present insights in this exact format:
## Infer Insights — [Date]
**Data window:** [time range] | **Total events:** [N]
[Include raw tool output with bar charts here]
### 1. [Headline — the insight in one sentence]
**Impact: [score]/125** | Surprise: [N] | Leverage: [N] | Confidence: [N]
[2-3 sentences explaining what you found, what it means, and the suggested action.]
### 2. [Next insight]
...
### 3-5. [Remaining insights]
...
---
**Next check:** [When the next automated run is scheduled, if applicable]
**Deep dive:** Ask me to investigate any of these further.
Insight Categories (what to look for)
Always check these (every run):
- Volume trend: Are page views / signups / core actions up or down vs last period?
- Retention health: What's week-1 and week-4 retention? Compare to benchmarks.
- Error rate: Any errors? Trending up or down?
Surface these when detected:
- Activation gap: Lots of signups but few core actions = broken onboarding
- Leaky bucket: Growing signups but declining retention = acquiring users faster than keeping them
- Power user pattern: Churned users vs retained users did different things in session 1
- Concentration risk: 80%+ of activity from one source/country/segment
- Silent failure: Errors spiking but no one noticed (because there's no dashboard)
Never surface these as insights:
- Raw numbers without interpretation ("You had 1,247 page views")
- Vanity metrics ("Total events is up!")
- Findings with N < 10 (too noisy to be useful)
- Obvious statements ("Most users visit the homepage first")
Interpretation References
For retention benchmarks, curve shape analysis, and framing guidance,
read the infer://skill resource. It has:
- B2C vs B2B retention benchmarks by week
- What retention curve shapes mean
- Small sample warnings
- How to frame findings for non-technical users
- What NOT to do (no causal claims, no small-sample extrapolation)
When You Don't Have Enough Data
If the app is new (< 7 days of data or < 50 total events):
## Infer Insights — [Date]
**Status:** Not enough data yet for meaningful insights.
**What I can tell you:**
- [N] total events recorded since [first event date]
- [N] unique users seen
- Events tracked: [list of event names found]
**What I need:**
- At least 7 days of data for trend analysis
- At least 50 users for retention analysis
- At least 30 users per cohort for reliable retention numbers
**Check back in [N] days.** I'll have something useful by then.
Automated Mode (via /schedule or /loop)
When triggered by a schedule, run the full query sequence silently. Only notify the user if:
- Any insight scores > 60/125 (high impact)
- Retention dropped > 10 percentage points vs previous period
- Error rate spiked > 2x vs previous period
- Zero events recorded (SDK may be broken)
For routine checks with no notable findings:
## Infer Pulse — [Date]
All clear. [N] events, [N] users, retention holding at [X%]. Nothing unusual.