Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/internal/workflows-email-auto-pause.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ Batch job metrics count toward their parent workflow, and discovery gates sum at
- Staff pause from Django admin with `paused_by="staff"`. Only staff can resume those: the customer's resume endpoint refuses with a contact-support message, the banner shows no button, and the email says to contact support.
- Resuming stamps `email_sending_resumed_at`, and every detector window then starts at the first full hour after it. A workflow that keeps misbehaving re-trips within a couple of hours on fresh feedback only; resuming without fixing anything cannot outrun the detector.

## Read-only inspection through MCP

`workflows-email-sending-suspension` is behind the default-off `workflows-email-from-code` flag.
`workflows-reputation-get` is behind `workflows-sending-tier-requests`.

`workflows-email-sending-suspension` reads the project's suspension flag, time, and reason. `workflows-reputation-get` reads sending health, visible workflows' pause state, and the [sending allowance](workflows-email-sending-tiers.md) when permitted. Both require `hog_flow:read` and preserve the API's project and object permissions. Project-wide reputation and allowance may be null for callers with only object-level access. Null, missing, denied, or unavailable data means unknown, not healthy, zero, or unlimited. Reported limits and usage do not guarantee available quota.

Use `workflows-get` to inspect `email_sending_paused_at` and `email_sending_paused_reason` for a particular workflow, including one absent from reputation rows. Use `integrations-list` with `kind=email` to inspect native senders' `config.verified`: true means verified, false means unverified, and a missing flag means unknown. An empty list means no visible sender after checking all pages. Other raw integration configuration remains excluded. These reads do not resume sending or verify a domain.

## Rollout

