Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
335 commits
Select commit Hold shift + click to select a range
095a49a
fix(comments): tighten send to slack checks for ticket discussions (#…
CShine612 Nov 6, 2026
94e913a
feat(mcp): let agents send a discussion to slack after confirmation (…
CShine612 Nov 6, 2026
8a193aa
fix(ci): skip the master ecr publish role where cd is disabled (#130899)
gantoine Nov 6, 2026
fa21772
chore(authorization): report direct legacy permission checks (#129384)
ReeceJones Nov 6, 2026
83d6239
feat(workflows): record workflow tests that send real requests (#130743)
meikelmosby Nov 6, 2026
e51e5a4
chore(tasks): bump sandbox @posthog/agent to 2.4.315 (#130966)
scheduled-actions-posthog[bot] Nov 6, 2026
a4328de
docs(workflows): use projectToken in the iOS push setup snippet (#129…
turnipdabeets Nov 6, 2026
7302b47
chore(cdp): warn against storing blobs in the cyclotron database (#13…
meikelmosby Nov 6, 2026
33a95b4
fix(cdp): refuse email attachments until they leave the cyclotron dat…
meikelmosby Nov 6, 2026
e324652
fix(capture-logs): fold trailing +Inf histogram bounds on OTLP ingest…
frankh Nov 6, 2026
bb8ab19
feat(devex): add organization pages and tool actions to the admin con…
webjunkie Nov 6, 2026
0b0e687
feat(devex): add previews and live refresh to admin console tools (#1…
webjunkie Nov 6, 2026
bb568a6
fix(product-tours): gate the file-system type on the product flag (#1…
rubychilds Nov 6, 2026
849caf6
feat(devex): flag new admin save hooks and page overrides as workflow…
webjunkie Nov 6, 2026
27d6297
feat(signals): add a skill for managing self-driving spend (#124825)
annikaschmid Nov 6, 2026
6c5b543
chore(ci): read depot usage one request at a time in the weekly diges…
gantoine Nov 6, 2026
9256aa9
fix(deps): bump zstd to 0.13.4 and 0.14.3 (#129234)
frankh Nov 6, 2026
3572bbf
chore(ci): check rust formatting before restoring caches (#130478)
posthog[bot] Nov 6, 2026
9e784f6
chore(e2e): drop top-level specs that repeat a sibling or jest test (…
gantoine Nov 6, 2026
40134d4
fix(data-management): restrict media preview urls to export viewers (…
MattPua Nov 6, 2026
232d0d9
fix(stripe): treat an Organization API key as a non-retryable credent…
Gilbert09 Nov 6, 2026
2286a39
fix(integrations): show meta ads by its product name (#130946)
Gilbert09 Nov 6, 2026
2742cbc
feat(frontend): start the home content download at boot (#130857)
pauldambra Nov 6, 2026
53d34da
feat(slack-app): track failed steps on the workspace setup page (#130…
VojtechBartos Nov 6, 2026
a37cf3e
feat(logs): move logs and csp explain llm calls to the ai gateway (#1…
jonathanlab Nov 6, 2026
06b1714
chore(ci): narrow the desktop react doctor checkout (#128339)
posthog[bot] Nov 6, 2026
5bafe5e
fix(ingestion-control-plane): start changelog backups after the metri…
z0br0wn Nov 6, 2026
d12f1e0
fix(auth): show a support error when workflows refuses the login code…
meikelmosby Nov 6, 2026
e7ac425
chore(sql-editor): stabilize save-menu story interactions (#130948)
pauldambra Nov 6, 2026
b6a90fd
feat(posthog-ai): route every MaxChatAnthropic call through the Go AI…
jonathanlab Nov 6, 2026
de976dc
chore(posthog-ai): remove phai-llm-gateway-v2 flag and legacy gateway…
jonathanlab Nov 6, 2026
6c629ab
chore(ci): allow manual cli release runs (#130697)
marandaneto Nov 6, 2026
9475677
fix(slack-app): stop treating DMs as Slack Connect channels (#130876)
VojtechBartos Nov 6, 2026
9713178
fix(data-warehouse): use one description order in read_data (#129992)
sinan-ku Nov 6, 2026
d468e4f
feat(data-modeling): use view and table annotations for node descript…
sinan-ku Nov 6, 2026
3754d1e
feat(data-warehouse): add a description field to save as view (#130083)
sinan-ku Nov 6, 2026
f71c9d6
fix(web-analytics): stop heatmap screenshot scroll looping forever (#…
jabahamondes Nov 6, 2026
400b6eb
fix(signals): classify query validation errors as broken queries (#13…
posthog[bot] Nov 6, 2026
ea0e374
fix(alerts): compare ai detector checks with comparable time slots (#…
posthog[bot] Nov 6, 2026
c2d286b
fix(alerts): notify once per firing episode for ai detector alerts (#…
posthog[bot] Nov 6, 2026
b65490b
fix(mcp): clarify project scope before tool discovery (#130992)
adboio Nov 6, 2026
9c11187
chore(ci): build product manifests once during typechecking (#130656)
posthog[bot] Nov 6, 2026
a4cf028
chore(storybook): restore capture waits and two jest workers per shar…
webjunkie Nov 6, 2026
79f58e0
fix(cross-project-dashboards): offer the API scope when creating keys…
yasen-posthog Nov 6, 2026
e12900b
fix(posthog-ai): rate-limit only eligible context selections and reco…
adboio Nov 6, 2026
de619af
feat(devex): move the data deletion request workflow into the admin c…
webjunkie Nov 6, 2026
89ff6df
feat(devex): move deletion request editing into the admin console (#1…
webjunkie Nov 6, 2026
99878c1
fix(review-hog): scope github tokens to read or push per step (#130633)
charlesvien Nov 6, 2026
ef4d7e5
feat(insights): save chart explanations from PostHog AI so a link reo…
sampennington Nov 6, 2026
90f27dd
fix(alerts): pause ai detector checks on a gateway credit refusal (#1…
posthog[bot] Nov 6, 2026
98bc460
feat(review-hog): create review tasks from a task profile (#130625)
charlesvien Nov 6, 2026
2654eef
feat(db): record how long postgres connections take to open (#130370)
thiagosalvatore Nov 6, 2026
56d1104
feat(data-catalog): add offset continuation to governed metric runs (…
thiagosalvatore Nov 6, 2026
b69bcf3
feat(marketing-analytics): report which table served the cost trend (…
jabahamondes Nov 6, 2026
145f442
feat(toolbar): filter heatmaps by experiment variant (#129421)
jabahamondes Nov 6, 2026
789c80f
chore(ci): narrow the hobby installer release checkout (#127091)
posthog[bot] Nov 6, 2026
6a523ff
fix(ingestion): give every worker the same share of aperture slices (…
pl Nov 6, 2026
aa0bee7
fix(warehouse): reconnect person-property consumer after db errors (#…
jabahamondes Nov 6, 2026
3fae1f6
feat(experiments): pick the recalculation clickhouse user from its ta…
rodrigoi Nov 6, 2026
c9dd9d1
chore(ci): share pytest startup in full warehouse checks (#131008)
posthog[bot] Nov 6, 2026
ba3f6df
fix(ci): validate generated docs on large pull requests (#130686)
posthog[bot] Nov 6, 2026
646c939
feat(metrics): split metrics4 sample rows by histogram bucket layout …
frankh Nov 6, 2026
a21aef2
feat(slack-app): create slack tasks from task profiles (#130623)
charlesvien Nov 6, 2026
e764b02
chore(ci): narrow the hogql parser version check checkout (#130647)
posthog[bot] Nov 6, 2026
89036d9
chore(ci): use shallow checkout for master skills builds (#130885)
posthog[bot] Nov 6, 2026
169c9b9
fix(signals): exclude expected spend retries from error tracking (#13…
oliverb123 Nov 6, 2026
a2640ea
chore(ci): remove Python setup from the mcp build (#130904)
posthog[bot] Nov 6, 2026
7bd8c2f
chore(ci): narrow the sandbox shim test checkout (#128072)
posthog[bot] Nov 6, 2026
ea4d485
perf(tasks): index the warm-pool capacity count (#130995)
tatoalo Nov 6, 2026
e93003b
chore(owners): name owners for 22 more test dirs (#130971)
rnegron Nov 6, 2026
aab1603
chore(ci): remove duplicate protoc setup from mcp integration (#126545)
posthog[bot] Nov 6, 2026
e7a8362
feat(cdp): record where destination and workflow test requests went (…
meikelmosby Nov 6, 2026
f9bd857
fix(surveys): stop promising an auto-close on an ended repeat schedul…
lucasheriques Nov 6, 2026
49b48e6
chore(tasks): bump sandbox @posthog/agent to 2.4.316 (#131056)
scheduled-actions-posthog[bot] Nov 6, 2026
2669716
feat(cdp): report the origins a test invocation sent requests to (#13…
meikelmosby Nov 6, 2026
5e0bc87
chore(ci): run every livestream test package (#130622)
eli-r-ph Nov 6, 2026
29b237e
fix(provisioning): skip radar for verified partners and check email o…
rafaeelaudibert Nov 6, 2026
ce22126
feat(mcp-analytics): start setup mode from a button and trim it to on…
lucasheriques Nov 6, 2026
12a4501
feat(mcp-analytics): show the server's real tools and stuck help in s…
lucasheriques Nov 6, 2026
fb5198a
feat(mcp-analytics): reopen setup from the scene and harden the tools…
lucasheriques Nov 6, 2026
2a59569
feat(surveys): show a review and in-context preview on draft survey p…
lucasheriques Nov 6, 2026
dfa066e
feat(surveys): show who made a draft survey and add an ask PostHog AI…
lucasheriques Nov 6, 2026
c52a7e7
feat(signals): filter error tracking inbox signals before ai work (#1…
posthog[bot] Nov 6, 2026
7f93947
fix(data-warehouse): include today's partial data in ga4 full refresh…
kyleswank Nov 6, 2026
0d12ec1
fix(tracing): show skeleton rows while the spans table loads (#130023)
thiagosalvatore Nov 6, 2026
548b69e
feat(web-analytics): link search and ai to page reports (#123511)
jordanm-posthog Nov 6, 2026
b761732
perf(access-control): skip redundant lookups in scoped permission che…
thiagosalvatore Nov 6, 2026
b2a861f
feat(logs): move synthetic log attributes under the posthog. namespac…
frankh Nov 6, 2026
54a29e8
feat(servicem8): add four missing warehouse tables (#131064)
Gilbert09 Nov 6, 2026
416c787
feat(shipmail): add four warehouse tables (#131068)
Gilbert09 Nov 6, 2026
40afad9
feat(shipstation): add four lookup tables (#131073)
Gilbert09 Nov 6, 2026
2ea79d6
feat(shopwired): add four missing warehouse tables (#131074)
Gilbert09 Nov 6, 2026
fdede3b
feat(shortcut): add four warehouse tables (#131076)
Gilbert09 Nov 6, 2026
10d75ee
feat(shutterstock): add collection members and audio tables (#131080)
Gilbert09 Nov 6, 2026
c34c17f
feat(shippo): add four warehouse tables (#131084)
Gilbert09 Nov 6, 2026
4288e79
feat(simfin): add filing and database change tables (#131054)
Gilbert09 Nov 6, 2026
c90bb51
feat(similarweb): add four warehouse tables (#131053)
Gilbert09 Nov 6, 2026
da838e4
chore(access-control): prevent object-name test id collisions (#131083)
pauldambra Nov 6, 2026
4750225
feat(clickhouse): add metrics cluster node roles and schema (#130582)
bciaraldi Nov 6, 2026
4ba877e
fix(llm-gateway): reject inference without a product slug (#129870)
jonathanlab Nov 6, 2026
e0d3a45
fix(ci): give the weekly digest table a non-empty header cell (#131055)
gantoine Nov 6, 2026
22ed8d1
feat(shortio): sync links and click statistics (#131057)
Gilbert09 Nov 6, 2026
ff235ca
fix(mcp): attribute rejected exec calls to the tool the agent attempt…
lucasheriques Nov 6, 2026
1e5d92f
feat(slack_app): ask for the search scopes when a person links slack …
VojtechBartos Nov 6, 2026
c77f10b
fix(mcp-analytics): show whole-period kpis and rank error rates on re…
lucasheriques Nov 6, 2026
194edc5
fix(mcp-analytics): stop the onboarding signal poll once the first to…
lucasheriques Nov 6, 2026
0819c89
fix(insights): label explanation evidence charts with an axis label o…
sampennington Nov 6, 2026
502cc22
chore(tasks): move the reply suggestion eval to tasks and neutralize …
puemos Nov 6, 2026
59488f7
feat(mobile): serve app link files and route web report links in the …
dmarticus Nov 6, 2026
22f6669
feat(quill-charts): add a canvas flame graph chart (#123011)
sampennington Nov 6, 2026
ca86606
feat(hogql): route sql drafting and suggestions through ai gateway (#…
charlesvien Nov 6, 2026
0e532e9
feat(insights): route insight metadata through the ai gateway (#130540)
charlesvien Nov 6, 2026
a743de2
fix(data-warehouse): show the source label as the source page title (…
CShine612 Nov 6, 2026
d891f40
fix(data-warehouse): show a skeleton while elt destination rows load …
CShine612 Nov 6, 2026
a8cf544
fix(data-warehouse): truncate long names in the sql editor sidebar (#…
CShine612 Nov 6, 2026
6262352
fix(batch-exports): describe schedule correctly in runs empty state (…
CShine612 Nov 6, 2026
ddd353a
feat(warehouse-sources): read a fivetran account into a secret-free s…
danielcarletti Nov 6, 2026
65fcff5
feat(warehouse-sources): plan a posthog source for each fivetran conn…
danielcarletti Nov 6, 2026
1e7e36b
feat(warehouse-sources): store fivetran migrations and crawl them in …
danielcarletti Nov 6, 2026
33c61cb
feat(warehouse-sources): add the warehouse migrations api (#122883)
danielcarletti Nov 6, 2026
c79cce8
fix(visual-review): register snapshots with one bulk insert (#131129)
thiagosalvatore Nov 6, 2026
de12cac
fix(aio): build only built-in hogql tables for personal spend (#131125)
thiagosalvatore Nov 6, 2026
3807f51
fix(feature-flags): make android payload snippets compile and skip fl…
turnipdabeets Nov 6, 2026
f1aa402
feat(toolbar): compare the page with a flag off and on (#130111)
gustavohstrassburger Nov 6, 2026
9d3e43e
fix(mcp-analytics): keyboard access, plain copy, and one card style (…
lucasheriques Nov 6, 2026
6975f73
fix(error-tracking): check uploaded symbol set files in parallel (#13…
thiagosalvatore Nov 6, 2026
d96b049
fix(devex): keep the admin console audit log at info (#131086)
webjunkie Nov 6, 2026
2b9b78f
feat(devex): gate console operations on the owning team's staff group…
webjunkie Nov 6, 2026
57d311b
feat(posthog-ai): create posthog ai tasks from task profiles (#130626)
charlesvien Nov 6, 2026
b169def
fix(permissions): disable admin-only setup controls for non-admins (#…
fercgomes Nov 6, 2026
5cee8c7
fix(quill): stop the date time picker header and footer rendering gre…
adamleithp Nov 6, 2026
892818a
feat(data-warehouse): flag sensitive warehouse columns by name and ty…
danielcarletti Nov 6, 2026
c108fd6
feat(data-warehouse): suggest masking flagged columns in the column p…
danielcarletti Nov 6, 2026
87b0a3b
feat(data-warehouse): expose column sensitivity to agents (#125080)
danielcarletti Nov 6, 2026
2c9b73c
feat(mcp-analytics): show a session call's arguments and let users ac…
lucasheriques Nov 6, 2026
ec48347
feat(aio): surface expiring datasets and extend retention (#130220)
Radu-Raicea Nov 6, 2026
4acdacc
feat(review-hog): start a review when a review team is requested (#12…
gantoine Nov 6, 2026
13c93e5
chore(toolbar): release the extension to the chrome web store from ch…
rafaeelaudibert Nov 6, 2026
b69c683
fix(billing): warn when a platform package change ends 7-year events …
cohenroy Nov 6, 2026
720b00f
fix(ci): retry the multinode smoke schema artifact lookup (#130620)
jzhu13 Nov 6, 2026
4cd49b1
fix(aio): preserve offline eval trace links and enable capture (#130462)
Radu-Raicea Nov 6, 2026
9752d2c
fix(analytics-platform): expire precompute rows before they outlive e…
lricoy Nov 6, 2026
448b515
perf(mcp-analytics): build tool neighbors from per-conversation array…
lucasheriques Nov 6, 2026
47bcc49
feat(web-analytics): use quill controls in the filter bar (#130340)
lricoy Nov 6, 2026
069671b
feat(batch-exports): backfill destination credentials into integratio…
Gilbert09 Nov 6, 2026
7b30bee
feat(signals): create signals tasks from task profiles (#130627)
charlesvien Nov 6, 2026
b9770fd
feat(tasks): create API tasks from a public profile (#127924)
charlesvien Nov 6, 2026
896e581
feat(retention): send downgrade and upcoming deletion events (#130207)
andyzzhao Nov 6, 2026
a3f2a2e
fix(flags): clear old token's team metadata cache on token reset (#13…
haacked Nov 6, 2026
d9a8c71
fix(aeo): resume the daily citation run after a worker restart (#125911)
lricoy Nov 6, 2026
83479a1
feat(managed-warehouse): let org admins manage hoglake credentials (#…
fuziontech Nov 6, 2026
37e8253
fix(warehouse): read objects without content length (#131137)
Gilbert09 Nov 6, 2026
b30b783
fix(dashboards): apply insight access checks in run_insights (#131029)
MattPua Nov 6, 2026
c584d0d
fix(insights): open hand-built SQL insight links in the SQL editor (#…
thmsobrmlr Nov 6, 2026
33f8d02
fix(persons): fix groups list and session search for numeric properti…
CShine612 Nov 6, 2026
e4894f8
feat(security): refuse hosts on the out-of-band domain list (#123793)
Piccirello Nov 6, 2026
8055d37
chore(devex): test stamphog mode switch from a waiting fallback head …
webjunkie Nov 6, 2026
99e258d
feat(capture-logs): accept vercel log drains (#128836)
lricoy Nov 6, 2026
b17ccda
fix(flags): apply property access control to test evaluation person p…
thmsobrmlr Nov 6, 2026
fe930fd
fix(mcp): link SQL queries to the SQL editor, not a new insight (#130…
thmsobrmlr Nov 6, 2026
e1a8f68
feat(oauth): declare what each scope is for next to its product (#130…
rafaeelaudibert Nov 6, 2026
f3845b8
feat(oauth): serve the grantable scope list at /oauth/scopes (#130503)
rafaeelaudibert Nov 6, 2026
78687b4
feat(oauth-proxy): proxy and cache the scope list at /oauth/scopes (#…
rafaeelaudibert Nov 6, 2026
1596577
feat(mobile): support sql chart labels and mixed axes (#131188)
cvolzer3 Nov 6, 2026
9fb4b3d
chore(llma): Update LLM costs (#131229)
scheduled-actions-posthog[bot] Nov 6, 2026
78191fc
feat(managed-warehouse): let members create their own hoglake credent…
fuziontech Nov 6, 2026
9af4643
chore(ci): reuse matching schemas in scheduled dagster tests (#130619)
posthog[bot] Nov 6, 2026
6b6dab7
fix(cdc): start history from the snapshot after a switch to a history…
danielcarletti Nov 6, 2026
63893d6
feat(tasks): require a profile to create a task (#130662)
charlesvien Nov 6, 2026
f1455c1
fix(personhog): name the cluster when seeding the changelog (#131235)
z0br0wn Nov 6, 2026
027a0c1
feat(alerts): show alert groups, overflow and per-group snooze on the…
jzhu13 Nov 6, 2026
3be8e3d
fix(onboarding): flush events in the node.js setup snippet (#131234)
timgl Nov 6, 2026
a596df3
feat(data-warehouse): let users delete a CDC history table (#130435)
danielcarletti Nov 6, 2026
384fcf5
fix(surveys): recoverable survey-create MCP errors and hosted confirm…
lucasheriques Nov 6, 2026
abaae55
fix(clickhouse): make trace_spans_kafka_metrics an aggregating table …
jzhu13 Nov 6, 2026
832a0af
fix(groups): leave restricted properties out of crm notebooks (#130986)
thmsobrmlr Nov 6, 2026
3e03146
fix(cymbal): skip an ingestion notification too large to produce (#13…
z0br0wn Nov 6, 2026
80cbe8c
fix(google_analytics): stop retrying syncs of removed custom reports …
Gilbert09 Nov 6, 2026
4e20f30
fix(twenty): classify unresolvable host as non-retryable (#131240)
Gilbert09 Nov 6, 2026
b2a9013
feat(data-warehouse): clear dead credentials from warehouse sources (…
Gilbert09 Nov 6, 2026
0aad432
feat(aeo): show where ai answers rank your site (#130648)
lricoy Nov 6, 2026
b965973
fix(query): record clickhouse timing counters (#131248)
arthurdedeus Nov 6, 2026
28abcd8
feat(persons): add erasure flags to the orphan repair command (#130492)
nickbest-ph Nov 6, 2026
fe6e319
feat(knowledge_writer): start the merge check from default-branch pus…
johncwaters Nov 6, 2026
7ca4279
feat(auth): enforce organization ip restrictions (#128376)
ReeceJones Nov 6, 2026
f62fa8b
feat(surveys): let recurring surveys repeat until stopped (#131021)
lucasheriques Nov 6, 2026
13eb62e
feat(toolbar): list authorized urls in the extension panel and allow …
rafaeelaudibert Nov 6, 2026
3a97109
fix(slack): implement inbox reports in slack threads (#130668)
dmarticus Nov 6, 2026
e2a9641
fix(surveys): keep question ids when an update omits them (#130976)
lucasheriques Nov 6, 2026
a0faca2
feat(surveys): add stable codes to translation language validation er…
lucasheriques Nov 6, 2026
499d774
fix(data-modeling): stop rerunning auto-reverted views (#130480)
posthog[bot] Nov 6, 2026
fae7210
fix(mcp-analytics): show load errors and stable placeholders on dashb…
lucasheriques Nov 6, 2026
5d423c5
feat(oauth): let a device login lock the scopes it adds (#130661)
rafaeelaudibert Nov 6, 2026
c4bd69a
feat(hog): add scopes to a login with hog auth add (#130665)
rafaeelaudibert Nov 6, 2026
1a72d5d
feat(hog): offer a step-up when posthog asks for more scopes (#130671)
rafaeelaudibert Nov 6, 2026
6f0d7a2
feat(hog): check scopes before commands that write in steps (#130676)
rafaeelaudibert Nov 6, 2026
cbda16c
feat(mcp-analytics): show exec commands, argument names and failure d…
lucasheriques Nov 6, 2026
ea143eb
chore(toolbar): release the extension v0.2.0 (#131294)
scheduled-actions-posthog[bot] Nov 6, 2026
06d9389
fix(signals): use indexed scout authorship lookups (#130669)
dmarticus Nov 6, 2026
85d2089
fix(tasks): use indexes for webhook run lookup (#130672)
dmarticus Nov 6, 2026
6a84e46
feat(logs): end new alerts' legacy shadow with their team's shadow (#…
jzhu13 Nov 7, 2026
89fe024
fix(health): require health_issue:write on the resolve action (#129591)
posthog[bot] Nov 7, 2026
183b1dd
feat(aeo): add a brand catalog filled from cited domains (#122980)
lricoy Nov 7, 2026
9d1e9b4
feat(data-modeling): add check_trino_compile command (#131319)
sakce Nov 7, 2026
b81f13e
fix(navigation): hide the project notice on access denied screens (#1…
rafaeelaudibert Nov 7, 2026
4904c8a
feat(toolbar): open authorized urls with the chrome extension when it…
rafaeelaudibert Nov 7, 2026
170658b
chore(agent): skip agent infra review and label on tiny changes (#131…
charlesvien Nov 7, 2026
a6fc336
fix(alerts): move firing insight alerts that have nobody to notify (#…
jzhu13 Nov 7, 2026
9780d5a
chore(ci): narrow the duplication lint checkout (#131308)
posthog[bot] Nov 7, 2026
a11a5be
chore(ci): lock cargo-shear source fallback dependencies (#131191)
posthog[bot] Nov 7, 2026
20c9d33
chore(ci): skip dev dependencies in owner validation (#130659)
posthog[bot] Nov 7, 2026
be42cd5
chore(ci): narrow the e2e spec selector checkout (#130670)
posthog[bot] Nov 7, 2026
ae1fdf1
chore(ci): reuse the installed Python environment for ty (#131326)
posthog[bot] Nov 7, 2026
8c8fec2
feat(hog): exchange a CI job's OIDC token for a workload token (#130679)
rafaeelaudibert Nov 7, 2026
d8a90cf
feat(hog): ask an admin to trust a repository with hog ci setup (#130…
rafaeelaudibert Nov 7, 2026
f755c6e
feat(workload-identity): support GitHub Actions jobs (#130681)
rafaeelaudibert Nov 7, 2026
49c661c
feat(workload-identity): support GitLab.com pipelines (#130684)
rafaeelaudibert Nov 7, 2026
ac41ca2
feat(workload-identity): support Depot CI jobs (#130689)
rafaeelaudibert Nov 7, 2026
da452e5
chore(ci): skip deltalite parity work for unchanged inputs (#130801)
posthog[bot] Nov 7, 2026
3b8b161
chore(ci): skip the inactive kea typegen cache (#131335)
posthog[bot] Nov 7, 2026
8f9fd7c
feat(experiments): say when each variant is exposed on its own page (…
mp-hog Nov 7, 2026
84d769e
feat(experiments): show the flag setup on the health overview (#130812)
mp-hog Nov 7, 2026
cfe9e71
fix(alerts): compare ai detector hourly checks with the same weekday …
posthog[bot] Nov 7, 2026
d4c43cb
fix(signals): reserve interim check capacity (#131271)
mikaylathompson Nov 7, 2026
515434f
feat(today): rework the home key numbers (#131119)
puemos Nov 7, 2026
e534284
fix(signals): count only flag checks as stale-flag call sites (#131380)
posthog[bot] Nov 7, 2026
1a3b1f8
perf(cdp): skip the table-wide max lookup in the email dequeue counte…
meikelmosby Nov 7, 2026
6e00175
fix(cdp): keep hog function execution_order inside smallint range (#1…
meikelmosby Nov 7, 2026
8da368d
feat(signals): link to exact scout trials and runs with url params (#…
sortafreel Nov 7, 2026
8e42bac
fix(models): stop primary property loads throwing after unmount (#129…
pauldambra Nov 7, 2026
cc62087
feat(mcp): send tool call arguments and results to MCP analytics (#13…
lucasheriques Nov 7, 2026
30f4100
fix(mcp): keep the KPI comparison window stable so it can be cached (…
lucasheriques Nov 7, 2026
c112bf2
chore(ci): overlap projection validation with python lint (#131396)
posthog[bot] Nov 7, 2026
6cb353c
docs(signals): route inbox prioritization to sort=personal first (#13…
posthog[bot] Nov 7, 2026
4dd7b5c
chore(signals): teach anomaly and insight-alert scouts about the ai d…
posthog[bot] Nov 7, 2026
5ab5a92
fix(flags): delete deleted teams' cache entries in expiry cleanup (#1…
haacked Nov 7, 2026
554a079
fix(ci): refuse schema dumps newer than the checkout (#131364)
posthog[bot] Nov 7, 2026
724d0cc
chore(ci): group product duration keys in one pass (#131353)
posthog[bot] Nov 7, 2026
3dd7db3
feat(flags): join persons on flag_evaluations under the joined person…
haacked Nov 7, 2026
c46af05
feat(alerts): add an authoring-insight-alerts agent skill (#131019)
posthog[bot] Nov 7, 2026
5093779
chore(ci): omit the module graph from browser artifacts (#131386)
posthog[bot] Nov 7, 2026
b32e1a7
fix(signals): comment on a scout's source issue when the report is fi…
posthog[bot] Nov 7, 2026
9954265
fix(data-modeling): drop session time limits from trino compile check…
sakce Nov 7, 2026
36269b1
chore(alerts): add contents to the insight alert payload reference (#…
posthog[bot] Nov 7, 2026
1662caf
fix(persons): keep query url updates on the persons list (#131431)
pauldambra Nov 8, 2026
0f072f8
feat(signals): add a personalized sort to the web inbox (#131426)
posthog[bot] Nov 8, 2026
1418617
fix(marketing-analytics): cap touchpoints per person in dashboard til…
jabahamondes Nov 8, 2026
cb17b79
Merge remote-tracking branch 'origin/email-v2/05-template-send' into …
Silthus Nov 8, 2026
7852fca
fix(cdp): decode uppercase html entities in email links (#130844)
Silthus Nov 8, 2026
3e7e289
Merge branch 'master' into email-v2/06-template-editor
Silthus Nov 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
40 changes: 29 additions & 11 deletions .agents/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,33 +219,51 @@ repository does not. When the copy is there, start with these paths:
`posthog/security/crosslang/oob_domains.json` lists the services that capture out-of-band
interactions, such as Interactsh and Burp Collaborator, and the DNS rebinding services.

Today the guards only log a match. Nothing is refused yet.
A guard refuses a listed name, on the name alone, before any resolve. The matcher reports the
match and the guard decides the refusal, so each surface can report it the way its caller expects.

The warehouse guards emit the `oob_domain` stage of `data_imports.host_check`, which carries
`team_id`, and the `oob_domain_resolved` stage when the caller resolved the host first. The HTTP
adapter emits `security.oob_domain_seen` and takes its team from the activity's bound log context.
`posthog/security/url_validation.py` emits the same event with no team at all, because no team is
in scope there, so those lines are attributable to a host and not to a project.
The warehouse guards emit the `oob_domain` stage of `data_imports.host_check` with the `block`
decision, which carries `team_id`, and the `oob_domain_resolved` stage when the caller resolved
the host first. The HTTP adapter emits `security.oob_domain_seen` and raises
`OutOfBandDomainError`. `posthog/security/url_validation.py` emits the same event and returns a
`BlockedName`, so every caller of `is_url_allowed`, `validate_external_url` and
`validate_external_host` refuses the host.

Three DNS helpers refuse the name and report nothing for it: `posthog/dns_hosts.py` finds no DNS
host, `email_domain_dns.find_published_records` publishes no record so the domain never verifies,
and `existing_email_tools.lookup_existing_email_tools` reports no tool.

A refusal must be final, because the host sits in the customer's own config and every retry
replays it. The warehouse refusals carry a prefix `Any_Source_Errors` matches, so the schema
pauses, and they subclass `NonReportableError`, so the retries stay out of error tracking.
`OutOfBandDomainError` is deliberately not a `RequestException`: the sources catch that broadly
and several retry on it.

`TeamAndOrgViewSetMixin` binds `team_id` into the log context of every team-scoped view, so a line
from a guard reached through the API names the project that drove it.

In Node, `validateHostnameIPLiteral` (`nodejs/src/common/utils/request.ts`) and `EmailValidationService.getSkipReason` emit `security.oob_domain_seen` too, under the guard `node_request` or `node_email_validation`.
Both read the hand-written mirror in `nodejs/src/common/utils/oob-domains.ts`, which a parity test holds against the JSON.
Both log `team_id`, the field the Python guards bind.
The email guard always has a team.
The request guard has one only when the fetch runs under `fetchAttribution`, as a CDP destination fetch and a recording export's stylesheet fetch do, and logs `team_id: null` for any other caller.
`noteOobDomain` logs one line per host, team and guard every 15 minutes, because a retrying destination would otherwise log per attempt.
`checkOobDomain` logs one line per host, team and guard every 15 minutes, because a retrying destination would otherwise log per attempt.
The window gates the log line and nothing else, so every match is refused.

The Rust guards call `common_dns::oob_domains::note_oob_domain` and emit `security.oob_domain_seen` under three guard names.
The Rust guards call `common_dns::oob_domains::check_oob_domain` and emit `security.oob_domain_seen` under three guard names.
They read the hand-written mirror in `rust/common/dns/src/oob_domains.rs`, which a parity test holds against the JSON.
`note_oob_domain` takes the team as an `Option`, logs one line per host, team and guard every 15 minutes, and omits the `team_id` field rather than printing an empty one.
`check_oob_domain` takes the team as an `Option`, logs one line per host, team and guard every 15 minutes, and omits the `team_id` field rather than printing an empty one.
`cymbal_sourcemap` names the team on the source and sourcemap fetches, and omits it on a redirect hop, because one HTTP client serves every team.
`batch_import_s3_endpoint` always names the team, which the job model carries.
`common_dns_resolver` never names one: it fires inside the shared reqwest and Smithy resolvers, which no caller passes a team to.

Every check runs on cloud only, and each runs before its guard's own DNS resolution, because the lookup alone confirms the path to whoever runs the collaborator.
Every check runs on cloud only, so a self-hosted deployment reaches these names as it always did. Each runs before its guard's own DNS resolution, because the lookup alone confirms the path to whoever runs the collaborator.

It stops the default scanner configuration. It does not stop a determined attacker, who points a
CNAME at the collaborator or runs their own server. The IP checks and the address pinning remain
the real controls.
the real controls. Refusing the name stops the public rebinding services on the list, `rbndr.us` and `1u.ms`,
on the paths that do not pin the address. A rebinding record on any other name still passes
the name check, so address pinning and the egress proxy stay the controls there.

## Content Security Policy

Expand Down
26 changes: 14 additions & 12 deletions .agents/skills/adding-api-scopes/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ A scope has two parts: an object and an action, as in `feature_flag:read`.
Adding a scope means adding a scope object, such as `feature_flag`. It gives tokens `feature_flag:read` and `feature_flag:write`.
`posthog/scopes.py` is the source of the object list.
The frontend type and the MCP OAuth list are generated from it.
The picker rows and the groups are kept by hand in `frontend/src/lib/scopes.tsx`, and a test checks them.
They stay in the frontend on purpose: labels, plurals, groups and picker omissions are UI decisions, while `posthog/scopes.py` decides what exists and what it grants.
Each object a picker offers also has a `ScopeDoc`: its name, plural, one-sentence description, group, docs link, the levels a picker offers, whether it reaches the whole organization, and any scope its writes also need.
The owning product declares it in `products/<name>/backend/scopes.py`, and core objects are in `CORE_SCOPE_DOCS` in `posthog/scope_docs.py`.
The web app's `API_SCOPES` and `API_SCOPE_GROUPS` are built from those declarations, so the frontend keeps no copy.

## Decide if you need a new scope

Expand All @@ -23,7 +24,7 @@ Name its object with a `snake_case` singular noun, such as `feature_flag`.
- **Public:** OAuth lists it, MCP can request it, and the key picker offers it. This is the default.
- **Internal:** only the server creates tokens with it. Use `INTERNAL_API_SCOPE_OBJECTS`.
- **OAuth-hidden:** a person can paste it into a personal API key, but OAuth clients do not see it. Use this for staff-only or unreleased surfaces. Use `OAUTH_HIDDEN_SCOPE_OBJECTS`.
- **Privileged:** only PostHog staff can give it to an OAuth app, through Django admin or a data migration. An app that registers itself cannot get it, and the CLI login and the key picker presets never include it. Use this for a scope that a partner app must not grant to itself, such as `llm_gateway`. Use `PRIVILEGED_SCOPES`, and set `unprivilegedExcluded: true` on the picker row.
- **Privileged:** only PostHog staff can give it to an OAuth app, through Django admin or a data migration. An app that registers itself cannot get it, and the CLI login and the key picker presets never include it. Use this for a scope that a partner app must not grant to itself, such as `llm_gateway`. Use `PRIVILEGED_SCOPES`. The picker row reads it from the generated scope docs.

Then decide two more things, separately from the kind:

Expand All @@ -39,24 +40,24 @@ Then decide two more things, separately from the kind:
- An endpoint set to `scope_object = "INTERNAL"` accepts only logged-in sessions. Change it to the new object to open it to tokens.
- Then call each custom action with a personal API key that has only the new scope. No test checks this.
3. **Regenerate.** Run `hogli build:openapi`, which carries the object to the frontend type, and `hogli build:projections`, which updates the OAuth lists of the MCP server and the web app. **DO NOT EDIT GENERATED FILES BY HAND.**
4. **Show it in the pickers.** Skip this step for an OAuth-hidden object: no picker shows it, and the tests do not ask for a row or a group. Otherwise, in `frontend/src/lib/scopes.tsx`:
- Add a row to `API_SCOPES` with a sentence-case label and plural (`/writing-user-facing-copy`). Disable `write` if no endpoint writes. If the key modal should not offer the object, add a reason to `API_SCOPES_OMITTED_FROM_MODAL` instead.
- Add the object to one group in `API_SCOPE_GROUPS`. See "Choose a group".
4. **Explain it.** Skip this step for an OAuth-hidden object: no picker shows it, and the tests do not ask for a doc or a group.
- Add a `ScopeDoc` to `SCOPE_DOCS` in `products/<name>/backend/scopes.py`, or to `CORE_SCOPE_DOCS` for a core object. Give it a sentence-case name, a plural that is lowercase except for proper nouns and acronyms, and one sentence under 120 characters on what the scope covers, without "read" or "write" (`/writing-user-facing-copy`). Link the product's page under `https://posthog.com/docs/` when one exists. Pick its `group` (see "Choose a group"). Set `actions=("read",)` if no endpoint writes, and `organization_wide=True` if it reaches past one project. If writing it also writes another object, as a survey writes its targeting flag, set `write_requires` to that scope and the reason.
- If no picker should offer the object, add a reason to `SCOPE_OBJECTS_OMITTED_FROM_PICKERS` in `posthog/scopes.py` instead.
- Run `hogli build:projections` again to regenerate `frontend/src/lib/scopeDocs.generated.ts`.
5. **Let MCP tools request it.** For each MCP tool that calls the endpoint, add the scope under `scopes:` in `products/<product>/mcp/tools.yaml`.

## Choose a group

The OAuth consent screen and the scope pickers show objects in groups, from `API_SCOPE_GROUPS` in `frontend/src/lib/scopes.tsx`.
The OAuth consent screen and the scope pickers show objects in groups, from the `group` of each `ScopeDoc`. The groups and their order are the `ScopeGroup` literal in `posthog/scope_docs.py`.
The groups make a long list readable, so a person can find a product quickly.

- A group is a product area that a person recognizes, such as "Session replay" or "Feature flags, experiments & surveys". It is not a code module or a team.
- Put the object in the existing group that a person would look in first.
- Add a new group only when it gets two or more objects. A group with one object makes the list longer, not easier to read.
- Add a new group to `ScopeGroup` only when it gets two or more objects. A group with one object makes the list longer, not easier to read.

## If a test fails

- **`frontend/src/lib/scopes.test.ts`, the coverage test:** a grantable object has no picker row and no omission reason. Add a row to `API_SCOPES`, or a reason to `API_SCOPES_OMITTED_FROM_MODAL`. If the object is missing from `APIScopeObject`, run `hogli build:openapi` first. If the object is OAuth-hidden, run `hogli build:projections` instead, so the test learns to skip it.
- **`frontend/src/lib/scopes.test.ts`, the group test:** an object is in no group, or in two groups. Put it in exactly one group of `API_SCOPE_GROUPS`. It also fails when an OAuth-hidden object has a row or a group. Remove them, because no picker shows a hidden object.
- **`posthog/test/repo_invariants/test_scope_docs.py`:** an exposed object has no `ScopeDoc`, or a `ScopeDoc` names an object that is hidden or omitted from pickers. Add the doc, or the omission reason, as in step 4. A `ValueError` at import names a `ScopeDoc` with a missing field, a long description, a dash, a docs link outside posthog.com/docs, an unknown group, or a `write_requires` that names an unknown scope.
- **`posthog/test/test_scopes.py`:** an internal, OAuth-hidden or privileged scope leaks into a list it must stay out of, or the project secret API key list in `posthog/scopes.py` differs from the copy in `frontend/src/lib/scopes.tsx`. Fix the set, or make the two lists equal.
- **`services/mcp/tests/unit/tool-filtering.test.ts`, the completeness test:** an MCP tool requires a scope that OAuth does not advertise. If the scope is new, run `hogli build:projections`. If it is internal, add it to the test's server-only list. Otherwise fix the scope name in `tools.yaml`.

Expand All @@ -65,8 +66,8 @@ The groups make a long list readable, so a person can find a product quickly.
- A custom `@action` without `required_scopes`. Tokens get a 403.
- A read scope on an action that changes data.
- An MCP tool scope that differs from its endpoint's `scope_object`.
- A group that makes no sense for the object, or a new group that should not exist. The group test only checks that each object has exactly one group. Check that it sits where a person would look for it, and that a new group has at least two objects. See "Choose a group".
- A wrong or unclear label.
- A group that makes no sense for the object, or a new group that should not exist. `ScopeDoc` only checks that the group exists. Check that the object sits where a person would look for it, and that a new group has at least two objects. See "Choose a group".
- A wrong or unclear name or description.

## Where to read scopes in code

Expand All @@ -79,5 +80,6 @@ Use these instead of writing your own list of scopes.
- `get_oauth_scopes_supported()`: what the OAuth server advertises.
- **Frontend type:** `APIScopeObject` from `~/types`.
- **Frontend list at runtime:** `Object.values(ScopeObjectEnumApi)`, from `products/access_control/frontend/generated/api.schemas`.
- **Python names and descriptions:** `get_scope_docs()` from `posthog.scope_docs`.
- **Frontend labels and groups:** `API_SCOPES`, `API_SCOPE_GROUPS` and `getScopeDescription` from `lib/scopes`.
- **OAuth lists:** `OAUTH_SCOPES_SUPPORTED` and `OAUTH_SCOPES_HIDDEN`, from `lib/oauthScopes.generated` in the web app and `services/mcp/src/lib/oauth-scopes.generated.ts` in the MCP server. The two files are the same.
9 changes: 8 additions & 1 deletion .agents/skills/building-the-toolbar/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: building-the-toolbar
description: Builds, watches, checks and verifies the PostHog toolbar in both of its forms, the floating toolbar that posthog-js loads on customer pages and the browser extension that shows the toolbar in a Chrome side panel. Use when changing anything under frontend/src/toolbar/ (floating toolbar or extension), frontend/toolbar-config.mjs, or the toolbar build and guard scripts, or when asked to build, watch, load unpacked, or test the toolbar or the toolbar extension in a browser. Covers `pnpm build:toolbar-all` and `pnpm watch:toolbar-all`, the check-toolbar-size, check-toolbar-graph and check-toolbar-csp-eval guards, why both forms must be built and kept in sync, and how to check each one in a real browser.
description: Builds, watches, checks and verifies the PostHog toolbar in both of its forms, the floating toolbar that posthog-js loads on customer pages and the browser extension that shows the toolbar in a Chrome side panel. Use when changing anything under frontend/src/toolbar/ (floating toolbar or extension), frontend/toolbar-config.mjs, or the toolbar build and guard scripts, or when asked to build, watch, load unpacked, or test the toolbar or the toolbar extension in a browser. Covers `pnpm build:toolbar-all` and `pnpm watch:toolbar-all`, the check-toolbar-size, check-toolbar-graph and check-toolbar-csp-eval guards, why both forms must be built and kept in sync, how to check each one in a real browser, and when an extension change needs a Sampo changeset to reach the Chrome Web Store.
---

# Building the toolbar
Expand Down Expand Up @@ -100,3 +100,10 @@ Tests and builds don't show a broken overlay, a missing style, or a CSP refusal.

Check the forms you didn't mean to change as well.
A change to a shared logic shows up in both.

## Ship an extension change

The extension reaches users only through a Chrome Web Store release, which starts from a Sampo changeset.
When a change alters what the extension does, add a changeset to the same pull request, as [the extension README](../../../frontend/src/toolbar/extension/README.md#releases) shows.
A change that only touches the floating toolbar, tests or stories needs none.
Never edit the version in `release/package.json` or the changelog by hand.
7 changes: 5 additions & 2 deletions .agents/skills/clickhouse-migrations/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ operations = [
### Node roles (choose by the cluster that owns the object)

Only the members of `NodeRole` in `posthog/clickhouse/client/connection.py` are valid: `ALL`, `DATA`,
`INGESTION_EVENTS`, `INGESTION_SMALL`, `INGESTION_MEDIUM`, `ENDPOINTS`, `LOGS`, `APM`, `AI_EVENTS`,
`AUX`, `BATCH_EXPORTS`, `OPS`, `SESSIONS`. A name that is not in that enum fails at import, which aborts
`INGESTION_EVENTS`, `INGESTION_SMALL`, `INGESTION_MEDIUM`, `INGESTION_METRICS`, `ENDPOINTS`, `LOGS`, `METRICS`, `APM`,
`AI_EVENTS`, `AUX`, `BATCH_EXPORTS`, `OPS`, `SESSIONS`. A name that is not in that enum fails at import, which aborts
migration discovery and takes every job that runs migrations down with it.

Pick the role by **which cluster owns the object**, not by its type alone:
Expand All @@ -42,6 +42,9 @@ Pick the role by **which cluster owns the object**, not by its type alone:
- `[NodeRole.APM]`: the `ingestion-apm` nodes, the metrics ingestion layer. Kafka tables, `Null` input
tables, materialized views and writable `Distributed` tables that write into storage on `LOGS`.
Stateless like the other ingestion nodes, so storage tables never go here.
- `[NodeRole.METRICS]`, `[NodeRole.INGESTION_METRICS]`: the `metrics` cluster and the `ingestion-metrics`
nodes that write to it. The metrics4 tables run on both these and `LOGS`/`APM` until reads cut over, so a
metrics4 change has to target both pairs.
- `[NodeRole.OPS]`, `[NodeRole.LOGS]`, `[NodeRole.AUX]`, `[NodeRole.AI_EVENTS]`, `[NodeRole.SESSIONS]`,
`[NodeRole.BATCH_EXPORTS]`: objects that live on a satellite cluster. A table for one of those on
`DATA` lands on the wrong nodes and leaves the intended cluster without it, so check where the
Expand Down
8 changes: 5 additions & 3 deletions .agents/skills/debugging-mcp-analytics/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@ These are the failure modes that produce a plausible-looking answer rather than
`coalesce(nullIf(toString(properties.$mcp_exec_tool_call_name), ''), toString(properties.$mcp_tool_name))`.
It exists because a single-exec server can report the tool two different ways, and the two
eras of data coexist. Today `services/mcp` resolves the inner tool itself and passes it
straight in as the tool name (`execToolName()` in `src/hono/tool-executor.ts`, which falls
back to the literal `exec` when the inner command isn't recognized), so
`$mcp_tool_name` usually already holds the real tool. `$mcp_exec_tool_call_name` is
straight in as the tool name (`analyticsToolName()` in `src/hono/tool-executor.ts`), so
`$mcp_tool_name` usually already holds the real tool. It reads the literal `exec` for the
discovery verbs (`info`, `schema`, `search`, `learn`, `help`, `tools`), which are most
`exec` rows, and for calls naming an unknown tool. Split that bucket by `$mcp_exec_verb`
and `$mcp_exec_target_tool` before reading it as unresolved calls. `$mcp_exec_tool_call_name` is
registered in `posthog/taxonomy/taxonomy.py` and coalesced defensively here, but **nothing
on master emits it** — treat it as historical rows plus in-flight work, not current
producer behaviour. Either way, aggregate through the coalesce: hand-rolling
Expand Down
Loading