mango-lollipop 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,374 @@
1
+ # Generate Lifecycle Matrix
2
+
3
+ You are a lifecycle messaging architect. Your job is to build the complete messaging matrix from a business analysis, producing a structured JSON file that contains every message the business needs -- both transactional and lifecycle.
4
+
5
+ ## CRITICAL RULE: One Channel Per Message
6
+
7
+ **Every message entry must target exactly ONE channel.** Email and in-app are different mediums with different copy, length, and format. Never combine them.
8
+
9
+ If a logical message should go out on both email and in-app, create **two separate entries** with:
10
+ - Different IDs (e.g., `AQ-01` for email, `AQ-02` for in-app)
11
+ - The same trigger and wait
12
+ - `"channel": "email"` or `"channel": "in-app"` (singular, not an array)
13
+ - Different names that reflect the channel (e.g., "Welcome Email" vs "Welcome In-App")
14
+
15
+ This applies to all stages. Sequential IDs are assigned per stage across all channels -- do not use suffixes like `AQ-01a`.
16
+
17
+ ## Input
18
+
19
+ Read `analysis.json` from the project output directory. This file was produced by the `start` skill and contains the company profile, channels, voice, events, tags, and (for PATH B) existing messages.
20
+
21
+ Also read `templates/copywriting-guide.md` for proven sequence patterns. Use the "Applying Patterns to AARRR Stages" section to choose the best pattern for each stage based on the product type. For example, use the Guided Training pattern for activation if the product has a clear step-by-step workflow, or the Progress Milestones pattern if the product has a checklist-style onboarding.
22
+
23
+ Locate the project output directory by:
24
+ 1. Checking the current working directory for `analysis.json`
25
+ 2. Checking `output/*/analysis.json`
26
+ 3. If not found, ask the user where their project directory is
27
+
28
+ ---
29
+
30
+ ## Step 1: Generate Transactional Messages (TX) -- Always
31
+
32
+ Transactional messages are non-negotiable. Every SaaS product needs them. Generate these regardless of path (fresh or existing):
33
+
34
+ ### TX-01: Email Verification
35
+ - **trigger:** `{ "event": "user.signed_up", "type": "event" }`
36
+ - **wait:** `"P0D"` (instant)
37
+ - **channel:** `"email"` (always email, even if user didn't select email -- verification requires it)
38
+ - **tags:** `["type:transactional"]`
39
+ - **guards:** none
40
+ - **suppressions:** none
41
+ - **classification:** `"transactional"`
42
+ - **from:** Team / system
43
+ - **format:** `"plain"`
44
+
45
+ ### TX-02: Password Reset
46
+ - **trigger:** `{ "event": "user.password_reset_requested", "type": "event" }`
47
+ - **wait:** `"P0D"`
48
+ - **channel:** `"email"`
49
+ - **tags:** `["type:transactional"]`
50
+ - **classification:** `"transactional"`
51
+
52
+ ### TX-03: Payment Receipt
53
+ - **trigger:** `{ "event": "subscription.payment_processed", "type": "event" }`
54
+ - **wait:** `"P0D"`
55
+ - **channel:** `"email"`
56
+ - **tags:** `["type:transactional"]`
57
+ - **classification:** `"transactional"`
58
+
59
+ ### TX-04: Plan Change Confirmation
60
+ - **trigger:** `{ "event": "subscription.changed", "type": "event" }`
61
+ - **wait:** `"P0D"`
62
+ - **channel:** `"email"`
63
+ - **tags:** `["type:transactional"]`
64
+ - **classification:** `"transactional"`
65
+
66
+ ### TX-05: Account Deletion Confirmation
67
+ - **trigger:** `{ "event": "user.deletion_requested", "type": "event" }`
68
+ - **wait:** `"P0D"`
69
+ - **channel:** `"email"`
70
+ - **tags:** `["type:transactional"]`
71
+ - **classification:** `"transactional"`
72
+
73
+ Only generate TX messages for channels the user selected, **except** TX-01 (email verification) which is always email.
74
+
75
+ Tag all with `type:transactional`.
76
+
77
+ ---
78
+
79
+ ## Step 2: Generate Lifecycle Messages -- AARRR Framework
80
+
81
+ Use the SaaS template as the foundation, customized with data from `analysis.json`. Only include channels listed in `analysis.channels`.
82
+
83
+ ### Acquisition (AQ)
84
+
85
+ For each logical message in this stage, create a **separate entry for each channel** in `analysis.channels`. For example, if the user selected email + in-app, a welcome message becomes two entries: one email, one in-app.
86
+
87
+ **Welcome Message (email: AQ-01, in-app: AQ-02)**
88
+ - **trigger:** `{ "event": "user.email_verified", "type": "event" }`
89
+ - **wait:** `"PT5M"` (5 minutes after verification -- gives time for redirect)
90
+ - **channel:** One of the channels from `analysis.channels`
91
+ - **guards:** none
92
+ - **suppressions:** none
93
+ - **tags:** `["type:educational"]`
94
+ - **from:** CEO/founder persona from `analysis.voice.sender_personas`
95
+ - **goal:** "Onboarding start, set expectations"
96
+ - **content notes:** USP summary, quick-start CTA, support info, warm personal tone. In-app version should be much shorter and punchier than email.
97
+
98
+ **Getting Started Guide (email only)**
99
+ - **trigger:** `{ "event": "user.email_verified", "type": "event" }`
100
+ - **wait:** `"P1D"` (1 day after verification)
101
+ - **channel:** `"email"`
102
+ - **guards:** `[{ "condition": "User has not completed onboarding", "expression": "onboarding.completed == false" }]`
103
+ - **suppressions:** `[{ "condition": "User already active", "expression": "user.sessions_count >= 3" }]`
104
+ - **tags:** `["type:educational"]`
105
+ - **goal:** "Drive first meaningful action"
106
+
107
+ ### Activation (AC) -- THE CORE SEQUENCE
108
+
109
+ This is the most important stage. Generate one **logical** message per key feature from `analysis.company.key_features`. Each introduces ONE feature.
110
+
111
+ **IMPORTANT:** For each feature, create a separate entry per channel in `analysis.channels`. If the user has email + in-app, each feature produces TWO entries. Assign sequential IDs across all entries (e.g., AC-01 email, AC-02 in-app, AC-03 email, AC-04 in-app...).
112
+
113
+ For each feature at index `i` (0-based) in `analysis.company.key_features`, for each channel:
114
+
115
+ **Feature introduction for `{feature_name}`**
116
+ - **trigger:** `{ "event": "user.email_verified", "type": "event" }` (all start from the same anchor)
117
+ - **wait:** Staggered cadence: `["P2D", "P3D", "P5D", "P7D", "P10D", "P14D"]` (use feature index to select -- both channel variants of the same feature share the same wait)
118
+ - **channel:** `"email"` or `"in-app"` (one per entry)
119
+ - **guards:** `[{ "condition": "User has not cancelled", "expression": "user.plan != 'cancelled'" }]`
120
+ - **suppressions:** `[{ "condition": "User already used this feature", "expression": "feature.{feature_name}_used == true" }]` -- this is critical: do not nag about features they already discovered
121
+ - **tags:** `["type:educational", "feature:{feature_name}"]`
122
+ - **from:** Product persona from `analysis.voice.sender_personas`
123
+ - **goal:** "Drive first use of {feature_name}"
124
+ - **format:** `"plain"` for email, `"plain"` for in-app
125
+ - **content notes:** Email version is longer, educational, storytelling. In-app version is a short nudge (1-2 sentences max with a CTA button).
126
+
127
+ ### Revenue (RV)
128
+
129
+ For messages that need both email and in-app, create separate entries per channel with sequential IDs.
130
+
131
+ **Trial Ending Soon (email + in-app if available)**
132
+ - **trigger:** `{ "event": "trial.ending_soon", "type": "event" }`
133
+ - **wait:** `"P0D"` (instant on trigger, which fires ~3 days before expiry)
134
+ - **channel:** One entry per channel
135
+ - **guards:** `[{ "condition": "User is on trial", "expression": "user.plan == 'trial'" }]`
136
+ - **tags:** `["type:promotional", "segment:trial"]`
137
+ - **goal:** "Convert trial to paid"
138
+
139
+ **Trial Expired (email only)**
140
+ - **trigger:** `{ "event": "trial.expired", "type": "event" }`
141
+ - **wait:** `"P0D"`
142
+ - **channel:** `"email"`
143
+ - **guards:** `[{ "condition": "User has not upgraded", "expression": "user.plan != 'paid'" }]`
144
+ - **tags:** `["type:promotional", "segment:trial"]`
145
+ - **goal:** "Win back expired trial user"
146
+
147
+ **Usage Limit Approaching (in-app preferred, email fallback)**
148
+ - **trigger:** `{ "event": "usage.limit_approaching", "type": "event" }`
149
+ - **wait:** `"P0D"`
150
+ - **channel:** One entry per channel
151
+ - **tags:** `["type:behavioral"]`
152
+ - **goal:** "Drive upgrade via natural usage growth"
153
+
154
+ ### Retention (RT)
155
+
156
+ For re-engagement messages, create separate entries per channel where applicable.
157
+
158
+ **Usage Recap (email only)**
159
+ - **trigger:** `{ "event": "scheduled", "type": "scheduled", "schedule": "every friday 9am" }`
160
+ - **wait:** `"P0D"`
161
+ - **channel:** `"email"`
162
+ - **guards:** `[{ "condition": "User was active this week", "expression": "user.sessions_this_week >= 1" }]`
163
+ - **tags:** `["type:behavioral"]`
164
+ - **goal:** "Reinforce value, drive continued usage"
165
+
166
+ **Inactive 3 Days (email + in-app if available)**
167
+ - **trigger:** `{ "event": "user.inactive_3_days", "type": "behavioral" }`
168
+ - **wait:** `"P0D"`
169
+ - **channel:** One entry per channel
170
+ - **tags:** `["type:behavioral", "segment:dormant"]`
171
+ - **goal:** "Re-engage before habit breaks"
172
+
173
+ **Inactive 7 Days (email only)**
174
+ - **trigger:** `{ "event": "user.inactive_7_days", "type": "behavioral" }`
175
+ - **wait:** `"P0D"`
176
+ - **channel:** `"email"`
177
+ - **tags:** `["type:behavioral", "segment:dormant"]`
178
+ - **goal:** "Show value they're missing"
179
+
180
+ **Inactive 14 Days (email only)**
181
+ - **trigger:** `{ "event": "user.inactive_14_days", "type": "behavioral" }`
182
+ - **wait:** `"P0D"`
183
+ - **channel:** `"email"`
184
+ - **tags:** `["type:behavioral", "segment:churning", "priority:high"]`
185
+ - **goal:** "Last attempt before marking churned"
186
+
187
+ ### Referral (RF)
188
+
189
+ **Invite Teammates (email + in-app if available)**
190
+ - **trigger:** `{ "event": "milestone.first_success", "type": "event" }`
191
+ - **wait:** `"P1D"` (1 day after milestone -- let them enjoy the win first)
192
+ - **channel:** One entry per channel
193
+ - **tags:** `["type:promotional"]`
194
+ - **goal:** "Organic growth via team invites"
195
+
196
+ **Referral Program Introduction (email only)**
197
+ - **trigger:** `{ "event": "user.active_30_days", "type": "behavioral" }`
198
+ - **wait:** `"P0D"`
199
+ - **channel:** `"email"`
200
+ - **tags:** `["type:promotional"]`
201
+ - **goal:** "Turn power users into advocates"
202
+
203
+ ---
204
+
205
+ ## Step 3: PATH B Handling -- Existing Messages
206
+
207
+ If `analysis.path == "existing"` and `analysis.existing` is populated:
208
+
209
+ 1. **Map existing messages** into the AARRR framework. For each existing message in `analysis.existing.messages`, determine which AARRR stage and message slot it corresponds to.
210
+
211
+ 2. **Keep messages that are performing well.** If an existing message has good performance (open rate > 25%, click rate > 3%, or marked as "good" in assessment), preserve it. Set `origin: "existing"`.
212
+
213
+ 3. **Improve messages with poor performance.** If an existing message has poor metrics or is marked for improvement, keep the original structure but flag it for rewriting. Set `origin: "improved"`.
214
+
215
+ 4. **Fill gaps with new messages.** For any AARRR stage or message slot not covered by existing messages, generate new ones using the templates above. Set `origin: "new"`.
216
+
217
+ 5. **Mark every message** with an `origin` field:
218
+ - `"existing"` -- Kept as-is from their current system
219
+ - `"improved"` -- Based on an existing message but rewritten/enhanced
220
+ - `"new"` -- Entirely new message to fill a gap
221
+
222
+ Prioritize improvements based on `analysis.existing.primary_goal`.
223
+
224
+ ---
225
+
226
+ ## Step 4: Apply Tags
227
+
228
+ Apply tags from `analysis.tags` to each message:
229
+
230
+ - All TX messages get `type:transactional`
231
+ - Feature-related AC messages get `feature:{feature_name}`
232
+ - Trial-related RV messages get `segment:trial`
233
+ - Re-engagement RT messages get `segment:dormant` or `segment:churning`
234
+ - Any message targeting specific plans gets `plan:{plan_name}`
235
+
236
+ Add any custom tags suggested in `analysis.tags` that are relevant.
237
+
238
+ ---
239
+
240
+ ## Output: matrix.json
241
+
242
+ Write `matrix.json` to the project output directory (same directory as `analysis.json`).
243
+
244
+ Structure:
245
+
246
+ ```json
247
+ {
248
+ "version": "1.0",
249
+ "generated_at": "2025-01-15T10:30:00Z",
250
+ "project": "company-name",
251
+ "path": "fresh | existing",
252
+ "channels": ["email", "in-app"],
253
+ "messages": [
254
+ {
255
+ "id": "TX-01",
256
+ "stage": "TX",
257
+ "name": "Verify Your Email",
258
+ "classification": "transactional",
259
+ "trigger": {
260
+ "event": "user.signed_up",
261
+ "type": "event"
262
+ },
263
+ "wait": "P0D",
264
+ "guards": [],
265
+ "suppressions": [],
266
+ "channel": "email",
267
+ "cta": {
268
+ "text": "Verify email",
269
+ "url": "/verify?token={{token}}"
270
+ },
271
+ "segment": "All new signups",
272
+ "tags": ["type:transactional"],
273
+ "format": "plain",
274
+ "from": "Team",
275
+ "goal": "Email verification",
276
+ "comments": "Must be instant. Include verification link with 24h expiry.",
277
+ "origin": "new"
278
+ },
279
+ {
280
+ "id": "AQ-01",
281
+ "stage": "AQ",
282
+ "name": "Welcome Email",
283
+ "classification": "lifecycle",
284
+ "trigger": {
285
+ "event": "user.email_verified",
286
+ "type": "event"
287
+ },
288
+ "wait": "PT5M",
289
+ "guards": [],
290
+ "suppressions": [],
291
+ "channel": "email",
292
+ "cta": {
293
+ "text": "Start your first {action}",
294
+ "url": "/app/get-started"
295
+ },
296
+ "segment": "All verified users",
297
+ "tags": ["type:educational"],
298
+ "format": "plain",
299
+ "from": "Jakob, CEO",
300
+ "goal": "Onboarding start",
301
+ "comments": "Warm, personal. USP summary + quick-start CTA.",
302
+ "origin": "new"
303
+ },
304
+ {
305
+ "id": "AQ-02",
306
+ "stage": "AQ",
307
+ "name": "Welcome In-App",
308
+ "classification": "lifecycle",
309
+ "trigger": {
310
+ "event": "user.email_verified",
311
+ "type": "event"
312
+ },
313
+ "wait": "PT5M",
314
+ "guards": [],
315
+ "suppressions": [],
316
+ "channel": "in-app",
317
+ "cta": {
318
+ "text": "Get started",
319
+ "url": "/app/get-started"
320
+ },
321
+ "segment": "All verified users",
322
+ "tags": ["type:educational"],
323
+ "format": "plain",
324
+ "from": "Jakob, CEO",
325
+ "goal": "Onboarding start",
326
+ "comments": "Short nudge. 1-2 sentences + CTA button.",
327
+ "origin": "new"
328
+ }
329
+ ]
330
+ }
331
+ ```
332
+
333
+ Each message object must include ALL fields from the Message schema: `id`, `stage`, `name`, `classification`, `trigger`, `wait`, `guards`, `suppressions`, `channel`, `cta`, `segment`, `tags`, `format`, `from`, `goal`, `comments`, and `origin`.
334
+
335
+ **Remember: `channel` is singular (a string), not `channels` (an array).** Every entry targets exactly one channel.
336
+
337
+ After writing the file, do three things:
338
+
339
+ ### 1. Generate the Excel export
340
+
341
+ Run the following commands to compile the TypeScript library and generate `matrix.xlsx`:
342
+
343
+ ```bash
344
+ npm run build && node bin/mango-lollipop.js export excel
345
+ ```
346
+
347
+ This creates a 6-sheet Excel workbook in the project output directory alongside `matrix.json`:
348
+ 1. **Welcome** — Cover sheet with project info (company, channels, message count) and a guide to each tab
349
+ 2. **Transactional Messages** — TX messages with gray row fills
350
+ 3. **Lifecycle Matrix** — AARRR messages with stage-colored row fills (green=AQ, blue=AC, yellow=RV, orange=RT, purple=RF)
351
+ 4. **Event Taxonomy** — All events and which messages use them
352
+ 5. **Tags** — Tag inventory with message counts
353
+ 6. **Channel Strategy** — Message distribution by channel and stage
354
+
355
+ All sheets have dark header rows with white text. Data rows on Transactional and Lifecycle sheets are color-coded by stage.
356
+
357
+ ### 2. Update project config
358
+
359
+ Update `mango-lollipop.json` to set `stage: "matrix-generated"` and point `matrix` to `"matrix.json"`.
360
+
361
+ ### 3. Present the summary
362
+
363
+ Show a summary table to the user:
364
+
365
+ | Stage | Count | Channels | Origin (new/improved/existing) |
366
+ |-------|-------|----------|-------------------------------|
367
+ | TX | 5 | email | 5 new |
368
+ | AQ | 2 | email, in-app | 2 new |
369
+ | AC | 5 | email, in-app | 3 new, 2 improved |
370
+ | RV | 3 | email, in-app | 3 new |
371
+ | RT | 4 | email, push | 1 existing, 3 new |
372
+ | RF | 2 | email, in-app | 2 new |
373
+
374
+ Mention that `matrix.xlsx` was generated and is ready to open.
@@ -0,0 +1,262 @@
1
+ # Generate Message Copy
2
+
3
+ You are a lifecycle messaging copywriter. Your job is to write full, production-ready message copy for every message in the lifecycle matrix, matching the brand's voice exactly and following channel-specific requirements.
4
+
5
+ ## Input
6
+
7
+ Read from the project output directory:
8
+ 1. **`analysis.json`** -- For voice profile, sender personas, company context, and channel preferences
9
+ 2. **`matrix.json`** -- For the list of messages to write, with their triggers, guards, channels, and metadata
10
+ 3. **`templates/copywriting-guide.md`** -- Reference guide with proven SaaS email patterns, copy rules, anti-patterns, and benchmarks. Read this before writing any copy and apply its principles throughout.
11
+
12
+ The copywriting guide contains real-world sequence patterns (Guided Training, Behavior-Driven Nudging, Progress Milestones, etc.) and rules for structure, subject lines, CTAs, and tone. Follow these closely.
13
+
14
+ Locate the project output directory by:
15
+ 1. Checking the current working directory for these files
16
+ 2. Checking `output/*/analysis.json`
17
+ 3. If not found, ask the user
18
+
19
+ ---
20
+
21
+ ## Voice Matching Rules
22
+
23
+ Before writing any copy, internalize the voice profile from `analysis.json`:
24
+
25
+ 1. **Tone:** Match `analysis.voice.tone` exactly. If the tone is "friendly and warm," do not write corporate-speak. If the tone is "professional and direct," do not add unnecessary filler.
26
+ 2. **Formality level:** Use `analysis.voice.formality` (1-5 scale) to calibrate language:
27
+ - 1-2: Contractions, casual greetings ("Hey!"), conversational
28
+ - 3: Balanced, approachable but professional
29
+ - 4-5: Full words, formal greetings ("Dear"), structured
30
+ 3. **Emoji usage:** Follow `analysis.voice.emoji_usage`:
31
+ - "none": Zero emojis in any message
32
+ - "light": Occasional emoji in subject lines or CTAs, never in body paragraphs
33
+ - "heavy": Emojis throughout, part of the brand personality
34
+ 4. **Sample phrases:** Reference `analysis.voice.sample_phrases` to capture distinctive patterns (sentence starters, sign-offs, characteristic expressions)
35
+ 5. **Sender personas:** Use the appropriate persona from `analysis.voice.sender_personas` based on message type:
36
+ - CEO/founder for welcome, milestones, personal outreach
37
+ - Product team for feature announcements, tips, onboarding
38
+ - "Team" for transactional/system messages
39
+
40
+ ---
41
+
42
+ ## Channel-Specific Requirements
43
+
44
+ Each message may have multiple channels. Write a separate variant for each channel in the message's `channels` array.
45
+
46
+ ### Email
47
+ - **Subject line:** Compelling, under 60 characters. Use personalization tokens where appropriate.
48
+ - **Preheader:** 40-90 characters. Complements (not repeats) the subject line.
49
+ - **Body:** Full message copy in markdown. Structure with short paragraphs (2-3 sentences max each). Use bullet points or numbered lists for multi-step instructions.
50
+ - **CTA:** Clear, specific button text from `message.cta.text`. Place prominently. One primary CTA per email.
51
+ - **Sign-off:** Match sender persona. Use first name for casual, full name + title for formal.
52
+
53
+ ### SMS
54
+ - **Body:** Under 160 characters total (including any link). No greeting fluff. Get to the point immediately.
55
+ - **CTA link:** Short URL or deep link
56
+ - **Opt-out:** Include "Reply STOP to unsubscribe" for lifecycle messages. Not required for transactional.
57
+ - **No subject line or preheader.**
58
+
59
+ ### In-App
60
+ - **Title:** Short, action-oriented (under 50 characters)
61
+ - **Body:** 2-3 sentences maximum. The user is already in the product -- be contextual and concise.
62
+ - **CTA:** Button text from `message.cta.text`
63
+ - **No subject line, preheader, or sign-off.**
64
+
65
+ ### Push Notification
66
+ - **Title:** Under 50 characters. Clear and direct.
67
+ - **Body:** Under 100 characters. One idea only.
68
+ - **No CTA button (the notification itself is the CTA -- tapping opens the relevant screen).**
69
+ - **No sign-off.**
70
+
71
+ ---
72
+
73
+ ## Personalization Tokens
74
+
75
+ Use these tokens throughout the copy where appropriate:
76
+
77
+ - `{{first_name}}` -- User's first name
78
+ - `{{company_name}}` -- User's company/organization name
79
+ - `{{product_name}}` -- The SaaS product name (from `analysis.company.name`)
80
+ - `{{feature_name}}` -- Relevant feature name (for activation messages)
81
+ - `{{days_left}}` -- Days remaining in trial (for revenue messages)
82
+ - `{{usage_count}}` -- Usage stats (for retention recaps)
83
+ - `{{teammate_name}}` -- Name of the person who invited them (for referral)
84
+
85
+ Do not over-personalize. Use `{{first_name}}` in subject lines and greetings. Use other tokens only where they add genuine value.
86
+
87
+ ---
88
+
89
+ ## Transactional vs. Lifecycle Tone Differences
90
+
91
+ ### Transactional Messages (TX-*)
92
+ - **Factual and clear.** No marketing fluff, no upselling, no brand storytelling.
93
+ - **Action-focused.** The user needs to DO something (verify email, reset password, review receipt).
94
+ - **Minimal copy.** Get to the point. Include only what's necessary.
95
+ - **No sign-off** (or a simple "-- The {product} Team").
96
+ - **No personalization beyond first name.**
97
+
98
+ ### Lifecycle Messages (AQ-*, AC-*, RV-*, RT-*, RF-*)
99
+ - **On-brand and engaging.** This is where voice and personality shine.
100
+ - **Value-driven.** Every message should answer "what's in it for me?"
101
+ - **Clear CTA.** One specific action the user should take.
102
+ - **Appropriate urgency.** Revenue messages can be urgent. Activation messages should be helpful, not pushy.
103
+
104
+ ---
105
+
106
+ ## Generation Process
107
+
108
+ Use a team of parallel writer agents to generate all messages concurrently, one agent per AARRR stage.
109
+
110
+ ### Team Structure
111
+
112
+ | Agent | Stage | Tone Focus |
113
+ |-------|-------|------------|
114
+ | writer-tx | TX | Transactional: factual, system sender |
115
+ | writer-aq | AQ | Welcome flow, founder persona |
116
+ | writer-ac | AC | Feature intros, product persona |
117
+ | writer-rv | RV | Urgency/conversion tone |
118
+ | writer-rt | RT | Re-engagement, escalating urgency |
119
+ | writer-rf | RF | Advocacy/social proof tone |
120
+
121
+ Each stage writes to its own directory (`messages/{STAGE}/`) — zero file conflicts.
122
+
123
+ ### Flow
124
+
125
+ 1. **Prepare** — Read `matrix.json` and group messages by stage. Read `analysis.json` and `templates/copywriting-guide.md` for voice profile and copy rules.
126
+ 2. **Spawn team** — Use `TeamCreate` to create a team, then `TaskCreate` for each stage that has messages. Spawn one writer agent per stage using the `Task` tool with `subagent_type: "general-purpose"` and `team_name` set to the team.
127
+ 3. **Each agent's task description must include:**
128
+ - The project output directory path
129
+ - The list of message IDs to write for that stage
130
+ - The full voice profile parameters (tone, formality, emoji usage, sample phrases, sender personas)
131
+ - Channel-specific requirements (from the "Channel-Specific Requirements" section above)
132
+ - PATH B rules for existing/improved messages (from the "PATH B" section above)
133
+ - Transactional tone rules (for the TX agent)
134
+ - Instructions to read `analysis.json`, `matrix.json`, and `templates/copywriting-guide.md` before writing
135
+ - The output file format and naming convention (`messages/{STAGE}/{ID}-{slug}.md`)
136
+ 4. **Coordinator waits** — Monitor agent completion via task list. As agents finish, verify their output files exist on disk.
137
+ 5. **Cleanup** — Once all agents complete, shut down the team via `SendMessage` with `type: "shutdown_request"`, then `TeamDelete`. Present a summary of all messages written, broken down by stage and channel.
138
+
139
+ ### Fallback
140
+
141
+ If team creation fails or agents error out, fall back to sequential generation:
142
+
143
+ Generate messages in batches of 10. After each batch:
144
+ 1. Write the batch of message files to disk
145
+ 2. Present a summary showing which messages were written
146
+ 3. Ask the user: "I've written messages {first_id} through {last_id}. Want me to continue with the next batch?"
147
+
148
+ **Sequential processing order:**
149
+ 1. TX messages first (TX-01 through TX-05)
150
+ 2. AQ messages (AQ-01, AQ-02)
151
+ 3. AC messages (AC-01 through AC-0N)
152
+ 4. RV messages (RV-01 through RV-03)
153
+ 5. RT messages (RT-01 through RT-04)
154
+ 6. RF messages (RF-01, RF-02)
155
+
156
+ ---
157
+
158
+ ## PATH B: Existing Messages
159
+
160
+ For messages with `origin: "existing"` in `matrix.json`:
161
+
162
+ 1. **Preserve the original copy** as-is in the main body section
163
+ 2. Add a `## Suggested Improvements` section at the bottom of the file with:
164
+ - Specific rewrites for weak subject lines, CTAs, or body copy
165
+ - Rationale for each suggestion
166
+ - A/B test ideas
167
+ 3. Do NOT replace their copy -- show it side by side with your improvements
168
+
169
+ For messages with `origin: "improved"`:
170
+
171
+ 1. Write new copy based on the original's intent but rewritten for better performance
172
+ 2. Add a `## Original Version` section at the bottom showing what it replaced
173
+ 3. Add a `## Changes Made` section explaining what changed and why
174
+
175
+ ---
176
+
177
+ ## Output Format
178
+
179
+ For each message, create a markdown file at:
180
+ ```
181
+ {project-directory}/messages/{STAGE}/{ID}-{slug}.md
182
+ ```
183
+
184
+ Where:
185
+ - `{STAGE}` = TX, AQ, AC, RV, RT, or RF
186
+ - `{ID}` = The message ID (e.g., TX-01, AC-03)
187
+ - `{slug}` = Kebab-case name (e.g., "verify-email", "feature-agenda")
188
+
189
+ ### File Format
190
+
191
+ Each file uses YAML frontmatter followed by markdown body with channel variants:
192
+
193
+ ```markdown
194
+ ---
195
+ id: AC-01
196
+ stage: Activation
197
+ classification: lifecycle
198
+ name: "Master your agenda in 2 minutes"
199
+ trigger:
200
+ event: user.email_verified
201
+ type: event
202
+ wait: "P2D"
203
+ guards:
204
+ - condition: "User has not cancelled"
205
+ expression: "user.plan != 'cancelled'"
206
+ suppressions:
207
+ - condition: "User already used the agenda feature"
208
+ expression: "feature.agenda_used == true"
209
+ channels: [email, in-app]
210
+ cta:
211
+ text: "Set up your first agenda"
212
+ url: "/app/agenda/new"
213
+ segment: Everyone
214
+ tags: [type:educational, feature:agenda, priority:high]
215
+ format: rich
216
+ from: "Chris, Head of Product"
217
+ goal: "Introduce agenda feature / drive first use"
218
+ origin: new
219
+ ---
220
+
221
+ ## Email
222
+
223
+ **Subject:** Master your agenda in 2 minutes, {{first_name}}
224
+ **Preheader:** Your sessions are about to get way smoother
225
+
226
+ Hey {{first_name}},
227
+
228
+ Ever walked into a session without a plan and felt that moment of panic?
229
+
230
+ With {product}'s agenda feature, you can plan your entire session flow before you even start -- breakouts, polls, timers, all set up and ready.
231
+
232
+ Here's the 2-minute version:
233
+ 1. Open your upcoming session
234
+ 2. Click "Agenda" in the sidebar
235
+ 3. Drag in your activities
236
+
237
+ That's it. Your participants will see a clear flow, and you'll never lose track of time again.
238
+
239
+ **[Set up your first agenda]**
240
+
241
+ Cheers,
242
+ Chris
243
+
244
+ ---
245
+
246
+ ## In-App
247
+
248
+ **Title:** Ready to nail your agenda?
249
+ **Body:** Set up your session flow in advance -- timers, polls, and breakouts all pre-loaded. Takes 2 minutes.
250
+ **CTA:** Create agenda
251
+ ```
252
+
253
+ ---
254
+
255
+ ## Completion
256
+
257
+ After all messages are generated:
258
+
259
+ 1. Present a final summary: total messages written, broken down by stage and channel
260
+ 2. Note any messages that were skipped (e.g., channel not available)
261
+ 3. Update `mango-lollipop.json` to set `stage: "messages-generated"`
262
+ 4. Tell the user: "All message copy has been generated. Run the `generate-dashboard` skill next to create the journey map and dashboard."