swap-sms-provider
Add or switch the SMS provider (Vonage, MessageBird, AWS SNS, …). Use when the user wants texts sent through a different service or in another region. Not for debugging; when something fails, use the
SKILL.md.claude/skills/swap-sms-provider/SKILL.md
GitHubSwap the SMS provider
- Interface:
SmsTransport(send(to, body, idempotencyKey): Promise<SmsResult>) inapps/notifications/src/channels/sms/sms-transport.ts. - Today:
TwilioTransport(twilio.ts) in production;EmailSinkSmsTransport(email-sink.ts) delivers texts to Mailpit as emails to<digits>@sms.testlocally. - Selected in:
createTransport()inapps/notifications/src/channels/sms/sms.module.tsbySMS_PROVIDER(unset in production: nothing is texted). - Env:
SMS_PROVIDER(twilio|email),TWILIO_ACCOUNT_SID,TWILIO_AUTH_TOKEN,TWILIO_FROM,TWILIO_API_URL(test hook only).
Swap
- A class implementing
SmsTransport. Map the provider's errors ontoSmsResult:permanentwhen retrying can't help,suppress: "unsubscribe"when the recipient opted out,suppress: "invalid"for numbers that can't receive texts. The dispatcher records suppressions (DeliveryPolicy) so those numbers are never texted again. - Its name in the
SMS_PROVIDERenum and its credentials inapps/notifications/src/env.ts, with a boot check that they're all set, plus.env.exampleanddocs/environment.md. A test hook for its API URL is refused in production likeTWILIO_API_URL. - A
caseincreateTransport().
Tests
apps/notifications/test/fake-twilio.ts is the pattern: a local server answering like
the provider, including its error cases. Write one for the new provider and cover
success, opt-out and invalid numbers in
apps/notifications/test/notifications.integration.test.ts.
apps/notifications/src/channels/sms/email-sink.test.ts covers the local sink.
Finish
- The verify skill.
- Ask the
revieweragent to review the change, and thesecurity-revieweragent: a new implementation brings its own credentials and sends data somewhere new. If you wrote a migration, themigration-revieweragent too. - Update the seam's row in the README's "Scaling path" table if what's "Now" changed.