Skip to content

feat(workflows): let agents set up an email sending domain via mcp - #568

Closed
Silthus wants to merge 12 commits into
masterfrom
email-domain-agent-setup
Closed

Silthus wants to merge 12 commits into
masterfrom
email-domain-agent-setup

Conversation

@Silthus

@Silthus Silthus commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Moved here from #116863, closed on 2026-10-25 so this fork stack is the only copy. It opens upstream again after review.

This revision

  • Restacked on master 43333f81da9 on 2026-10-31. Master gained the read-only email/status route and its integrations-email-status-retrieve tool (feat(workflows): add a read-only email domain status endpoint PostHog/posthog#120402), so this body no longer claims the status and verify tools.
  • One rollout flag for the Workflows email work: workflows-email-from-code. 3c0a6bcd8f moves master's agent setup flag onto it; feat(workflows): expose read-only email sending readiness over mcp #570 carries the same commit, so the two merge cleanly.
  • Absorbs Silthus#352 (92e394edff): its token tests and the guide section on scoped sender access.
  • 34d216911e: the email domain verified event now groups by the sender's organization, not the acting user's current one.
  • Review fixes: the eval simulator answers the read-only status route (4876fbd361), the skill's tool table passes oxfmt (89b56b97e4), and email_verify sits once in the write scopes (fa6d94df9b).
  • Two-family panel fixes, 2026-11-01:
    • 7e7a885a04: integrations-email-create takes a typed config whose provider defaults to ses. Before, the skill's email-and-name call returned 400.
    • 7e7a885a04: the flag checks send the web app's person and group inputs, so a release condition on the project's id matches.
    • 7e7a885a04: the skill merges SPF on the manual path too, the member eval case reaches verify, and the new eval modules carry no docstrings.
    • 1ce3487b0a: the eval DNS simulation patches one resolver entry point.
    • 641380bd8c: the create tool no longer offers setup_method, which create ignores.

Problem

  • An agent on the PostHog MCP can read a Workflows email sender's DNS status and mark it verified, but it cannot create the sender, offer one-click DNS setup, or edit the sender.
  • Enabling those routes alone would not help. Personal API keys and OAuth tokens get "This action does not support personal API key access" on PATCH email and both Domain Connect actions, because none of them is in the viewset's scope lists.
  • PATCH email and apply-url declare no request schema, so generated tools would get untyped or empty inputs.

This recreates the fork drafts Silthus#343 and Silthus#352 on current master. Their earlier upstream drafts, PostHog#109703 and PostHog#113059, are closed.

Impact

Pays into Grow Workflows through organizations that verify an email sending domain. Measured by email domain verified with method: agent, which fires on a sender's first verification. Expected move: small, up. Run cost: n/a.

Warning

🟡 Merge risk: medium · two-way door (merge-risk rubric)

  • Every caller of PATCH email and both Domain Connect routes now goes through new request serializers, with or without the flag. A payload the web app sends that they reject would break sender edits or Domain Connect links.
  • Master gates the agent setup panel and the status and verify tools on its own agent setup flag. After this merges they read workflows-email-from-code. Copy that flag's release conditions to the new one before the deploy, or anyone it targets loses them.
  • Scoped tokens reach the Domain Connect check, apply-url and PATCH email, and the address check runs, only while workflows-email-from-code is on. Create and verify keep master's scoped token access, flag or not. The web app's payloads match the serializers, and HTTP tests cover each route for session, API key and OAuth callers.

Changes

Agents can take a domain from "add a sender" to "verified" over MCP, behind the default-off workflows-email-from-code flag. The backend checks the same flag, so turning it on enables the tools and the API access together.

Tool Does New here
integrations-email-create Creates the sender and registers its domain; the provider defaults to ses yes
integrations-email-status-retrieve Returns the DNS records with per-record status flag only
integrations-domain-connect-check-retrieve Says if the DNS host supports one-click setup yes
integrations-domain-connect-apply-url-create Returns a URL the person approves at their DNS host yes
integrations-email-verify-create Marks the sender verified once the records are found flag only
integrations-email-partial-update Changes the display name, reply-to address or MAIL FROM subdomain yes
  • Scoped API keys and OAuth reach the Domain Connect check, apply-url and PATCH email only while the flag is on for the caller. The check reads (integration:read); apply-url and the update write (integration:write), because apply-url calls SES. Create and verify keep master's scoped access.
  • The flag checks send the same person and group inputs as the web app (flag_identity), so a release condition on the project's id or the user's email matches. Before, the project's id property carried its UUID.
  • Session access does not change, including email and proxy Domain Connect links while the flag is off.
  • Scoped credentials get Domain Connect for email senders only. A proxy request from a token returns 403 before any URL is signed. A token's redirect_uri must point back to PostHog; session requests keep master's handling.
  • PATCH email and apply-url declare request and response schemas, as the check already did. URLs and success responses do not change.
  • email/verify and PATCH email on a non-email integration return 400 instead of 500.
  • apply-url returns 404 for an unknown or non-email integration_id, and for an unknown proxy_record_id. Before, these returned 500 or a "try again later" 400.
  • With the flag on, PATCH email with a different address returns 400. The check ignores case.
  • email domain verified groups by the sender's organization on both the verify and the Domain Connect paths. Before, a verification in another organization's project landed on the acting user's current organization.
  • The generic integrations-create tool stays disabled: it takes an untyped config for 30+ kinds, including credentials. integrations-email-create reuses the same route with kind: email injected and a typed config.
  • A new setting-up-an-email-domain skill teaches the flow, including SPF merging and keeping an existing DMARC record.
  • A new sandboxed eval suite, eval_email_domain_setup, runs an agent with the skill against the real API over MCP on SandboxedEval, with SES, DNS and Domain Connect simulated per case.
  • An MCP codegen fix: param_overrides.<field>.required now also works with input_schema. Before, codegen ignored it.
  • Mechanical: the flag rename across master's frontend, API, tool and test files; the email sender serializer moved to posthog/api/integration_domain_serializers.py with help_text; the OpenAPI types, MCP schemas, tool definitions and snapshots are regenerated.

Note

Turn the flag on only after this PR has deployed to Django. The MCP server deploys separately, and until Django has the change every new tool call returns 403.

Start with EmailDomainAgentSetupPermission and the three actions in posthog/api/integration.py. No web app screen changes.

How did you test this code?

Test rationale:

  • TestEmailIntegrationScopedAccess (API key, OAuth and session, flag off/on/unresolved): fails if a token reaches the update with the flag off, or a session loses access. It also covers read-only scope, member role, a foreign integration, a project-restricted key and the read-only MCP policy.
  • test_email_domain_actions_with_scoped_api_key (12 cases in the existing API key class): fails if an action moves between scope lists, if a response body changes shape, or if apply-url stops returning 404/403 for unknown, non-email or proxy requests.
  • test_email_update_from_the_app_keeps_the_sender_address: fails if a sender stored with capitals cannot be edited, or if the address check runs with the flag off.
  • The email domain verified tests in test_integration.py and test_email_domain_status_api.py: fail if a verification in a second organization's project groups by the acting user's current organization.
  • test_integration_domain_serializers.py (SimpleTestCase): per-context required fields on apply-url, a malformed proxy_record_id, and maildev outside DEBUG.
  • products/workflows/evals/test/: the simulation runs the real SES provider and Domain Connect code. New: a fresh sender reads its pending records through email/status, and a seeded verified sender reads as verified. Red first with AttributeError: ... ses_status_client. The scorers reject split SPF records and case-changed TXT values.
  • MCP unit tests: the apply-url tool never forwards context: proxy; the create tool fills in provider: ses and posts to the integrations route; the codegen required override works with input_schema; the sender tools appear only with the flag on.
  • test_flag_released_to_a_project_id_reaches_the_sender_update: a flag released only to the project's numeric id lets a scoped token update the sender. Red before 7e7a885a04 with a 403.
  • test_a_member_reaches_verify_and_is_refused: the member eval case reaches verified DNS and gets the 403 it scores. Red before 7e7a885a04: status stayed pending.

Lane gate on the restacked head: the posthog/api integration, Domain Connect, email model, workflows email-domain and eval tests (701 passed), the MCP unit tests (183 files, 5,362 passed), the MCP and frontend typecheck, and mypy on every changed Python file. After the panel fixes on 641380bd8c: the MCP unit tests (184 files, 5,363 passed) and MCP typecheck; the integration API, Domain Connect, integration model, products/workflows/backend and eval tests (3,469 passed, 1 failed); mypy and ruff on the changed Python. The one failure, test_ses_provider.py::test_delete_identity_removes_tenant_associations_first, is a master test outside this diff. It fails the same way on the pre-fix head in this ordering and passes alone. hogli build:openapi and hogli build:schema-mcp regenerated cleanly.

CI on the fork: the depot jobs never get a runner, so the change-detection jobs never run and Semgrep Checks Pass, MCP Tests Pass and Python code quality checks fail. The lane gate stands in until the PR opens upstream. Frontend formatting failed once on the skill's table, fixed in 89b56b97e4.

Proofs per qa-swarm PROOF.md:

  • Live run: gap. It needs a running stack with SES and a domain under DNS control.
  • Prod shape: gap, accepted by standing rule until 2026-11-02; read-only production access arrives then.
  • Post-deploy watch: owed after merge.
  • The eval suite itself did not run: it needs LLM gateway and Braintrust keys.

👉 Stay up-to-date with PostHog coding conventions for a smoother review.

Release status

  • This change is behind a feature flag and is not available to users

Docs update

Updated the OAuth development guide with the sender and Domain Connect access that scoped credentials get while the flag is on.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: Claude Code, Claude Opus 5.5 (claude-opus-5-5)

  • Recreated from the fork drafts feat(workflows): let agents set up an email sending domain via mcp #343 and fix(integrations): scope email sender verification and updates #352, then restacked on master 43333f81da9: 18 conflicting files, 9 of them generated and regenerated rather than taken from one side. The restack keeps master's eval flag overrides and test assertions next to this PR's.
  • Skills: /improving-drf-endpoints, /implementing-mcp-tools, /writing-tests, /writing-pr-descriptions, pr-description, modernize-pr, merge-risk, tdd.
  • Follow-up, not changed: integrations-email-partial-update needs the sender's current name, and no read tool returns it. Making name optional changes the API contract, so it is left for a separate PR.
  • Follow-ups from the panel: build the eval simulation on products/workflows/backend/tests/fakes; add an MCP test against the real API transport; find the test that leaks state into test_delete_identity_removes_tenant_associations_first.
  • Size: about 550 changed production lines outside generated files, tests, docs and the eval suite, above the 400-line split guide. Not split before the 2026-11-02 push; the reviewer decides whether the eval suite moves to its own PR.
  • Overlap: feat(integrations): add an email sender over MCP PostHog/posthog#125535 adds a create tool under the same name, integrations-email-create. Whichever lands second keeps one definition.
  • CodeRabbit: not run; it is retired on this repository.
  • Stacked on this PR: fix(workflows): keep one mail from label per email sending domain #569 (one MAIL FROM label per domain). Independent and on master: feat(workflows): expose read-only email sending readiness over mcp #570 (read-only sending readiness tools).
  • No customer material went into this PR. Fixtures use example.com and invented domains.

Decisions

Question Answer Who Where
Which flag gates the Workflows email work? One rollout flag, workflows-email-from-code; master's agent setup flag moves onto it 👤 Human map
Land #352 on its own? No, absorbed here: it only adds tests and guide text for these routes 🤖 Agent pending approval
Which organization does email domain verified group by? The sender's, so a verification in another organization's project lands there 🤖 Agent pending approval
Where does the redirect_uri check apply? Scoped tokens only; session requests keep master's handling 🤖 Agent pending approval
Which inputs do the email flag checks send? The web app's, through flag_identity, instead of a hand-built project group 🤖 Agent pending approval
Does the eval run turn the flag on for every suite? Yes, like master's other MCP flag overrides; a per-suite override needs a new harness option 🤖 Agent pending approval

Involvement: no grilling rounds, no prototypes. GPT-6.1 Sol (high) reviewed the restack in round 1 (one finding, fixed) and in four final reads (one finding, fixed). On 2026-11-01 a two-family panel reviewed the whole diff: nine GPT-6.1 Sol (high) lenses and a Claude Opus 5.5 (high) fresh-eyes lane. Round 2 raised 12 distinct findings: 6 fixed in code, 1 fixed in this body, 3 rejected, 2 follow-ups. Round 3 checked the fixes: 4 findings, all fixed. Final reads follow. Proof: command output; live run owed.

🤖 Generated with Claude Code

Silthus and others added 5 commits October 31, 2026 08:22
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add MCP tools that create an email sender, check Domain Connect support,
build a Domain Connect apply URL and update a sender, with typed request
schemas for their endpoints and scoped API key and OAuth access behind
the workflows-email-from-code flag. Point the tools at the email status
and verify tools master added, and add the setting-up-an-email-domain
skill and its eval suite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Absorb #352: the update tests for OAuth tokens, an
unresolved flag and the access restrictions that the other sender tests
do not cover, now on workflows-email-from-code, and the guide section on
scoped sender access. Verify keeps master's scoped access.

(cherry picked from commit 8064a1f)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ation

The event took its organization group from the acting user's current
organization, so a verification in another organization's project landed
on the wrong group. Pass the sender's organization, on both the verify
and the Domain Connect paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nner

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Silthus
Silthus force-pushed the email-domain-agent-setup branch from e057075 to 7386a38 Compare October 31, 2026 10:11
@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

🤖 CI report

✅ Complexity (TypeScript) — clean

Cyclomatic complexity above the limit in changed typescript files (10 for production files, 15 for test files). Warn only: worth simplifying when you next touch these functions.

⚠️ Bundle size — 🔺 +3.0 KiB (+0.0%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 75.14 MiB · 🔺 +3.0 KiB (+0.0%)

No file changed by more than 1000 B.

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

✅ Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.02 MiB · 25 files 🔺 +133 B (+0.0%) █████████░ 88.8% of 1.14 MiB
logged-out boot: index + App + bootApp (preloaded by every page, including /login)
src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
2.99 MiB · 622 files 🔺 +115 B (+0.0%) ██████████ 98.5% of 3.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
6.46 MiB · 2,235 files 🟢 -243 B (-0.0%) ██████████ 95.4% of 6.77 MiB
dashboard scene
src/scenes/dashboard/Dashboard.tsx
9.97 MiB · 3,730 files 🔺 +1.8 KiB (+0.0%) ██████████ 99.6% of 10.01 MiB
today home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
6.71 MiB · 2,337 files 🟢 -243 B (-0.0%) ██████████ 96.4% of 6.96 MiB
AI-first home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
7.28 MiB · 2,426 files 🟢 -243 B (-0.0%) ██████████ 96.7% of 7.53 MiB
events scene
src/scenes/activity/explore/EventsScene.tsx
9.40 MiB · 3,502 files 🔺 +1.8 KiB (+0.0%) ██████████ 98.0% of 9.59 MiB
web analytics scene
src/scenes/web-analytics/WebAnalyticsScene.tsx
10.36 MiB · 3,769 files 🔺 +1.8 KiB (+0.0%) ██████████ 95.6% of 10.83 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
7.99 MiB · 2,970 files 🔺 +1.8 KiB (+0.0%) ████████░░ 84.4% of 9.47 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/zod/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/billing/billingLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/ProductEmptyState/productSetupPreloadLogic.ts stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/dashboards/frontend/widgets/previews/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/wizard/frontend/runs/WizardRunDetailsDrawer.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayShell.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayContextPanelFloating.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodaySidePanel.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayTopBar.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/todayRailItems.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 zod/v4/locales/de.js stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/queries/validators.js stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/project-homepage/today/TodayReportPage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 packages/quill/packages/charts/ stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 products/posthog_ai/frontend/components/tool/widgets/VisualizationWidget.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 products/posthog_ai/frontend/components/tool/widgets/RecordingsWidget.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 products/posthog_ai/frontend/api/primitives.ts stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 src/scenes/notebooks/Notebook/notebookLogic.ts stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/validators.js stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/web-analytics/LiveMetricsDashboard/LiveWebAnalyticsMetrics.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 products/product_analytics/frontend/insights/trends/WorldMap/countryVectors.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 src/scenes/settings/SettingsMap.tsx stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 @jspm/core/nodelibs/browser/fs stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx

Largest files eagerly shipped from src/index.tsx
Size File
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
6.3 KiB ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js
4.7 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
4.0 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.7 KiB src/index.tsx
1.7 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.7 KiB src/lib/utils/bootTiming.ts
1.2 KiB src/RootErrorBoundary.tsx
949 B src/scenes/ChunkLoadErrorBoundary.tsx
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
86.6 KiB src/lib/api.ts
67.9 KiB src/lib/lemon-ui/icons/icons.tsx
41.9 KiB ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js
36.4 KiB ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js
27.0 KiB ../node_modules/.pnpm/tailwind-merge@2.2.2/node_modules/tailwind-merge/dist/bundle-mjs.mjs
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
86.6 KiB src/lib/api.ts
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
86.6 KiB src/lib/api.ts
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/activity/explore/EventsScene.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/web-analytics/WebAnalyticsScene.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
187.9 KiB src/queries/validators.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
316.5 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of PostHog#32479

✅ Toolbar bundle — eager 2.33 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.33 MiB · 19 files 🔺 +115 B (+0.0%) ████░░░░░░ 40.8% of 5.72 MiB
Deferred (lazy) 2.11 MiB · 42 files no change n/a — loads on demand
Loader dist/toolbar.js 1.2 KiB no change █░░░░░░░░░ 6.0% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
941.8 KiB dist/toolbar/toolbar-app-CNZCJTDY.css
695.8 KiB dist/toolbar/chunk-chunk-NUWPCNXY.js
261.2 KiB dist/toolbar/chunk-chunk-T5DKNJQU.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
130.4 KiB dist/toolbar/chunk-chunk-KDUJEIKP.js
75.7 KiB dist/toolbar/toolbar-app-TP2JYJFO.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
33.8 KiB dist/toolbar/chunk-chunk-FR2SFTP5.js
21.7 KiB dist/toolbar/chunk-chunk-2P7IMPQ2.js
6.8 KiB dist/toolbar/chunk-chunk-DV7IWQNF.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

✅ Dist folder size — 🔺 +26.3 KiB (+0.0%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 966.36 MiB · 🔺 +26.3 KiB (+0.0%)

ℹ️ MCP UI apps size — 35 app(s), 29120.9 KB JS

Built size of each MCP UI app (main.js + styles.css).

App JS CSS
debug 844.3 KB 211.6 KB
explain-chart 1117.7 KB 211.6 KB
action 767.7 KB 211.6 KB
action-list 835.3 KB 211.6 KB
cohort 766.7 KB 211.6 KB
cohort-list 834.3 KB 211.6 KB
email-template 766.6 KB 211.6 KB
error-details 771.6 KB 211.6 KB
error-issue 768.9 KB 211.6 KB
error-issue-list 836.8 KB 211.6 KB
experiment 832.4 KB 211.6 KB
experiment-list 836.1 KB 211.6 KB
experiment-results 834.3 KB 211.6 KB
feature-flag 834.7 KB 211.6 KB
feature-flag-list 838.4 KB 211.6 KB
feature-flag-testing 770.0 KB 211.6 KB
inline-scan 767.2 KB 211.6 KB
insight-actors 833.8 KB 211.6 KB
llm-costs 831.1 KB 211.6 KB
session-recording 769.0 KB 211.6 KB
survey 768.3 KB 211.6 KB
survey-global-stats 831.1 KB 211.6 KB
survey-list 836.0 KB 211.6 KB
survey-stats 831.1 KB 211.6 KB
trace-span 767.1 KB 211.6 KB
trace-span-list 835.2 KB 211.6 KB
vision-observation-list 834.4 KB 211.6 KB
workflow 767.1 KB 211.6 KB
workflow-list 834.7 KB 211.6 KB
workflow-setup-status 766.7 KB 211.6 KB
query-results 1089.6 KB 211.6 KB
render-ui 1193.6 KB 211.6 KB
visual-review-snapshots 771.6 KB 211.6 KB
workflow-data-suggestions 769.4 KB 211.6 KB
workflow-sending-rules 768.1 KB 211.6 KB
ℹ️ MCP agent API — agent-facing tool changes

What this PR changes for agents, from the tool schema snapshots and tool definitions.

Tools added (4): integrations-domain-connect-apply-url-create (431 chars), integrations-domain-connect-check-retrieve (435 chars), integrations-email-create (1,388 chars), integrations-email-partial-update (1,747 chars)

Tools changed (2):

Tool Params Scopes Annotations Schema chars
integrations-email-status-retrieve +id +refresh n/a -> 298
integrations-email-verify-create +id n/a -> 142
ℹ️ frontend-layers — no base comparison available

Static imports from a lower frontend layer into a higher one (layers, lowest first: kernel, shell, query, features). Compared with the base branch, so an import that a PR also adds to layer-baseline.txt still shows here. Sizes are the source bytes on the eager path of every logged-in page.

Layer Eager source bytes Δ vs base
kernel 4.06 MiB (no base measurement)
shell 2.98 MiB (no base measurement)
query 338.8 KiB (no base measurement)
features 2.91 MiB (no base measurement)

ℹ️ No base report, so new and removed imports are not listed.

Download the interactive layer graph for this PR.

Posted automatically by check-layers

Silthus and others added 6 commits November 1, 2026 12:22
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The eval's simulated SES provider had no status clients, so an agent that
read a sender's records through email/status got a 500. It now answers
the status reads with the identity's tokens and MAIL FROM domain, binds
the team for them, and seeded verified senders carry their MAIL FROM
domain. Simulated zones have no authoritative nameservers, so the status
check reads them through the simulated resolver.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he app

- integrations-email-create takes the typed sender config, so the provider
  defaults to ses and a config with only email and name no longer returns 400
- the email flag checks send the same person and group inputs as the web
  app through flag_identity, so a flag released to a project id matches
- the skill's manual handoff merges SPF into an existing record
- the member eval case publishes its records, so the agent reaches verify
  and gets the 403 the case scores
- the new eval modules carry no docstrings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dns.resolver.resolve delegates to Resolver.resolve, so one patch covers both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Silthus added a commit that referenced this pull request Nov 1, 2026
The email flag helper now lives in posthog/models/integration/email.py and
builds its inputs with flag_identity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Create ignores setup_method, so the create tool no longer advertises it.
The create tool test also checks the endpoint, and the skill keeps one
sentence per line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Silthus

Silthus commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

Moved to PostHog#127296.

@Silthus Silthus closed this Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant