Ask anything about your product, or jump to a page.
Everything Irv has shipped, in reverse chronological order. Most entries trace back to a single PR that introduced the feature, with the LinkedIn-quality summary you might have read about.
Researched the field (classic statistics through HuggingFace-hosted time-series foundation models) and landed on a well-established, zero-cost technique: alongside the existing 3σ rule, every anomaly check now also runs a double MAD robust/asymmetric gate — a median-based scale estimate computed separately for each tail. It fixes two real failure modes: masking (one huge spike inflates the old threshold enough to hide a second, smaller-but-real anomaly) and skew (count-like series such as commits or orders can't go negative, so one symmetric threshold is wrong on one side). Additive only — nothing the old rule caught stops being caught, and the causation page now labels the specific anomalies the classic rule alone would have missed.
The Shopify template's Phase 1 connector: a merchant creates orders/create, orders/paid, and refunds/create webhooks manually in Shopify admin (Settings → Notifications), pastes the shop's webhook signing secret + domain into a new Shopify Orders settings card, and revenue becomes first-party and HMAC-verified — no ad-blocker exposure, no app to install, a near-exact clone of the Stripe connector. Only order id, status, amount, currency, and email are ever stored; the rest of the order payload (address, phone, line items) is dropped at the door. The new shopify_orders source is registered with three series (revenue, order count, refunds) that compute correctly today but aren't yet read by the correlation/anomaly engine — widening that engine beyond its legacy 9 series is the deliberate next step.
Each anomaly on the causation page now has an investigate pill that drops it onto a canvas — a note callout with the magnitude (σ), the expected-vs-observed values, the Granger-ranked likeliest cause, and nearby project-log events, plus metric widgets for any web series involved. Same queue + canvas path as the existing send-to-canvas buttons, so the anomaly arrives with the math already laid out. This is the fourth and last surface in the engine-findings rollout (after the daily brief/podcast, daily email, and weekly narrative).
The weekly narrative's What didn't and Where to look next sections used to ask the model to infer anomalies from raw analytics — guesswork. They now read verified_cross_source_findings from the shared [engine-findings](/changelog#engine-findings-surfaces) provider: real >3σ STL anomalies (with dates + magnitude) and Granger-tested cross-source links. The prompt is told to ground those sections in measured findings and not fabricate anomalies the engine didn't surface. Same zero-AI-cost, self-warming path as the daily brief + email.
Irv's edge — the correlation/anomaly engine that finds links across data sources (commits → visitors with a 2-day lag, deploys → revenue) using lagged correlation + Granger causality + STL anomaly detection — used to live only on the causation page. Now one shared provider (lib/engine-findings.ts) feeds it into the surfaces you actually receive each morning: the daily brief (and therefore the podcast, which reads it aloud) gets the verified findings injected as facts to weave in, and the daily email gains an *"Across your sources"* section. Same numbers everywhere — no more each surface re-guessing a weaker version. It's zero added AI cost (the stats are pure math; correlation narration is skipped for these callers) and self-warming (recomputes only when stale). Because it reads the sources registry, every new source — Shopify orders next — lights up all these surfaces automatically.
A once-a-day email to the creator summarizing how Irv-the-business is running: data (visitors/pageviews/events today + 7d, active projects, users, waitlist, AI spend vs cap with the ⚠ alarm), shipped (PRs merged to main in the last 24h = the deploy signal), and open work (open PRs + issues). The data half runs off computePlatformStats() and works on day one; the GitHub half lights up when IRV_OPS_GITHUB_TOKEN is set, and degrades to a one-line note otherwise. Daily cron at 07:00 UTC, Bearer CRON_SECRET auth, idempotent per UTC day, sent to getCreatorEmails() via Resend. Distinct from the product's per-user daily digests — this one is for the founder. Deployments are approximated as merges-to-main; a true Vercel deploy feed is a documented follow-up.
Built the actual switch the abuse defences were waiting for. IRV_OPEN_SIGNUP=1 (lib/signup-mode.ts) turns /waitlist — the single chokepoint every 'Join the beta' CTA points to — into a redirect to the new public /sign-up page, which renders a Clerk SignUpButton straight into onboarding. No invite code. While the flag is unset (the default), /sign-up bounces back to the waitlist, so there's still no public sign-up until you flip it. Read per-request (force-dynamic), so the flip needs no code change — set IRV_OPEN_SIGNUP=1 and IRV_REQUIRE_PHONE_VERIFY=1 together (the human gate) and the doors are open, with the per-user $2 AI cap + per-IP throttle holding the line. Existing /access invite codes keep working.
Added a single compact callout to the homepage — 'Running a Shopify store? Irv reads your whole funnel from one Custom Pixel, no app' — linking to /shopify. Deliberately *not* a 'templates' section: only Web (default) and Shopify are real today, so the page names the one live vertical and nothing that isn't built yet. Same minimal.so idiom as the rest of the page (hairline divider, big type, a text-link with an arrow), slotted between 'How it works' and the close.
Two server-side guards that make it safe to drop the waitlist and let anyone sign up, layered on the per-user $2/month AI cap. (1) The verified-phone gate (IRV_REQUIRE_PHONE_VERIFY) now covers project creation, not just token-minting — so every account costs an attacker a unique phone number; onboarding catches the 403 and routes to phone verification. (2) A per-IP throttle caps new projects per IP per hour (IRV_PROJECTS_PER_IP_HOUR, default 10) as defence-in-depth against a single-IP farm. Both are inert during the beta (phone gate permissive while the flag is unset; 10/IP/hour never bites a real user). The one consequential step — flipping public sign-up on — is deliberately left for a human; the checklist is in docs/features/open-signup-defenses.md.
Fixed a silent killer for real Shopify stores: onboarding seeded allowed_origins from the store URL you type, but Shopify's Custom Pixel runs in a sandboxed origin (not the storefront domain), so ingest would have rejected every event with origin_not_allowed — an empty dashboard with no error. Shopify-type projects are now created with an open origin allowlist (the pk_live key is public + write-only, the same trust model as the web snippet), so a merchant's pixel works the moment it's pasted. The onboarding note no longer claims a non-existent origin lock. Web projects are unchanged — they still auto-lock to their domain.
A dedicated marketing page at /shopify for store owners, in the same minimal.so design as the homepage but with store-specific, non-developer copy: paste one Custom Pixel (no app), get a plain-English morning report — what sold, where you're losing sales, the one thing to fix today. Three-step setup, six store-focused features (sales each morning, where shoppers drop, best/worst sellers, ask anything, breakage alerts, what-changed), and a Shopify-flavoured sample brief. Pairs with the Shopify template (the pixel + mapping + test-kit).
The Shopify template is now a one-click choice in the setup wizard. A new merchant signs in, picks Shopify store on the first screen (next to the Lovable/v0/Cursor builders), pastes their store URL, and gets the Custom Pixel — their real project key already baked in — with the exact Settings → Customer events steps. No JS snippet, no GitHub step (a store has no repo to patch); the live-event verifier still flips green the moment the first storefront event lands. Projects now carry an additive type field ("shopify", default "web") so the dashboard knows which taxonomy it's reading — the core ingest/analytics engine is untouched. The pasteable pixel is generated by lib/shopify-pixel-source.ts, whose event mapping is verified byte-for-byte against the unit-tested lib/shopify-pixel.ts.
A Shopify merchant pastes one Custom Pixel (Settings → Customer events, no app) and Irv sees the full storefront → cart → checkout → purchase funnel, with revenue, in the dashboards Irv already has. It's the first 'customer-type template' from the e-commerce plan — and it's purely additive: the core ingest/analytics/insight engine is unchanged. The pixel subscribes to Shopify's standard events (incl. checkout_completed, which a theme script can't reach) and POSTs mapped events to the existing /api/v1/ingest (already CORS-enabled). Money is normalized to value_cents + currency like the Stripe connector. The mapping lives once in lib/shopify-pixel.ts (unit-tested), mirrored by the pasteable pixel and a self-contained tools/shopify-test-kit/ that replays a realistic Shopify session through the mapping into a real project and verifies it lands. Revenue aggregation (AOV/conversion/refund), the server-side Orders-webhook connector, and the e-commerce insight lens are documented next phases, deliberately not bolted into core.
New homepage (v4). Design, in the minimal.so idiom: a left-aligned hero with a huge, tight headline; pill buttons (black primary + a plain text-link secondary with an arrow); monochrome chrome, hairline dividers, lots of whitespace. Content, cut hard and rewritten for non-developers — the page is a headline, ONE real morning-brief shot (the thing Irv actually makes), a brief feature grid (morning brief, Ask Irv, Autoheal, tracking gaps, Canvas, change tracking), a short plain-English 'how it works' (watches → analyses with significance tests + correlations → explains), and a close. ~75% shorter than the old homepage; the demo carousel, surface tour, and developer sections (SDK / MCP / CLI / agents) are gone. v3 is kept for one-line revert (swap the import in app/page.tsx).
Opening Irv on a phone now gives a real mobile experience instead of a shrunk-to-fit desktop page. A proper viewport meta tag makes the app render at device width (readable text, no horizontal overflow). The top nav collapses into a hamburger drawer — brand, search, and avatar stay in the bar; nav links + account actions slide in from the side. Detection is two-layered: responsive CSS as the backbone plus server-side user-agent detection (lib/device.ts) for decisions CSS can't make — so Canvas, the drag-and-drop investigation workspace, isn't mounted at all on a phone; it shows a tidy 'best on desktop' card and drops out of the mobile nav. Scope is the read-first flow (project list → dashboard → daily brief → log); Canvas and other pointer-heavy editors stay desktop-only by design. The security-critical proxy.ts was left untouched — detection lives in component-level header reads on the already-dynamic app pages.
Wired up the path to charge: subscriptions run on Clerk Billing (built on Stripe, native to the Clerk auth we already use). New /app/billing page renders Clerk's <PricingTable />, and a plan now maps to one product effect — the per-user monthly AI budget it lifts (Free $2 → Pro $15, both env-tunable). runAICall resolves the cap live from the user's subscription via auth().has({ plan }), so an upgrade takes effect immediately with no entitlement store or webhook sync. It's inert until configured: with no plans in the Clerk dashboard, everyone stays Free and nothing charges — the only remaining steps are the dashboard ones (npx clerk enable billing --for users, create the pro plan, connect Stripe), documented in docs/features/billing.md. The public /pricing page stays beta-free until you flip it. BYOK remains unmetered on any plan.
Added a fourth cost-control layer: a hard $2/user/month cap on platform-paid AI, summed across ALL of a user's projects (IRV_USER_USD_CAP, default $2). Until now spend was bounded per-project ($15) and platform-wide ($200), but nothing capped a single *account* — so opening sign-up to everyone risked one person (or a script) spinning up many projects to multiply cost. Now any user-attributed AI call checks the per-user month-to-date spend first and returns 402 with a clear 'resets next month, or bring your own key' message once they cross $2. Cron surfaces (daily brief, weekly narrative) run without a user and stay under the per-project cap; BYOK calls are exempt (their bill). Enforced in the runAICall gateway before any Anthropic request, so a tripped cap costs $0.
On Vercel a function instance freezes the moment its response returns, so void-fired promises started after the response are silently dropped — the same failure mode that briefly killed webhook deliveries (fixed in the earlier closed-loop work). A sweep found more of the pattern and fixed it: the GitHub push pipeline (re-analysis + LLM call), the PR-bot comment, the auto-instrument PR, the manual re-analyze endpoint, and the repo-link flow now run inside after(); the AI spend ledger (lib/ai.ts) — which the per-project and platform cost caps count against — is now awaited so spend can't be undercounted; and the analytics daily-metrics write moved into after() (it claims an idempotency marker before writing, so a dropped write left a permanently-missing day). A new guard test fails CI if any heavy or correctness-critical helper is void-fired again.
Agents no longer poll. POST /api/v1/subscriptions registers a URL; Irv POSTs to it the moment a new critical insight or anomaly lands — HMAC-signed (X-Irv-Signature, same convention as GitHub webhooks), content-fingerprinted so re-refreshes don't re-fire, auto-disabled after 10 dead deliveries. Payloads carry the paste-ready lovable_prompt fix. On the act side, the MCP server gains its first write tool: mark_shipped records the fix, snapshots the cited metric, and starts the 7/14-day outcome clock (requires a write-scope token). The full circle is documented as recipe §9E in irv.dev/agents: subscribe → wake → fetch → ship fix → mark shipped → Irv measures the lift → agent reports what it actually moved. A self-healing app, with the human's role collapsed to reviewing the PR.
Three additions so agent signups don't land silently. New lib/agent-provisions.ts append-only log records each provision (agent_id, project_id, beta_key_label, contact_email, created_at) — last 100 rows kept. New lib/admin-notifications.ts fires a debounced email to creator emails on three events: agent applies, agent gets approved, agent provisions. Per-kind 10-minute debounce so a 50-event spike sends one email at t+0 saying '1 event' and another ~10 min later saying '47 since last batch'. Disable with IRV_AGENT_SIGNUP_NOTIFY=0. The /app/admin/agent-beta page gains a 24h counter chip + a 'Recent provisions' panel (last 20 rows, each linking to the provisioned project). /app/admin/waitlist gains '+N agents in 24h' chips in the header. All three layers fail independently — if Resend's down, the log + chips still work; if Redis hiccups on the log, email + chips still work.
Site footer gains a 'For agents' link to /agents (between Docs and Pricing — visible on every page). The /docs hub leads with a pinned callout above the TOC: 'If you're here on behalf of an AI agent, hand it irv.dev/agents instead'. The /agents URL itself was shipped earlier; this PR just makes it findable from anywhere in the marketing surface. The companion instant-try endpoint that was prototyped alongside this work was held back pending beta launch — see docs/features/agent-instant-try.md for the deferred design + threat model.
The comprehensive agent reference now lives at /agents (canonical, recitable in conversation) as well as /llms-full.txt (the llms.txt-convention alias). Same bytes, two URLs — both pull from src/lib/agent-reference.ts. The short /.well-known/llms.txt summary now directs agents to /agents first. A human can tell their Claude or Codex "go visit irv.dev/agents" and the agent has everything in one fetch: how to sign up (three paths), how to integrate, how to pull data, the error model, copy-paste recipes. The /docs/agents page now opens with a callout pointing humans at /agents for the agent-readable form.
Rewrote /llms-full.txt from a marketing-led structure to an agent-API-led one. The single fetch now covers: three sign-up paths (autonomous beta-key, hand-reviewed application, device-code), identity verify, project setup, three integration paths (snippet + npm + direct ingest), every read endpoint (freshness, live, sessions, analytics, insights, daily brief, weekly narrative, outcomes, causation, ask), error model with codes per status, four copy-paste agent recipes, alt transports (CLI + MCP), and the last 30 changelog entries. The short /.well-known/llms.txt now explicitly directs agents to /llms-full.txt as the primary read.
Closes the autonomy gap left by the agent application flow. POST /api/v1/agent-beta/provision takes a beta key (admin-minted at /app/admin/agent-beta, separate from PATs) and returns a synthetic agent identity, a fresh project + project_key, and a read+write PAT in one shot. No browser, no Clerk sign-up, no human in the loop. Companion /api/v1/projects/{id}/events-freshness?since=2m returns one number an agent can poll while verifying the snippet it just embedded is firing. Operator quickstart at /docs/agents/quickstart has copy-paste prompts for Codex CLI and Claude CLI — the agent can go provision → embed snippet → fire test event → verify → hand off in one continuous run.
A dedicated funnel for agent operators (Claude Desktop, Codex, custom workflows) to apply for Irv API access — separate from the human waitlist. Full intake form captures contact email, agent name, use case, scopes wanted, expected volume, and what built it. Admin sees agents in a new Humans/Agents toggle at /app/admin/waitlist with structured metadata at a glance. Approval sends an agent-flavoured invite email; on first /app/account visit a PAT is auto-minted with the requested scopes and surfaced once in a banner — operator copies it, wires it up, done. Companion changes: monochromatic light theme — orange + amber tokens dropped sitewide.
Status filter chips compose with a debounced search box (matches email + the "what are you building" field, case-insensitive). 20 entries per page with a "1-20 of N" indicator. Per-row trash icon, confirm before firing — cleans every secondary index in one Upstash pipeline. The list stopped scrolling well around 30 signups; now scales cleanly.
Two halves of the same problem. Bot-attractive moments (PAT mint + device-code approve) gate behind a verified phone when IRV_REQUIRE_PHONE_VERIFY=1 — using Clerk's native phone factor, no Twilio plumbing on our side. Default off; flip when abuse appears. Companion: @irv/agent-tests, an end-to-end suite where a real Claude agent drives Irv's API via tools across 5 scenarios. Catches integration bugs unit tests can't.
The old test-mode page asked you to read a test, switch tabs, navigate to the surface, come back, mark status. Most tests are *about* a page so it didn't work. New flow: pick a project, click Start on any row, app navigates to the right page, a floating banner rides along with Pass / Fail / Skip / N/A buttons + a note field, Done returns to the overview. 45 of 50 test items have navigable destinations.
Irv is now usable by any agent — Claude (API or Desktop), Codex, OpenAI function-calling, n8n, custom Node — not just MCP-aware clients. Mint a Personal Access Token at /app/account, pick scopes (read / write / admin), use the same token over both /api/mcp and /api/v1/*. New /api/v1/me, /api/openapi.json, /.well-known/llms.txt, and /docs/agents with code samples. Plus a full OAuth-style device-code flow at /api/v1/auth/device — agent shows you a code, you visit /device, click Approve, agent has a token. Same pattern as GitHub / Vercel CLI auth.
Zoom floor was 30% — too tight to see boards with widgets pushed into the corners. Now 10%. New Maximize button in the toolbar (also press F) computes the bounding box of every widget and zooms to show them all with a 40 px margin. Pure fitToContent() helper with 7 unit tests.
The daily cron diffs the freshly-computed signals against the prior run, emails every creator address when a new severity ≥4 signal appears (cluster, spike, trend). Re-running the cron same day doesn't re-alert because the (feature, signal_type) keys haven't changed. Gated by feedback-signals:alert-emails, default off. Closes the loop — the panel stops needing to be checked.
Three layers on top of the per-feature ? chip. (1) Generic feature-flag system controls who sees each chip — creator / members / all / off — default creator so nothing leaks. (2) A daily cron runs both heuristic (cluster ≥3, spike ≥2.5×) and LLM passes over the feedback corpus, surfaces signals at the top of /app/admin/feedback. (3) /app/help/feedback user-facing explainer + first-time coachmark next to the first chip you see.
Two surfaces for the same loop. Creator-only /app/test-mode walks every shipped feature methodically — ~50 items grouped into 6 passes, Pass / Fail / Skip / N/A, notes, filter chips, markdown export. State persists per-user in Upstash. Companion: tiny ? <FeedbackChip feature="..."> next to every feature headline. Tap → popover with Works / Broken / Confusing → submits to the admin inbox tagged with the feature. Catches passive feedback you'd otherwise just think to yourself.
Same partial-JSON streaming pattern as the daily brief, applied to the Magic Wand canvas analysis. Select 2+ widgets → Analyze. Toolbar progress pill appears immediately; the title drops in ~500 ms; the summary widget materialises on complete. No more 5-10 s of staring at a spinner.
Regenerating the brief used to mean ~5-10 s of waiting for the whole thing. Now uses Anthropic's stream: true + input_json_delta events + partial-json over the accumulating buffer to emit each section as soon as the model has "moved on" (the field is followed by structural punctuation). The headline appears in ~500 ms; sections drop in as they parse. Same six-section structure, same voice rules.
Added Anthropic's cache_control: ephemeral to the system prompts on the four uncached surfaces (canvas chat, ask Irv, magic wand, weekly narrative — daily brief + insights were already cached). Repeat calls within the 5-min TTL hit the cache for ~80 % off the input-token cost. A meaningful spend reduction at zero UX cost.
Every user-visible feature now has a docs/features/<slug>.md that describes what it is *today* plus a ## Changelog section with newest-first entries (YYYY-MM-DD · #PR · one-sentence description.). When a PR ships a change that touches a feature, the discipline is: append an entry to that feature's doc before merging. Future collaborators (human or agent) can open any feature doc and see both current state and how it got there.
Open a canvas in two windows: the other person's cursor appears with a name pill + colour. Drag a widget, they see it move in real time. Shift-drag to connect, the interpretation appears in both windows at once. Delete a widget, the connections touching it vanish atomically for everyone. Backed by a Liveblocks-hosted LiveList + Storage room per canvas. Plus a per-canvas chat thread with Irv as a co-author — AI tool calls (add_widget, connect, remember) mutate the shared canvas, every peer sees the changes.
37 owner-checks across 29 files migrated from literal owner_user_id !== userId to requireProjectMember / requireProjectMemberPage. Projects now carry an owner_org_id; any member of the org gets full access. Invite teammates from /app/team — Clerk handles roles + the invite email. Legacy single-owner projects still work; the migration script backfills as orgs are enabled. Solo users see no change.
Three small things that add up. Canvas-chat error messages are now sanitised server-side so SDK error details never persist in the shared LiveList. Dashboard poll dropped from 5 s → 30 s (6× fewer requests per open tab; data doesn't move on a 5 s timescale). Resend now returns a structured success/failure result instead of null — the admin health page can finally distinguish "not configured" from "API rejected the key".
Same data as the email brief, different surface. Each morning Irv renders a ~60-second MP3 narrated by OpenAI's gpt-4o-mini-tts. Three style presets per project — calm (NPR Daily feel), energetic (morning-radio host, default), punchy (sports-radio momentum). Read-along transcript on the dashboard. Subscribe to one project's feed or a single personal cross-project feed at /app/account — pastes into Apple Podcasts, Overcast, Pocket Casts. ~$0.015 per episode.
Every project dashboard (and /app/admin/self) now lists users who've called irv.identify(email). Each row: the country we saw on their first identify (sticky — a user who travels still shows where they signed up from), email or distinct_id, and a relative last-seen time. Demo + pk_irv show masked emails by default; the data owner sees the real addresses.
lucide-react (imported in 70+ files), recharts and @base-ui/react now barrel-rewrite via experimental.optimizePackageImports. @tanstack/react-query-devtools (~40 KB gzipped) gated behind a build-time NODE_ENV check so it DCE-eliminates from prod. @next/bundle-analyzer + shadcn (CLI) moved out of dependencies. The 919-line marketing landing page was marked "use client" for no reason — zero hooks, zero handlers — dropped the directive so the whole hero + four-act section + trust strip ships as server HTML.
An Upstash plan-limit overage took down every Redis-touching endpoint with an empty-body HTTP 500, including the public landing-page signup form. The waitlist endpoint now wraps its rate-limit check in try/catch (best-effort spam protection that fails open, not closed) and has an outer try/catch that returns proper JSON { error: "internal" } instead of an unhandled-exception 500. A small circuit-breaker for the other ~30 Redis-touching routes is the follow-up.
Clicking 'Refresh insights' on the dogfood dashboard was returning unknown_project_key because pk_irv has no row in the project store on purpose (it's a reserved key, sibling to pk_demo). Fix: synthesise a virtual Project at request time when the caller is the creator — lovable_url = https://www.irv.dev so the same HTML-grounded insights pipeline that runs against customer apps now runs against irv.dev itself. Project store is never written to; the synth is throwaway.
Single home for every creator-only surface — Platform stats, Waitlist, Feedback, AI cost — with a shielded Admin link in the top bar visible only to the creator email. Server-gated via isCreator(); non-creators are redirected to /app so the route doesn't even leak its existence.
Users were (rightly) complaining about the broad repo scope. New consent screen at /app/connect/github explains exactly what Irv uses GitHub for, then lets you pick Public repos only (public_repo, recommended for Lovable/Bolt/Replit apps) or All repos (repo, for private code). Per-repo GitHub-App installations are the next step.
Thumbnail-scale view of every widget on the canvas with a viewport rectangle showing what you're looking at. Click anywhere on the minimap to recenter. Useful once boards have 15+ widgets.
Per-canvas opt-in toggle. Flip on, get /canvas/<slug>. Read-only. Numbers frozen at share time so people see what you saw, not a moving target. The interpretation prose Irv wrote on each connection travels with the share.
Daily Brief gets an "Open on canvas" button (drops the whole brief — metrics + cohorts + priorities-as-notes — onto a fresh board). Per-priority pills on each "what moved" row. Change-effects rows get pills too. Top pages list batches the top 5 onto a fresh canvas. Causation correlation rows drop both metrics + the Pearson r as a note.
Toggle digests on at /app/account → demo email lands in your inbox immediately, with a yellow "this is a test" banner so you know the data isn't yours. Same renderer as the cron-triggered digest, so what you see is what you'll get. "Send test email" button stays available for re-sends.
Three starter investigations (Pricing, Signup deep-dive, Revenue cohort spread) — each materializes against your live analytics so connection labels are populated on first load. Magic Wand multi-selects widgets and writes an AI summary connected to all of them. Tidy button auto-layouts the board grouped by widget type.
New surface at /app/<id>/canvas. Drop metrics, pages, cohorts, commits onto a freeform board; shift + drag between two widgets and Irv writes the analytical interpretation onto the line. Pearson + p-value for metric × metric, cohort share for metric × cohort, page share for metric × page. Reuses the existing lib/stats engines — instant, deterministic, free.
Reframed as "AI tool that ships analytics for you" with three concrete acts (Morning Brief / PR bot / Ask Irv). Sub-hero strip pulls Dashboard / Claude Desktop / CLI / Email up front so the multi-surface story lands above the fold. v1 + v2 kept as ?v=1 / ?v=2 revert paths.
Opt-in toggle in project settings spins up /changelog/<slug> for any project. Auto-generated from your commits + shipped prompts paired with their measured metric impact. No manual posts to write.
The PR-review bot already detected new buttons / forms without nearby irv.track() and suggested the right event names. Now it goes the rest of the way: opens a companion PR with the actual code change patched in.
Three layers on top of the Phase 1 token split. PII redaction on ingest (emails / phones / SSNs / IPs). Per-project Origin allowlist for ingest. 1000 reqs/min sliding window per read token, token-scoped so leaked bots can't burn the owner's quota.
Pre-fix, the same pk_live_… key was both the SDK ingest token (visible in your customer's HTML) AND the dashboard read token. Now they're separate: ingest keys are write-only, read tokens (irv_read_…, SHA-256 hashed at rest) are required for every read endpoint. 9 endpoints locked.
Button next to the range picker. Ask in plain English ("why did /pricing bounce go up this week?"), get an answer with citations + a collapsible "how I checked" trace listing every analytics tool the LLM called. Multi-turn tool-use loop, ~$0.02-0.05 per question.
FDR-corrected proportion z-tests across every dimension × metric combination. Surfaces the segments where bounce / errors / 404s deviate from the global baseline ("mobile-Safari users on /pricing bounce 3x baseline, q=0.003"). Fed into the daily brief automatically.
Six sections: headline · tl;dr · what moved · ranked priorities (action / expected impact / why-now) · EOD watchpoints · continuity from yesterday. Generated daily, ~$0.05 per run. Voice rules enforced: specific, observation-vs-hypothesis discipline, no fluff.
No Ship-to-AI click required. Every commit, shipped prompt, and tracking-plan change gets the [-3d, +3d] before/after delta computed automatically. Verdicts: positive / negative / inconclusive (within ±5% noise). Confidence scales with magnitude × sample size.
Connect GitHub. Open a PR. Bot parses the diff, finds new buttons / forms without irv.track(), flags removed tracking calls, surfaces the page-traffic impact, links any past insights touching the same files. Updates the same comment on subsequent pushes.
Three weighted components: form coverage (40%) · declared events firing in last 30d (30%) · top-clicked elements matching tracked events (30%). Surfaces severity-sorted gaps with snake_case event-name suggestions. Updates on every push.
Every insight gets a 0-100 confidence badge — LLM-emitted, then deterministically recalibrated by hard evidence (commit_sha bumps +10, missing metric_refs −20, anomaly without metric_refs −25). Ranked top-3 candidates panel shows what was ruled out, not just what won.
Channel grouping (Direct / Search / Social / Email / Paid / Referral with regional Google TLDs and 25 social hosts), new-vs-returning split, 24-hour UTC heatmap, top-clicked element per page.
Five new SDK autocaptures: $form_submit (field counts only, never values), $click_outbound with destination host, $scroll_milestone at 25/50/75/100%, $error for sync + unhandled rejections, $page_not_found via heuristic + manual irv.notFound() API.
npm i -g irv-cli then irv stats --range=30d. Fourteen commands talking to the same MCP endpoint Claude Desktop uses. Read-only and stable across releases.
Add Irv as a Model Context Protocol server. Then ask Claude things like "what's the highest-priority fix on my SaaS this week?" and it calls Irv's tools to pull real numbers + return a tool-driven answer.
Visitors, prompts shipped, outcomes measured, top insights — opt-in, hour-of-day configurable per user. Sent via Resend.
Vercel Speed Insights tracks Core Web Vitals on the dashboard itself. @next/bundle-analyzer integrated for shipping leaner JS.