analyzing-insights-across-teams
Analyze PostHog insights, dashboards, or teams beyond the current project by querying the prod Postgres replicas synced into the dogfood data warehouse (US…
npx skills add https://github.com/posthog/posthog --skill analyzing-insights-across-teamsAnalyzing insights across teams
system.* entity tables (e.g. system.insights) are scoped to the current project,
and the generic execute-sql guidance says other teams' data is inaccessible.
For the dogfood project (US project 2) that is not the whole story:
production Postgres tables are replicated into the project's data warehouse,
so cross-team entity metadata is queryable with posthog:execute-sql.
Do not stop at system.insights when the question spans teams.
This skill is deliberately repo-local (.agents/skills/): it documents PostHog's internal dogfood setup,
applies only to agents working in this repo, and must not move into the packaged products/*/skills/ bundle that ships to every team.
Synced tables
| Entity | US (prod-us) | EU (prod-eu) |
|---|---|---|
| Insights | postgres.posthog_dashboarditem | eu_postgres_posthog_dashboarditem |
| Dashboards | postgres.posthog_dashboard | eu_postgres_posthog_dashboard |
| Teams / projects | postgres.posthog_team | eu_postgres_posthog_team |
-
Underscore aliases (e.g.
postgres_posthog_dashboarditem) point at the same synced data. -
These are replicas of the Django tables in this repo (
posthog_dashboarditembacks theInsightmodel), so rows span every team;team_idis the scoping column. -
More prod tables than these are synced. Before concluding cross-team data is inaccessible, check the catalog:
SELECT table_name, description FROM system.information_schema.tables WHERE table_type = 'data_warehouse' AND table_name ILIKE '%postgres%'
Workflow
-
Confirm columns before projecting — synced schemas drift with the Django models:
SELECT column_name, data_type FROM system.information_schema.columns WHERE table_name = 'postgres.posthog_dashboarditem' -
Query with
posthog:execute-sql, filtering or grouping byteam_id. Example — most active teams by insights created in the last 30 days:SELECT team_id, count() AS insights_created FROM postgres.posthog_dashboarditem WHERE NOT deleted AND saved AND created_at >= now() - INTERVAL 30 DAY GROUP BY team_id ORDER BY insights_created DESC LIMIT 20Join
postgres.posthog_teamonid = team_idfor team names only when the output stays on an internal surface (see below). -
Remember the sync lag: these are periodic replicas, not live reads — fine for analysis, not for "right now" state.
Output handling (required)
Rows in these tables are customer data: team names, insight names, descriptions, and queries.
- Never put customer team names, insight titles, or other row-level metadata on public surfaces — PR titles/descriptions, commit messages, issues, code comments, or uploaded screenshots. Aggregates and
team_id-level figures without names are the ceiling for public copy. - Keep named results in the private conversation, internal docs, or auth-gated links.
- Access is gated by membership in the internal dogfood project. If a query fails with a permissions error, report it and stop — do not look for another route to cross-team data.
Related
- For cross-team event/analytics data (not entity metadata), see the
query-clickhouse-via-metabaseskill instead.