Comms Platform
One-line description. One internal communications layer for email, SMS, and (later) voice that every system sends and receives through, instead of each system wiring its own vendor. Resend (transactional email) + Telnyx (SMS/voice) + Kit (nurture), glued by Cloud Run + BigQuery. FUB stays the CRM.
Why
Outbound/inbound comms were sprawling toward per-system vendor wiring, with a paid-but-never-built Brevo subscription and a Twilio-default dialer plan. Consolidating into four non-overlapping lanes (transactional email, nurture, SMS/voice, correctness backbone) means one place to send, one place to receive, one event log that every send is gated against for suppression/dedup.
The decision that shaped it (2026-06-02): Resend replaces the never-built Brevo for transactional email; Telnyx replaces Twilio for SMS/voice because its native transcription removes the bolt-on-STT step the coaching pipeline needs; Kit stays for nurche (its price matches Resend's marketing tier and it does more). Net ≈ $45–55/mo, down from the $90 Brevo+Kit was heading toward.
Current state
- Status: in-progress — email layer Phase 1 SHIPPED (2026-06-05, on
main). - Last update: 2026-06-05
Email layer Phase 1 (built subagent-driven TDD, on main): the data-platforms/comms-platform/comms/ Python package — stage registry, template render, Resend send adapter, FUB read client (recruiting instance), append-only BigQuery layer, and the cold-cadence sequencer (with warm-up ceiling). Live BQ comms dataset (events partitioned + contacts + contact_state view). Proven end-to-end with a real cold-cadence email through the full pipeline (suppression-checked, BQ-logged, landed in-inbox).
- Resend account = Ry's own workspace (Google
ry@rycolston.com). Cold laneorchard.rycolston.comis verified + sending (DNS via Cloudflare API). Transactional laneinfo.rycolston.comdeferred behind Resend Pro — both lanes run onorcharduntil the one-line split. - FUB recruiting instance =
ryan.colston+mm@orchard.com(key mirrored to SMfub-recruiting-api-key) — distinct from the seller-consultFUB_API_KEY. - Phase 2 DEPLOYED (2026-06-05):
pos-commsCloud Run service live + Cloud Scheduler PAUSED (daily 11:00 CT). Cron path verified end-to-end via real OIDC (200, 0 sends, no stray send). Emails nobody until launch (0 tagged, paused, placeholder copy). Next: Phase 3 (transactional stages + Resend webhook), Phase 4 (real copy), then unpause + tag. - Second consumer planned (2026-06-22): the Customer Database Plays (50OS) — Ry's automated weekly database email, a separate Cloud Run service pair (
pos-customer-db-playengine +pos-customer-db-play-approvepublic approve shim) reusing thiscommslibrary, NOTpos-comms. Design + 14-task plan done, not built. gitlab #81; specRoadmap/plans/2026-06-22-customer-database-plays.md.
Next 3 actions
Phase 2 —ALREADY DEPLOYED 2026-06-05 — this file's own "Current state" says so two sections up. Do not rebuild. The live question is whether to unpause the scheduler (Ry gate, RYR-172 P3).pos-commsdeploy: build the FastAPI wrapper + terraform, bootstrap the Cloud Run service + paused scheduler.- Phase 3 — transactional stages + Resend webhook (booking confirm, night-before, no-show via live FUB outcome
"No show"). - Phase 4 — real Hormozi-voice copy for the 6 cold touches + transactional templates; then launch (unpause scheduler, begin tagging
cold-cadence-active).
Decisions log
- 2026-06-05 — Email layer Phase 1 shipped. Sending spine + cold-cadence, single sending domain now (
orchard.rycolston.com), pipeline-first / copy-last, proven with a real send. Stack decision recorded in ADR-0004. - 2026-06-05 — CI drift-gate race fixed (de-risked Phase 2's deploy MR). MR
drift-check-tfvars-vs-livescoped to MR-changed services; daily full sweep unchanged. ADR-0005 + Issue #33. - 2026-06-04 — Single sending domain now, split later. Build all email on
orchard.rycolston.com; flip the transactional lane toinfo.rycolston.com(needs Resend Pro) via a one-lineLANESconfig change.sender_lane→domain is per-stage config. - 2026-06-03 — FUB tag taxonomy ratified (
meeting-scheduled→discovery-booked; dropcontacted→call-connected-status-quo-captured). Propagated to setter script + source-of-truth §6 + DESIGN §10. - 2026-06-03 — Recruiting FUB instance =
ryan.colston+mm(mirrored to SMfub-recruiting-api-key), NOT the sellerFUB_API_KEY. No-show signal = appointment outcome"No show". - 2026-06-02 — Telnyx + Resend + Kit; Brevo dropped; Telnyx over Twilio. Rationale in code repo
docs/DESIGN.md§2 + ADR-0004. - 2026-06-02 — Recruiting sequence grounded in primary sources (cold-call script, cadence SOP, wrapper analysis, VM/SMS spec) and captured in
docs/recruiting-source-of-truth.md. Surfaced 4 cross-source contradictions (tease-vs-reveal, tag drift, closer-vs-Ry, cold-SMS). - 2026-06-02 — All 4 contradictions resolved. Tease-not-reveal: script Day 3/7 rewritten to tease (undeployed; audio re-record pending). Tag taxonomy: canonical 10-tag set locked (
§6), 2 names await ratification. Cold-SMS: warm-only default (ratify; diverges from VM/SMS spec). Sender identity: per-stage config, not hard-coded Ry.
Open issues
- FUB tag taxonomy — RATIFIED 2026-06-03 (
meeting-scheduled→discovery-booked;contacted→call-connected-status-quo-captured); script Outcomes block updated (committed, ships next handbook deploy) - Tease-not-reveal — RESOLVED 2026-06-02: script Day 3/7 rewritten to tease (committed, undeployed). ⚠️ re-record
recruiting-12-5-day-03-time-risk+recruiting-12-5-day-07-likelihoodaudio before next handbook deploy - Cold-SMS — RESOLVED to warm-only (pending Ry ratification); update the VM/SMS spec; cold B2B SMS parked behind a TCPA/10DLC legal review
- Sender identity — RESOLVED 2026-06-02: per-stage config field, defaults to Ry (DESIGN §7), not hard-coded
-
Telnyx— likely dead: Telnyx was never built and the 2026-07-16 direction moved to a Twilio path (see project memory). Confirm and delete rather than run.POST /sequence-emailstest - Voice transcription path: managed STT vs WebSocket→Vertex (Phase 6 / Mojo replacement)
- Reconcile 3 stale docs: External API Platforms, Newsletter Architecture, Custom Dialer (Mojo Replacement)
- RYR-465 —
claim_sendmoves off the GCS CAS lock to Cloud SQL Postgres (filed 2026-08-26).comms/bq.py:112is one of nine call sites in a platform-wide cutover; its lines 56–81 carry a comment block whose first three paragraphs are explicitly INVALIDATED by RYR-107 (two concurrent BQ MERGE claims both won) followed by the GCS CAS fix — the whole block gets replaced. Relevant to the RYR-172 P3 unpause gate: the cold cadence still ships PAUSED, which is why this cutover carries no live customer exposure. Parent: Platform.
References
- Code home (all substance):
~/rylobasic/data-platforms/comms-platform/ - Design:
data-platforms/comms-platform/docs/DESIGN.md - Plan:
data-platforms/comms-platform/docs/PLAN.md - API refs:
data-platforms/comms-platform/docs/api/{telnyx,resend,kit,cloud-run,bigquery}.md - Recruiting sequence provenance + cross-source contradictions:
data-platforms/comms-platform/docs/recruiting-source-of-truth.md - Recruiting primary sources (traced 2026-06-02): cold-call script
rylobasic/domains/handbook-rycolston-com/content/ryan-colston/_overrides/recruiting.md; cadence SOPWork/Recruiting Team/Agent Recruiting Cadence - Expert.md;Projects/Agent Recruiting Wrapper/{Wrapper Analysis,VM and SMS Build Spec,Pipeline Email Mapping,Brevo Trigger Map}.md - Related projects: Custom Dialer (becomes Phase 6), Agent Recruiting Wrapper (first consumer), Newsletter Architecture (Kit lane)
- Supersedes the Brevo role in Kit vs Brevo and External API Platforms