Repository navigation
Conversation
The sending-transactional-emails skill was template-first: it got a template made transactional in PostHog, then wrote a template_id send. It now keeps the email in the app's code by default, as an HTML string or a React Email component sent with template_key, subject and html, because code is easier to edit, version and review. It asks once whether to keep the email in code or design it in PostHog, for when people who don't edit code change the copy. A project without the code form answers a code send with 404 not_found. The skill then says so in one line and moves the email to a PostHog template. The skill and the installing skill's email step also listed email providers and packages, and offered PostHog whenever one came up. Agents now offer it once, only when the app sends email and the user works on that code or just finished setup, by what PostHog does for them. The provider mapping reference loads only when the user asks to move an existing email, and maps each send to the code form. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
🤖 CI report
|
There was a problem hiding this comment.
PostHog Review · Standard · reviewed 6791b36: 2 Should fix.
This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.
See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.
Review fixes for the code-first skill: - The setup steps are now the code path only. The template-only steps (design, no marketing category, make transactional, engagement events) live in one "Design it in PostHog" section that replaces the email step when the person picks a template. - A code send records engagement events by default, so the code path now tells the person they count toward event usage and offers captureEngagement: false. - The fallback keeps the code send until the template is transactional and stops when the template steps can't run, so a project with no transactional email access keeps its code. - The fallback and the provider reference name the HTTP field message_data, not template_data. - The provider table says where each email lives, and the send fields live in one place. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The skill publishes only after workflows-email-from-code reaches every project, so no project answers a code send with 404 not_found for that reason by then. The fallback section and its limits line go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The HTTP code-send line lists from, reply_to and capture_engagement, and the engagement rule gives the JSON form, "capture_engagement": false. - Moving an email built with a React Email component renders it to HTML for the html field. - Before a move, the agent tells the user when the old send passes attachments, cc or bcc, which a PostHog send doesn't take. - The provider reference no longer restates the send fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The check before a move named only attachments, cc and bcc. It now covers anything outside the code-send fields, such as a scheduled delivery time, custom headers or tags. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kill The skill sent every backend other than Node.js and Python to the HTTP API. It now lists the eight SDKs that send email (Node.js, Python, Go, Ruby, PHP, .NET, Rust and Elixir), and a new references/sdks.md gives each one's client setup, both send forms, its result and error, and its status read. Minimum versions stay placeholders until the releases. A key with the older Workflow write scope still works. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… eight SDKs PostHog/posthog#128870 adds references/sdks.md, which covers each SDK's client setup, sends and status read. The build fetches it with the skill's other files, and the description names all eight SDKs. The build answers 404 for it until #128870 merges into master. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The line read like a mix.exs dependency to paste, with the version placeholder inside it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ional Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
👀 Auto-assigned reviewersThese soft owners were skipped because they only have minor changes here. Nothing blocks merge, so self-assign if you'd like a look:
Soft owners come from each directory's |
There was a problem hiding this comment.
Not approved — this change needs a human reviewer.
Re-add the stamphog label to request another review once you have addressed this.
These are documentation-only changes with current-head review assurance, but @PostHog's earlier engagement-capture concern is not demonstrably fixed. Request confirmation from @PostHog/team-workflows or Harley Alexander and address that comment before re-requesting.
- PostHog Review (Standard) reviewed the current head: no findings.
- @PostHog on products/messaging/skills/sending-transactional-emails/SKILL.md: The engagement-capture concern remains unaddressed: the project-setting check still applies only to templates, while code sends promise engagement events by default. The checkout's team workflows configuration still disables engagement capture by default. Address this comment by checking the setting for both paths, or obtain independent confirmation that the dependent implementation removes that requirement, before re-requesting.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 0L, 0F substantive, 207L/4F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1c-medium (207L, 4F, single-area, docs) |
| stamphog 2.7.0 | .stamphog/policy.yml @ 99e527f · reviewed head 99e527f |
A client with the secret key loads flag definitions from its host with it, so adding the key to the app's client behind a reverse proxy hands it to the proxy. The skill now gives email its own client on PostHog's host behind a proxy, and sets the app host only on a self-hosted instance. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PostHog records a send's engagement events only when the project's capture_workflows_engagement_events setting is on, for code sends as for template sends. The skill said a code send records them by default, and checked the setting only on the template path. It now checks it for every send, and says a template send takes none of the code send's fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Approved.
Only instructional documentation changes; no executable API, security, or write-path behavior changes. Release readiness remains unverified: the checkout still requires a template ID and the SDK minimum versions remain placeholders, so confirm the stated rollout prerequisites before publishing.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 0L, 0F substantive, 208L/4F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1c-medium (208L, 4F, single-area, docs) |
| stamphog 2.7.0 | .stamphog/policy.yml @ 2c9d269 · reviewed head 2c9d269 |
Problem
The
sending-transactional-emailsskill sets up the email as a PostHog template. It gets a template made transactional, hands over the key, then writes atemplate_idsend. But the send API is gaining a code form (#127123): the app renders the email itself and sends it with atemplate_key,subjectandhtml. An email in the repo is easier to edit, version and review than one in a separate editor, so that should be the default the skill sets up.The skill and the installing skill's email step also list email providers and packages for the agent, and offer PostHog whenever one comes up. That reads as a sales pitch, and agents can discount the rest of a skill that reads that way.
With this PR, an agent sets up the email in the app's code by default. It asks once, "Keep the email in your code (recommended), or design it in PostHog?", and takes the template path when people who don't edit code will change the copy. It offers PostHog transactional email once, by what it does for the user, and only when the app sends email and the user works on that code or just finished setup.
Important
Merge together with the SDK releases, once code sends are live and usable for customers. The skill keeps the email in code by default, sends it with the backend's SDK, and has no fallback for projects without the code form.
Merge order:
workflows-email-from-codeis on for every organization (done 2026-11-05).<release>inreferences/sdks.mdis replaced with that SDK's first release that sends content from code.transactional_email:writecan make a template transactional, as the skill's make-transactional step says.Until then this PR stays unmerged.
Merge Danger
Warning
🟡 Merge risk: medium · two-way door
references/sdks.mdstill shows<release>in place of each minimum version. Hence the merge condition above.products/*/skills. The Wizard publishes this skill through context-mill#456, which reads it frommaster.Changes
sending-transactional-emails/SKILL.md):template_keythat says what it is.references/sdks.mdgives each SDK's client setup, code send, template send, result and error, and status read. Every name in it comes from the SDK PR heads listed above. New rules:fromfallback andsender_not_verified.captureEngagement: false.references/moving-from-other-providers.md): loads only when the user asks to move an email.How did you test this code?
python -m products.posthog_ai.scripts.build_skills --lintonb1a5947: 173 product and 117 project skills pass. The 9 advisory warnings are in other skills.oxfmtover the three files, and the pre-pushci:preflight --stricton each push: no findings.76c38e8builds with these files in place ofmaster's. Its packagedreferences/sending-transactional-emails.mdis byte for byte thisSKILL.md(at46c18e1).references/sdks.md, checked on 2026-11-05 against the head of each SDK PR above: each package, client option, send and status call, result and error name is in that PR's code.fc7d606builds with this branch's files at316b4a6in place ofmaster's. Its bundle carriesreferences/sdks.mdbyte for byte.build_skills --linton316b4a6(sparse checkout, this product's skills): passes.oxfmtover the changed files: no changes. The pre-push preflight didn't run on this box (nohogli), so CI is the full check.f95c37b1and context-mill#456 serving this skill at99e527f, in project 2 on an Express sample app. Both runs exited 0.template_keywelcome, and a send at signup with the user's distinct ID and an idempotency key.posthog-nodehas no code send yet. That's why this PR waits for the SDK releases.400 invalid_input.confirmbefore making it transactional. Read back over the API, the template is transactional with no marketing category.posthog.emails.send({ to, templateId, templateData, distinctId, idempotencyKey })on the app's client, withsecretKeyandenableLocalEvaluation: false.validation_error/invalid_input.00b8e40and2c9d269. Those change the reverse proxy client, the engagement check and the template send's fields, and the sample app has no proxy.00b8e40and2c9d269:build_skills --lintpasses, andoxfmt --checkpasses on both files. context-mill#456 at3390e97builds with this branch's files at2c9d269, and its bundledSKILL.mdis byte for byte this one.shouldCaptureEngagementEvents(teamId)is true (email.service.ts,email-tracking.service.ts). That readscapture_workflows_engagement_events, defaultFalse.SendEmailSerializerrejects everyCODE_SEND_FIELDSfield sent withtemplate_id.load_feature_flags()from flag evaluation whenever a secret key is set, so it fetches{host}/flags/definitionswith the key.Docs: the send API docs for the code form follow when the flag opens, as #127123 says.
Decisions
workflows-email-from-codereaches 100%; no fallback for projects without code sendssending-transactional-emailsisn't loadedInvolvement: no grilling rounds, no prototypes. Two Opus 5.5 review panels: round 1 (fresh eyes, correctness, risk, design, anti-overengineering, sweep: four major, eight minor and nit findings; ten fixed in
f1742ba, two rejected) and round 2 on the fixes (three major findings on this description's stale merge hold, fixed here, and five minor and nit findings, fixed in89e131c), then two final reads (one minor finding, fixed inb1a5947). On the eight-SDK change, one Opus 5.5 final read: two major findings, the Elixir package line (fixed in21d379c) and a merge order that waited only for Node.js and Python (fixed in this description). Then two GPT-6.1 Sol final reads. One read00b8e40, covering the scope wording and the reverse proxy client. The other read2c9d269, the fix for two PostHog Review findings (engagement events checked for every send, and no code fields on a template send). Both found nothing.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, Claude Opus 5.5 (
claude-opus-5-5), as the docs, skills and Wizard slice of Michael's transactional email map.🤖 Generated with Claude Code