Skip to content

feat(transactional-email): add a command that sets up the first email send - #1

Draft
Silthus wants to merge 2 commits into
mainfrom
feat/transactional-email-program
Draft

Silthus wants to merge 2 commits into
mainfrom
feat/transactional-email-program

Conversation

@Silthus

@Silthus Silthus commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

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

Problem

A team that has never sent email from code has no guided way to start with PostHog. Wizard can add PostHog to a project, but the setup agent has no path to send a transactional email, such as a welcome email after signup.

With this PR, npx @posthog/wizard transactional-email checks for a verified sender, writes the project secret API key to the env file, and adds the first send to the app's server code. A plain run that finds PostHog already installed lists the command in its intro spell book.

Part of Silthus/posthog#544.

Impact

Pays into Grow Workflows through organizations that send email from code (not measured yet: it needs the send source on each send, PostHog/posthog#120628). In scope: transactional email. Expected move: medium, up. Run cost: n/a.

Merge Danger

Warning

🟡 Merge risk: medium · one-way door: a release publishes the transactional-email command name (merge-risk rubric)

  • The skill this runs, omnibus-send-transactional-email, is not in the published skill menu yet (PostHog/context-mill#433, draft). Released before it, the command fails when it downloads the skill.
  • The transactional email API is in beta and on per project. Where it is off, the skill emits [ABORT] transactional email api not enabled. On the default Pi binding no program's [ABORT] ends the run yet (see Gaps), so such a run can still end on the success outro.
  • Merge after fix: drop stale introspection from interactive OAuth scope list PostHog/wizard#433 is released and the posthog-node release with emails.send is out. A revert removes the command and the spell book row.

Changes

  • New program transactional-email (src/programs/transactional-email/), built with createSkillProgram, on the default binding (Pi, linear).
  • New command transactional-email (nativeCommandFactory), registered in runCli.
  • The intro spell book of a plain run lists it last: transactional-email Send your first transactional email from code.
  • Two abort cases match the skill's "Inside the PostHog Wizard" section: the API is not enabled, and no server code was found. The linear sequence matches them against the run's abort reason.
  • No extra OAuth scopes. The PostHog MCP hides tools whose scopes the login lacks: the integrations-* sender tools and the workflows-* email tools. The skill's Wizard section treats a missing tool as inconclusive, sends the person to the PostHog UI to verify a sender, and takes only a send's 404 as "API not enabled".
  • README: a "Transactional email" section.

The skill's Wizard section (ask through wizard_ask, write the key with set_env_values, reach PostHog tools through posthog_exec, the [ABORT] reasons) is in PostHog/context-mill#433.

Test plan

Test seams:

  • CLI dispatch (src/cli/__tests__/programs-cli.test.ts): transactional-email runs with skill omnibus-send-transactional-email. Red before the command existed (module not found), green after.
  • Intro spell book (intro-menu.test.ts): the curated list resolves and ends with transactional-email, and the row fits 80 columns. Red, then green.
  • Abort cases (src/programs/transactional-email/__tests__): each [ABORT] reason from the skill matches exactly one case.
  • Bindings and flow: program-registry.test.ts pins the default linear binding. The flow-traces snapshot records intro, health check, auth, run, and outro for the program.

Checks after the rebase, as CI runs them: pnpm install --frozen-lockfile, pnpm lint (0 errors), pnpm typecheck, and pnpm test (build, smoke tests, vitest: 257 files and 3,816 tests pass).

Rebase fixes, both from changes on main:

  • The program imports ProgramConfig from @programs/program-contract, where main moved the program contract.
  • The flow-traces snapshot for this program ends on the exit screen, which replaced keep-skills on main.
$ npx tsx bin.ts --help
  bin.ts revenue-analytics    Set up PostHog for Revenue Analytics
  bin.ts transactional-email  Send your first transactional email from code

Gaps:

  • The Pi harness ends a run only on [posthog:abort], the gateway refusal marker. It ignores a skill's [ABORT], so these abort cases, like those of revenue-analytics and mcp-analytics, don't fire on the default binding yet. Fixing that is a separate PR.
  • No end-to-end run of the setup agent. It needs the skill in a published menu (or --local-context-mill), Wizard CI credentials, and a project with the transactional email API on.
  • No rendered screenshot of the spell book row. The intro-menu test covers the row's text.

Decisions

Question Answer Who Where
Offer transactional email setup in Wizard Yes, as a draft, in the core run where it fits 👤 Human Silthus/posthog#544
Where the entry hooks into the core run A native command plus a spell book row. An install-run offer needs a signal for "sends no email yet", and a seeded orchestrator task needs a flag and runner support 🤖 Agent pending approval
OAuth scopes for sender setup None now. The skill treats hidden tools as inconclusive and uses the UI path. Add integration:read and integration:write once the OAuth app's scope ceiling holds them, together with the migrate family 🤖 Agent pending approval
[ABORT] ignored on the Pi harness Out of this PR: a side fix for every program on Pi, not a workaround in one skill 🤖 Agent pending approval

Involvement: no grilling rounds, no prototypes, one GPT-6.1 Sol review round over this PR and PostHog/context-mill#433 (four findings: three fixed in PostHog#433, one deferred as above) and one final read (one finding, fixed in PostHog#433), and one GPT-6.1 Sol review of the rebase fix (no findings). Proof captured as command output.

LLM context

Written by Claude Opus 5.5 (claude-opus-5-5) as a build lane of a planning map. The setup agent copy follows the "Wizard once, then the setup agent" rule.

🤖 Generated with Claude Code

Silthus and others added 2 commits October 23, 2026 13:46
… send

`npx @posthog/wizard transactional-email` runs the context-mill skill
omnibus-send-transactional-email: the setup agent checks for a verified
sender, writes the project secret API key to the env file, and adds the
first send with posthog-node or the HTTP API. The intro spell book of a
plain run lists it, and the skill's two [ABORT] reasons end the run with
a next step.

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

Import `ProgramConfig` from `@programs/program-contract`, where the services
refactor moved it, and take the outro's `exit` step from the skill cleanup
in the flow trace.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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