Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Diagnoses the health of a project's PostHog SDK integrations — which SDKs are up to date, which are outdated, and what to do about it. Use when a user asks about PostHog SDK versions, outdated SDKs, upgrade recommendations, \"SDK health\", \"SDK doctor\" (the former name), or when events or features seem off and it might be due to using an old SDK.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-21 | ✗→✓ | ▲ Improved | 151% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 93% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 137% | 0% |
| case-23 | ✗→✓ | ▲ Improved | 109% | 0% |
| case-24 | ✗→✓ | ▲ Improved | 64% | 0% |
When a user asks about PostHog SDK versions, outdated SDKs, or whether they should upgrade, use the pre-digested SDK Health report rather than reasoning about versions yourself. The backend applies smart-semver rules (grace periods, minor-count thresholds, age-based detection), traffic-percentage thresholds, and provides user-facing copy that matches the SDK Health UI exactly.
| Tool | Purpose | | ------------------------ | ---------------------------------------------------------------------------------------------------- | | posthog:sdk-health-get | Returns a structured health report plus UI-matching copy and drill-in URLs per SDK/version. | | posthog:execute-sql | (Optional) Run a sql_query from the report to show events captured by a specific outdated version. |
jsonposthog:sdk-health-get {}
Pass force_refresh: true only when the user explicitly asks for fresh data — by default the report uses a Redis cache that's refreshed every 12 hours.
json{ "overall_health": "healthy" | "needs_attention", "health": "success" | "warning" | "danger", "needs_updating_count": 0, "team_sdk_count": 0, "sdks": [ /* per-SDK assessments */ ] }
Lead with the headline:
overall_health: healthy — everything's current; say so and stop.health: warning — some SDKs outdated but less than half of the project's SDKs. Flagas upgrade recommendations.
health: danger — majority of team SDKs are outdated. Treat as urgent.Each SDK's banners array contains zero or more sentences that match the SDK Health UI's "Time for an update!" alert exactly, e.g.:
> Version 7.0.0 of the Python SDK has captured more than 10% of events in the last 7 days.
Quote these verbatim. They're what the user already sees (or would see) in the UI — rewording creates drift between agent and product copy.
For each entry in sdks, surface:
readable_name (e.g. Python, Node.js, Web) — use this in prose, not the raw liblatest_versionseverity (none / warning / danger) — use this to group or color findingsGroup by severity (danger first, then warning, then none). Skip SDKs with needs_updating: false unless the user explicitly asked about the full state.
Each SDK's releases array has per-version rows. Each row includes UI-matching copy and ready-to-use links:
status_reason — badge tooltip text that closely matches the UI. Quote directly.Caveat: the relative-age segment ("5 months ago" etc.) is computed with Python's humanize.naturaltime on the backend and JavaScript's dayjs().fromNow() in the browser, and the two libraries have different thresholds at some boundaries (e.g. humanize says "30 days ago" where dayjs says "a month ago"; humanize says "4 months ago" at 148 days where dayjs says "5 months ago"). The overall template is identical; the age phrasing may be one threshold off. If a user cites an exact age from the UI that doesn't match, don't "correct" them — the UI is showing dayjs output and both are internally consistent.
released_ago — human-readable relative age (e.g. "5 months ago") — samehumanize-vs-dayjs caveat as above.
is_outdated, is_old, is_current_or_newer — booleans if you need to branchsql_query — complete SQL statement to see the last 50 events captured by this version.Suggest it as a copy-paste snippet OR pass it to posthog:execute-sql to drill in.
activity_page_url — relative path (starts with /project/<id>/) to the Activity >Explore page pre-filtered to this lib + version. Combine with the user's PostHog host (e.g. us.posthog.com) for a clickable link.
Always close with a link to the SDK Health page: /project/<project_id>/health/sdk-health. The UI shows per-row event counts, last-event timestamps, release notes, and SDK docs links — more than the tool response includes.
The backend applies these rules (you don't need to re-check them):
flagged, even if major versions behind.
> 24 weeks old (mobile is more lenient — users don't auto-update apps).
surfaces as a traffic alert even if a newer version is also in use. Mobile SDKs are excluded from traffic alerts.
danger when half or more of the project's SDKs are outdated,warning when some are outdated but not majority.
These response fields are user-facing UI copy — quote them verbatim, don't reword:
banners[] — top-level "Time for an update!" alert text. Byte-for-byte match with UI.releases[].status_reason — per-version badge tooltip text. Template matches the UI,but the relative-age phrasing ("5 months ago" etc.) can be one boundary threshold off because the backend uses humanize and the UI uses dayjs. See Step 5 caveat.
readable_name — human-readable SDK name. Byte-for-byte match with UI.reason (per-SDK) is a programmatic summary meant for ranking/filtering, not for quoting to users. Prefer banners[] and status_reason for user-visible output.
If sql_query or activity_page_url comes back as an empty string for a particular release, the backend sanitizer rejected the lib_version as potentially unsafe to interpolate (e.g. it contained quote characters or whitespace). When this happens:
interpolate into a query, so I can't build a drill-in link for it." This is a signal worth noting (it could indicate instrumentation tampering or a library bug).
that into posthog:execute-sql. That would defeat the sanitizer.
Similarly, if you pass sql_query to posthog:execute-sql and it errors, surface the error verbatim rather than rewriting the query. The query template is a verbatim mirror of what the SDK Health UI uses — if the UI's SQL wouldn't run, something else is wrong.
Do not wrap, truncate, or modify sql_query in any way before passing to posthog:execute-sql. No SELECT * FROM (<sql_query>) LIMIT 10, no adding WHERE clauses, no changing the ORDER BY, no dropping columns. The query is the verbatim mirror — if you need something different, build a fresh query from scratch with the user's help, don't derive it from sql_query.
When the user expresses confusion about an old SDK version still producing events after they believed it was updated — phrasings like "I thought I updated", "we already upgraded", "we deployed the new version but…", "why are users still on the old SDK?", or any variation of "why isn't it gone?" — do not improvise a list of causes. Point them to the canonical docs page instead:
https://posthog.com/docs/sdk-doctor/keeping-sdks-current
That page is the product team's source of truth on why versions persist (HTML snippet pinning, lockfiles in separate apps, CDN or browser caching, service workers, build/deploy issues) and what to do about each one (auto vs. manual update paths per SDK). It has diagrams, product-specific language, and will stay up to date as the guidance evolves — your improvised version will drift.
Suggested response shape:
> That's a common question with a few possible causes — cached bundles, pinned snippet > versions, lockfiles in separate apps, service workers, build/deploy issues, etc. > Rather than guess which one's biting you, have a look at > Keeping SDKs current — > it walks through each cause and the fix. Once you've skimmed it, I can help you narrow > it down for your setup (e.g. by pulling the activity events for the outdated version > to see whether it's one app/domain/subpath or spread across everything).
The trigger is intent, not content. Defer whenever the user expresses surprise or confusion about persistence ("still", "thought I updated", "why haven't users upgraded", "why is the old one still there"), even when the tool response technically contains the version's age, reason, or traffic breakdown. The docs page exists because the literal data doesn't answer _why_, just _what_.
Do not send the user to the docs page when:
is_oldmean?" or "how is severity calculated?" — answer directly using the report fields or the "Interpreting severity" rules below.
pull it via the report or posthog:execute-sql and present it.
directly or pull data to help narrow things down.
team_sdk_count is 0, the project isn't sending events with SDK metadata. Suggestchecking that posthog-js (or another SDK) is actually installed and capturing events.
once per project (after switching project context via posthog:switch-project).
ordered from most to least interactive:
activity_page_url — user explores in PostHog UI.sql_query to posthog:execute-sql and summarize the result inline.sql_query as a copy-paste snippet.When you offer to open activity_page_url or run sql_query, describe what the user will see in terms of the SDK being old, not the page or person. The data is about the customer's end-users' events captured while an old SDK is loaded — the old thing is the SDK, not the page or person.
pages on your site are still loading it, and which end-users are hitting them?"
who's generating events from them."
run SDK versions; visitors of pages do. This phrasing makes the user think the old thing is the page or the person, which is wrong.
these; the customer's deployed app/site does. For mobile SDKs (posthog-ios, posthog-android, posthog-flutter, posthog-react-native), though, "users who haven't updated the app" IS accurate — the SDK ships embedded in the app binary and users control the update by updating the app. So the rule flips for mobile: phrasings like "end-users still running an older app version" or "users who haven't updated to the latest release" are correct for mobile drill-ins.
Other measured skills in the registry, with their headline benchmark lift.