`WORKFLOW_EMAIL_AUTO_PAUSE_ENABLED` (default off) gates every automatic write; warnings and pauses arm together.
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -621,8 +621,8 @@ export const FEATURE_FLAGS = {
WORKFLOWS_COHORT_CONDITIONS: 'workflows-cohort-conditions', // owner: @meikelmosby #team-workflows
WORKFLOWS_CUSTOMERIO_IMPORT: 'workflows-customerio-import', // owner: @dmarchuk #team-workflows, import Customer.io automations as draft workflows
WORKFLOWS_DESTINATION_SUGGESTION: 'workflows-destination-suggestion', // owner: #team-workflows, offers workflows instead of a new email tool destination
WORKFLOWS_EMAIL_DOMAIN_AGENT_SETUP: 'workflows-email-domain-agent-setup', // owner: @silthus #team-workflows
WORKFLOWS_EMAIL_DOMAIN_WIZARD: 'workflows-email-domain-wizard', // owner: @silthus #team-workflows
WORKFLOWS_EMAIL_FROM_CODE: 'workflows-email-from-code', // owner: @silthus #team-workflows
WORKFLOWS_EMAIL_SENDER_ROTATION: 'workflows-email-sender-rotation', // owner: @arthurdedeus #team-workflows
WORKFLOWS_INTERNAL_EVENT_FILTERS: 'workflows-internal-event-filters', // owner: @haven #team-workflows
WORKFLOWS_LINEAR_VIEW: 'workflows-linear-view', // owner: #team-workflows
Expand Down
2 changes: 1 addition & 1 deletion posthog/api/integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -2823,7 +2823,7 @@ def email_status(self, request: ValidatedRequest, **kwargs: Any) -> Response:
},
send_feature_flag_events=False,
)
for flag in ("workflows-email-domain-wizard", "workflows-email-domain-agent-setup")
for flag in ("workflows-email-domain-wizard", "workflows-email-from-code")
):
raise NotFound()
instance = self.get_object()
Expand Down
9 changes: 6 additions & 3 deletions products/integrations/mcp/tools.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ tools:
after adding DNS records until status is verified, waiting at least 10 seconds between calls. Pass
refresh=true right after changing DNS to skip the 10 second cache. It does not change DNS or SES, and it
does not mark the sender verified: once status is verified, call integrations-email-verify-create.
feature_flag: workflows-email-domain-agent-setup
feature_flag: workflows-email-from-code
integrations-email-verify-create:
operation: integrations_email_verify_create
enabled: true
Expand All @@ -90,7 +90,7 @@ tools:
Record that an email sender's domain is verified, by integration ID, so its senders can send. Call it once
integrations-email-status-retrieve reports status verified. It asks SES to check the domain again and
returns status success when SES has verified it. Needs a project admin.
feature_flag: workflows-email-domain-agent-setup
feature_flag: workflows-email-from-code
integrations-github-repos-retrieve:
operation: integrations_github_repos_retrieve
enabled: true
Expand Down Expand Up @@ -155,7 +155,9 @@ tools:
List all third-party integrations configured in the current project. Returns each integration's type (kind),
display name, non-sensitive configuration, error status, and creation metadata. Common kinds include slack,
github, hubspot, salesforce, and various ad platforms. Sensitive credentials (access tokens, secrets) are
never serialized.
never serialized. For native email senders, filter kind=email and inspect config.verified: true means
verified, false means unverified, and a missing flag means unknown. An empty result means no visible
sender; check all pages before concluding none is configured. Other raw configuration is excluded.
response:
include:
- id
Expand All @@ -164,6 +166,7 @@ tools:
- errors
- created_at
- created_by
- config.verified
integrations-users-retrieve:
operation: integrations_users_retrieve
enabled: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def test_status_reads_ses_without_writing_to_it(
writes_after_create = list(self.world.ses.writes)
self.feature_flags.side_effect = lambda key, *args, **kwargs: {
"workflows-email-domain-wizard": wizard_enabled,
"workflows-email-domain-agent-setup": agent_enabled,
"workflows-email-from-code": agent_enabled,
}.get(key, False)
response = self.get_status(sender)
assert response.status_code == expected_status, response.json()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,6 @@ export const AgentHandoff: Story = {
stage: (_, id) => emailDomainAgentLogic.findMounted({ id })?.actions.openAgentModal(),
},
parameters: {
featureFlags: [FEATURE_FLAGS.WORKFLOWS_EMAIL_DOMAIN_WIZARD, FEATURE_FLAGS.WORKFLOWS_EMAIL_DOMAIN_AGENT_SETUP],
featureFlags: [FEATURE_FLAGS.WORKFLOWS_EMAIL_DOMAIN_WIZARD, FEATURE_FLAGS.WORKFLOWS_EMAIL_FROM_CODE],
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ export const emailDomainAgentLogic = kea<emailDomainAgentLogicType>([
selectors({
agentSetupEnabled: [
(s) => [s.featureFlags],
(featureFlags: FeatureFlagsSet): boolean =>
!!featureFlags[FEATURE_FLAGS.WORKFLOWS_EMAIL_DOMAIN_AGENT_SETUP],
(featureFlags: FeatureFlagsSet): boolean => !!featureFlags[FEATURE_FLAGS.WORKFLOWS_EMAIL_FROM_CODE],
],
setupPrompt: [
(s) => [
Expand Down
12 changes: 12 additions & 0 deletions products/workflows/mcp/tools.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ tools:
shape, an archived workflow, a workflow with a staged draft, or one that is already a broadcast. Returns the
id and origin_product, plus _posthogUrl, the broadcast link.
url_prefix: /broadcasts
workflows-email-sending-suspension:
operation: hog_flows_email_sending_suspension_retrieve
enabled: true
feature_flag: workflows-email-from-code
title: Get project email sending suspension
description: >
Read whether workflow email sending is suspended for the current project, with the suspension time and
reason. A false suspension flag only means the project is not suspended; it does not establish sender
verification, workflow readiness, reputation, or available quota. Use workflows-reputation-get for
sending health and allowance, integrations-list (kind=email) to inspect senders, and workflows-get to
inspect a workflow's email_sending_paused_at and email_sending_paused_reason. Missing data or an
unavailable tool means unknown. This tool changes nothing.
workflows-create:
operation: hog_flows_create
enabled: true
Expand Down
22 changes: 19 additions & 3 deletions services/mcp/schema/generated-tool-definitions.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 19 additions & 3 deletions services/mcp/schema/tool-definitions-all.json
Original file line number Diff line number Diff line change
Expand Up @@ -8719,7 +8719,7 @@
"openWorldHint": true,
"readOnlyHint": true
},
"feature_flag": "workflows-email-domain-agent-setup"
"feature_flag": "workflows-email-from-code"
},
"integrations-email-verify-create": {
"description": "Record that an email sender's domain is verified, by integration ID, so its senders can send. Call it once integrations-email-status-retrieve reports status verified. It asks SES to check the domain again and returns status success when SES has verified it. Needs a project admin.",
Expand All @@ -8735,7 +8735,7 @@
"openWorldHint": true,
"readOnlyHint": false
},
"feature_flag": "workflows-email-domain-agent-setup"
"feature_flag": "workflows-email-from-code"
},
"integrations-github-repos-retrieve": {
"description": "List the repositories accessible to a GitHub integration (by integration ID). Serves the cached repository list from the GitHub App installation. Supports `search` (case-insensitive name match), `limit` (default 100, max 500), and `offset` query parameters. Returns repository id, name, and full_name (owner/repo), a has_more flag, a total count, and next_offset. When has_more is true, call again with `offset` set to next_offset to get the next page. Set `compact` to false only when you need the extra repository details. Use this to validate that a repository is accessible to the integration before referencing it (e.g. when creating a GitHub data warehouse source).",
Expand Down Expand Up @@ -8783,7 +8783,7 @@
}
},
"integrations-list": {
"description": "List all third-party integrations configured in the current project. Returns each integration's type (kind), display name, non-sensitive configuration, error status, and creation metadata. Common kinds include slack, github, hubspot, salesforce, and various ad platforms. Sensitive credentials (access tokens, secrets) are never serialized.",
"description": "List all third-party integrations configured in the current project. Returns each integration's type (kind), display name, non-sensitive configuration, error status, and creation metadata. Common kinds include slack, github, hubspot, salesforce, and various ad platforms. Sensitive credentials (access tokens, secrets) are never serialized. For native email senders, filter kind=email and inspect config.verified: true means verified, false means unverified, and a missing flag means unknown. An empty result means no visible sender; check all pages before concluding none is configured. Other raw configuration is excluded.",
"category": "Integrations",
"feature": "integrations",
"summary": "List integrations",
Expand Down Expand Up @@ -17647,6 +17647,22 @@
},
"feature_flag": "workflows-destination-suggestion"
},
"workflows-email-sending-suspension": {
"description": "Read whether workflow email sending is suspended for the current project, with the suspension time and reason. A false suspension flag only means the project is not suspended; it does not establish sender verification, workflow readiness, reputation, or available quota. Use workflows-reputation-get for sending health and allowance, integrations-list (kind=email) to inspect senders, and workflows-get to inspect a workflow's email_sending_paused_at and email_sending_paused_reason. Missing data or an unavailable tool means unknown. This tool changes nothing.",
"category": "Workflows",
"feature": "workflows",
"summary": "Get project email sending suspension",
"title": "Get project email sending suspension",
"required_scopes": ["hog_flow:read"],
"api_operations": ["GET /api/projects/{project_id}/hog_flows/email_sending_suspension/"],
"annotations": {
"destructiveHint": false,
"idempotentHint": true,
"openWorldHint": true,
"readOnlyHint": true
},
"feature_flag": "workflows-email-from-code"
},
"workflows-enable": {
"description": "Enable / activate a draft workflow and start processing events. From then on it runs on real people: test it first with workflows-test-run and get the user's explicit approval before invoking - don't enable on your own initiative. Once live, content edits stage as a draft you publish with workflows-publish.",
"category": "Workflows",
Expand Down
15 changes: 14 additions & 1 deletion services/mcp/src/generated/workflows/api.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion services/mcp/src/tools/generated/integrations.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading