Repository navigation
Conversation
The migrate group keeps Statsig's mapping and SDK reference under references/statsig/, and its step files point there, but the generator copied only the top-level reference files. Copy references/<variant-id>/ into each variant's bundle, and nothing of the other variants. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Move the sender setup of send-transactional-email's STEP 3 into
context/shared/email-sender-setup.md, so the email migration skill
includes the same text. A partial now takes the indentation of its
{{> name}} line on every line, so it nests under a step. The built
send skill is unchanged byte for byte.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
v0 prepares a move off Resend and changes no send call site. It finds every Resend send, classifies each one as ready to move or staying on Resend with a reason, sets up the PostHog sender next to Resend's DNS records, imports Resend's suppression list when the import tool exists, hands over the project secret key, checks the sending tier, and writes posthog-migrate-email-resend-report.md with a summary block. Steps are provider-neutral; references/resend/ holds what is specific to Resend. Statsig and Resend now publish as wizard migrate subcommands. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Fixture runs wrote reasons into the summary block, which the Wizard can't parse, and counted a forwarding helper as one site or as each caller. The report step now shows bare values, and a site is the place that decides a send's content and fields. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…the sending skill The send-transactional-email skill is gone from this stack, so migrate-email bundles the transactional email pages and names the sending-transactional-emails skill for the general move. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Silthus
force-pushed
the
feat/migrate-email-resend
branch
from
October 31, 2026 09:53
0a48cff to
6e902dc
Compare
Silthus
changed the base branch from
feat/send-transactional-email-skill
to
main
October 31, 2026 09:53
… PostHog's reply-to rules The preflight looked for two MCP tools that don't exist. It now looks for the make-transactional pair, and a missing pair records the API as not confirmed instead of stopping, because it can also mean a missing scope. The mapping now keeps a site on Resend for reply-to addresses with a name or more than 10, and lists every reserved header and the header and tag length limits. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…partial imports in migrate-email Step 1 now admits the SMTP host and a framework mailer and needs at least one send; step 3 stops when it finds no site. A suppression import that stops partway stays unticked and lands in the report's "Before cutover" list. A template site needs its content from the person or stays on Resend. The sender setup is inlined into step 4, which keeps the existing `from` domain and records an unverified domain instead of waiting. AGENTS.md says the migrate subcommands run once the wizard runs migrate as a family. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…e loop The selected variant's `references/<variant-id>/` files now go through the same loop as the root reference files, so the separate copy helper is gone. The partial expander drops the indentation it gained for the sender partial, which nothing includes any more, and the bundle test drops the migrate-statsig case that guarded nothing. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…tes from files Step 4 records a domain as not verified, with its records or Domain Connect link, when the person can't publish them during the run. Step 3 asks the person to save each template from the dashboard to a file outside the repository and reads it, since the Wizard can't take pasted HTML. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Owner
Author
|
Moved to PostHog#450. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Moved here from PostHog#435, closed on 2026-10-25 so this fork stack is the only copy. It opens upstream again after review.
This revision
Restacked on
mainon 2026-10-31. What changed:main. feat(skills): add send-transactional-email skill #3 (the send skill) is closed, because feat(messaging): add a skill that offers and sets up transactional emails PostHog/posthog#125415 addssending-transactional-emailswithreferences/moving-from-other-providers.md.6e902dcbundles the posthog.com transactional email pages (transactional-emails.mdandtransactional-emails/api.md) and names thesending-transactional-emailsskill for the general move.0286e23(review fixes): the preflight looks for theworkflows-make-email-template-transactional-prepareand-executetools. When they are missing, it names both causes (a missinghog_flow:writescope, or transactional email off for the project), recordsapi: not confirmed, and continues; it never probes with a mutating tool. The[ABORT] transactional email api not enabledline is gone. The mapping keeps areplyTowith a display name, more than 10 entries, or a value built at run time on Resend, and lists the reservedDKIM-SignatureandReceivedheaders and the header and tag limits.41ca66a(QA swarm round 3): step 1 also admits Resend's SMTP host and a framework mailer and needs at least one send; step 3 stops when it finds no site. A suppression import that stops partway stays unticked and lands in "Before cutover". Atemplatesite needs its content from the person, or stays withtemplate content not checked. The sender setup is inlined into step 4, which keeps the existingfromdomain and records an unverified domain instead of waiting.0e526b9(QA swarm round 3): the selected variant'sreferences/<variant-id>/files go through the same loop as the root reference files, so the separate copy helper is gone, and the partial expander drops the indentation it gained for the sender partial. A shadow build of every bundle shows no output change outside the rewritten step files.4ad8c6e(QA swarm fixes round): step 4 records a domain as not verified, with its records or Domain Connect link, when the person can't publish them during the run, and step 3 asks the person to save each template from the dashboard to a file outside the repository and reads it.moving-from-other-providers.md. That reference maps any provider's sends to a PostHog template. This skill adds the Resend-specific preparation: send detection for the SDK, REST, and SMTP; the sender and DNS setup next to Resend's records; the suppression list import; the key handover; the sending-tier check; and a report the Wizard parses.Problem
A team on Resend that wants its transactional email on PostHog has no skill for the move. Its coding agent would have to find every send, decide which ones PostHog can take, set up the sender without breaking Resend's DNS, and carry the suppression list over, all by hand.
With this skill,
migrate-email-resenddoes the preparation and changes no send call site: it finds every Resend send, classifies each one as ready to move or staying on Resend with a reason, sets up the PostHog sender next to Resend's records, imports Resend's suppression list, hands over the secret key, checks the sending tier, and writesposthog-migrate-email-resend-report.md. The next slice moves the sites.Important
Based on
mainnow. The send skill it used to stack on (#3) is closed, because PostHog/posthog#125415 adds thesending-transactional-emailsskill. This skill names that skill for the general move and keeps only the Resend-specific preparation.A clean build needs the transactional email pages of PostHog/posthog.com#21564 on posthog.com (
transactional-emails.mdandtransactional-emails/api.md). Until they publish,pnpm buildstops on a404for thoseshared_docs.Tracking: Silthus/posthog#539, slice 14 of the Resend parity spec. Contract: PostHog/posthog#120921.
Impact
Pays into Grow Workflows through Switched orgs: teams that move their transactional email from Resend to PostHog. Not measured yet: it needs the migration marker on each send (PostHog/posthog#120628) and the Wizard's migration summary. Expected move: large, up, once the cutover slice and
wizard migrate resendship. This slice alone moves no mail.Merge Danger
Warning
🟡 Merge risk: medium · two-way door (merge-risk rubric)
skill-menu.jsonchanges for the Wizard:migrate-statsigmoves fromcommand: migratetoparentCommand: migrate, command: statsig, andmigrate-email-resendjoins asmigrate resend. Today's Wizard registerswizard migratenatively with the hardcoded skill idmigrate-statsigand never reads these entries, so Statsig keeps working;wizard migrate statsigandwizard migrate resendrun once the Wizard turnsmigrateinto a family.references/<variant-id>/folder now ships through the reference loop (onlymigratehas one today). A shadow build of all 446 bundles without example projects is byte-identical outside this skill.Summary
A new skill group,
context/skills/migrate-email/, with one variant per provider. Resend is the first. The seven steps are provider-neutral;references/resend/holds everything specific to Resend, so a SendGrid or Postmark variant is mostly three reference files.api.resend.com,smtp.resend.comin code or mail config, or a framework'sresendmailer, with at least one send. React Email or Nodemailer alone, or a Resend client used only for contacts or domains, is not a migration:[ABORT] no email provider sends foundbefore any change. Step 3 stops the same way when it finds no site.template,react,html,text) and fields, written to.posthog-email-migration-plan.md. Atemplatesite needs a copy of the template from the person, or stays withtemplate content not checked.mapping.mddecides field by field:cc,bcc,headers,tagsandattachmentsmove within the contract's limits;scheduledAt,topicId, batch sends, SMTP, more than oneto,last_eventreads, and error names PostHog lacks stay on Resend with a reason.fromdomain, on the domain the app already sends from. Resend's records stay; PostHog's MAIL FROM label must not be Resend'ssend. Pending DNS, a 403, or missing sender tools record the domain as not verified, and the run goes on.email-suppressions-add, from the dashboard CSV orGET /suppressions. Addresses never land in a file of the repository, the plan, or the report. The phase is ticked only when every entry is imported; a partial import keeps its count and lands in "Before cutover". That tool does not exist yet (see Open below): until it does, the step recordsnot importedand the report tells the person to add them before cutover.phs_key withhog_flow:writeforPOSTHOG_PROJECT_SECRET_API_KEY. The report lists every other place the Resend key lives, such as CI and docs.Other changes:
description.mdnames thesending-transactional-emailsskill (feat(messaging): add a skill that offers and sets up transactional emails PostHog/posthog#125415) for a general move off any provider, andmapping.mdpoints attransactional-emails/api.md.fix(skills): the generator copied only top-level reference files, somigrate-statsigshipped withoutreferences/statsig/mapping.mdandsdk-reference.mdthat its steps tell the agent to read. Both now ship, through the same loop as the root files.AGENTS.mdlists the migrate subcommands and says they run once the Wizard runsmigrateas a family.Evidence
Bundle and generator tests (vitest, red then green):
migrate-email-skill.test.js:migrate-email-resendbuilds with everyreferences/...path it names present in the bundle, the API page and the Resend files ship without the send skill, and Resend and Statsig publish asmigratesubcommands. Red before the skill:expected undefined to be defined.skill-generator-references-folder.test.js: a variant ships its own folder and no other variant's. Red before the fix:ENOENT ... references/statsig/mapping.md. Green before and after the0e526b9refactor.4ad8c6e:vitest run scripts/plugins/tests scripts/lib/tests, 29 files, 224 tests pass. Fork CI runs no workflows on pull requests.0286e23against0e526b9): every skill without example projects, 446 bundles, built withgenerateSkilland stubbed docs on both commits. Only the sixmigrate-email-resendstep files whose text41ca66achanged differ;migrate-statsigwith itsstatsig/folder and every other bundle are byte-identical. Saved in proof storage.pnpm buildstops on the404for the posthog.com pages until docs(workflows): add the transactional email API page PostHog/posthog.com#21564 publishes them. The earlier revision built with the page stubbed in.docs-cache.Ranking in the MCP's
SkillCatalog(itsskill-catalog.tsfrom PostHog/posthog master over every built bundle):migrate-statsig(126)migrate-email-resend(1162)feature-flags-ios(138)migrate-email-resend(990)omnibus-send-transactional-email(133)migrate-email-resend(1011)Agent runs on fixture apps. Claude Code on Sonnet 5.5 with only this skill installed, headless, the PostHog MCP not connected, and the person's answers given in the prompt. Every run changed no send call site: the diff is one commented
POSTHOG_PROJECT_SECRET_API_KEYline in the env example, plus the report.resendSDK (PostHog/wizard-workbench#2221)sendUserEmail. Summary parses every timefetch('https://api.resend.com/emails'), noresendpackagescheduled_at), the invoice stays (attachment bypath). The Resend key in the deploy workflow is listedThe first two REST runs found two skill gaps, fixed in
0a48cff: a run wrote reasons into a summary value, and runs disagreed whether a helper that only forwards its callers' payload is one site. The reruns agree and parse.Happy fixture report, excerpt
cliEntriesthe Wizard reads, the MCPSkillCatalogranking, and the files an agent run leaves in a fixture.pnpm exec vitest run scripts/lib/tests/migrate-email-skill.test.jspasses.41ca66a. No run inside the Wizard (wizard migrate resendneeds the Wizard PR), no run with the PostHog MCP connected, so sender creation, DNS publish, and sender verification on a deployed project are unproven. The suppression import has no tool to run against yet.pnpm buildneeds docs(workflows): add the transactional email API page PostHog/posthog.com#21564's pages. From the Wizard'smainsource:wizard migratekeeps running Statsig,wizard migrate statsig|resendfails with an unknown-argument error, andwizard skill listprints the subcommand paths before they run.Decisions
migrate-emailgroup, one variant per provider; Resend parts stay in its folderemail-suppressions-add, and recordnot importeduntil it exists; the existing one-address route has no MCP toolsuppressions_readyafter the spec's five keysmigratenow; today's Wizard ignores the entrymainwithout #3, and namesending-transactional-emailsinsteadmigrated_fromsetup wizard finishedevent; no new eventapi: not confirmedand continue, instead of aborting; never probe with a mutating toolreplyTothe API can't takemigratedefault leafdefault: true: it would hideresendfrom the family picker and not save CI scripts, which need a subcommand either way; the release notes belong to the Wizard PR that makesmigratea familyOpen: the server half of the suppression import, a bulk route and the
email-suppressions-addMCP tool in PostHog/posthog. Recommended as its own slice.Open: accept the cross-version gap (prod-shape is accepted by the standing rule until 2026-11-02). Recommended: accept; the check runs once the posthog.com pages publish and the manifest builds.
Follow-up: the Wizard PR that turns
migrateinto a family names the barewizard migratechange in its release notes (CONTRIBUTING.md, flat to family, step 2).Involvement: no grilling rounds, no prototypes, one Opus 5.5 review of the strand (PostHog#435 and PostHog#436), and one GPT-6.1 Sol (high) round on this revision (two findings, both fixed) with a clean read of the fixes. QA swarm 2026-11-01: round 3, the first two-family panel (Opus 5.5 fresh eyes, GPT-6.1 Sol on nine lenses), round 4 on the fixes (six lenses), and one clean final read: 12 findings, 11 fixed, 1 rejected (Statsig default leaf), 1 follow-up. Proof captured. Its findings were on rules the cutover uses (suppressed recipients, subjects, fallback quoting, idempotency across providers), and the fixes landed in PostHog#436, where those rules apply.
🤖 Generated with Claude Code