vibebusiness 1.2.39 → 1.2.42

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.
Files changed (184) hide show
  1. package/.next/standalone/.env +7 -0
  2. package/.next/standalone/.next/BUILD_ID +1 -1
  3. package/.next/standalone/.next/app-build-manifest.json +64 -56
  4. package/.next/standalone/.next/app-path-routes-manifest.json +1 -1
  5. package/.next/standalone/.next/build-manifest.json +6 -6
  6. package/.next/standalone/.next/prerender-manifest.json +1 -1
  7. package/.next/standalone/.next/routes-manifest.json +1 -1
  8. package/.next/standalone/.next/server/app/_not-found/page.js +1 -1
  9. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  10. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  12. package/.next/standalone/.next/server/app/_not-found.rsc +1 -1
  13. package/.next/standalone/.next/server/app/api/analyze/route.js +1 -1
  14. package/.next/standalone/.next/server/app/api/analyze/route.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/api/checkout/route.js +1 -0
  16. package/.next/standalone/.next/server/app/api/checkout/route.js.nft.json +1 -0
  17. package/.next/standalone/.next/server/app/api/config/detect-repos/route.js +1 -1
  18. package/.next/standalone/.next/server/app/api/config/detect-repos/route.js.nft.json +1 -1
  19. package/.next/standalone/.next/server/app/api/config/route.js +1 -1
  20. package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/api/epics/[id]/ideas/route.js +1 -1
  22. package/.next/standalone/.next/server/app/api/epics/[id]/ideas/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/epics/[id]/route.js +1 -1
  24. package/.next/standalone/.next/server/app/api/epics/[id]/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/epics/route.js +1 -1
  26. package/.next/standalone/.next/server/app/api/epics/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/goals/[id]/kpis/route.js +1 -1
  28. package/.next/standalone/.next/server/app/api/goals/[id]/kpis/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/goals/[id]/route.js +1 -1
  30. package/.next/standalone/.next/server/app/api/goals/[id]/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/goals/route.js +1 -1
  32. package/.next/standalone/.next/server/app/api/goals/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/health/route.js +1 -1
  34. package/.next/standalone/.next/server/app/api/health/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/hypotheses/[id]/route.js +1 -1
  36. package/.next/standalone/.next/server/app/api/hypotheses/[id]/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/hypotheses/route.js +1 -1
  38. package/.next/standalone/.next/server/app/api/hypotheses/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/ideas/[id]/comments/route.js +1 -1
  40. package/.next/standalone/.next/server/app/api/ideas/[id]/comments/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/api/ideas/[id]/implement/route.js +1 -1
  42. package/.next/standalone/.next/server/app/api/ideas/[id]/implement/route.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/api/ideas/[id]/route.js +1 -1
  44. package/.next/standalone/.next/server/app/api/ideas/[id]/route.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/api/ideas/[id]/transition/route.js +1 -1
  46. package/.next/standalone/.next/server/app/api/ideas/[id]/transition/route.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/api/ideas/route.js +1 -1
  48. package/.next/standalone/.next/server/app/api/ideas/route.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/api/implementations/route.js +1 -1
  50. package/.next/standalone/.next/server/app/api/implementations/route.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/api/kpis/refresh/route.js +1 -1
  52. package/.next/standalone/.next/server/app/api/kpis/refresh/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/license/route.js +1 -0
  54. package/.next/standalone/.next/server/app/api/license/route.js.nft.json +1 -0
  55. package/.next/standalone/.next/server/app/api/portal/route.js +1 -0
  56. package/.next/standalone/.next/server/app/api/portal/route.js.nft.json +1 -0
  57. package/.next/standalone/.next/server/app/api/social/[id]/publish/route.js +1 -0
  58. package/.next/standalone/.next/server/app/api/social/[id]/publish/route.js.nft.json +1 -0
  59. package/.next/standalone/.next/server/app/api/social/[id]/route.js +1 -0
  60. package/.next/standalone/.next/server/app/api/social/[id]/route.js.nft.json +1 -0
  61. package/.next/standalone/.next/server/app/api/social/route.js +1 -0
  62. package/.next/standalone/.next/server/app/api/social/route.js.nft.json +1 -0
  63. package/.next/standalone/.next/server/app/api/webhook/route.js +1 -0
  64. package/.next/standalone/.next/server/app/api/webhook/route.js.nft.json +1 -0
  65. package/.next/standalone/.next/server/app/goals/[id]/page.js +1 -1
  66. package/.next/standalone/.next/server/app/goals/[id]/page.js.nft.json +1 -1
  67. package/.next/standalone/.next/server/app/goals/[id]/page_client-reference-manifest.js +1 -1
  68. package/.next/standalone/.next/server/app/goals/page.js +1 -1
  69. package/.next/standalone/.next/server/app/goals/page.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/goals/page_client-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/app/hypotheses/[id]/page.js +1 -1
  72. package/.next/standalone/.next/server/app/hypotheses/[id]/page.js.nft.json +1 -1
  73. package/.next/standalone/.next/server/app/hypotheses/[id]/page_client-reference-manifest.js +1 -1
  74. package/.next/standalone/.next/server/app/hypotheses/page.js +1 -1
  75. package/.next/standalone/.next/server/app/hypotheses/page.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/hypotheses/page_client-reference-manifest.js +1 -1
  77. package/.next/standalone/.next/server/app/ideas/[id]/page.js +1 -1
  78. package/.next/standalone/.next/server/app/ideas/[id]/page.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/ideas/[id]/page_client-reference-manifest.js +1 -1
  80. package/.next/standalone/.next/server/app/landing/page.js +1 -1
  81. package/.next/standalone/.next/server/app/landing/page.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/landing/page_client-reference-manifest.js +1 -1
  83. package/.next/standalone/.next/server/app/landing.html +1 -1
  84. package/.next/standalone/.next/server/app/landing.rsc +1 -1
  85. package/.next/standalone/.next/server/app/page.js +1 -1
  86. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  88. package/.next/standalone/.next/server/app/roadmap/[id]/page.js +1 -1
  89. package/.next/standalone/.next/server/app/roadmap/[id]/page.js.nft.json +1 -1
  90. package/.next/standalone/.next/server/app/roadmap/[id]/page_client-reference-manifest.js +1 -1
  91. package/.next/standalone/.next/server/app/roadmap/page.js +1 -1
  92. package/.next/standalone/.next/server/app/roadmap/page.js.nft.json +1 -1
  93. package/.next/standalone/.next/server/app/roadmap/page_client-reference-manifest.js +1 -1
  94. package/.next/standalone/.next/server/app/sessions/page.js +1 -1
  95. package/.next/standalone/.next/server/app/sessions/page.js.nft.json +1 -1
  96. package/.next/standalone/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  97. package/.next/standalone/.next/server/app/settings/page.js +1 -1
  98. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  100. package/.next/standalone/.next/server/app/settings.html +1 -1
  101. package/.next/standalone/.next/server/app/settings.rsc +2 -2
  102. package/.next/standalone/.next/server/app/social/page.js +1 -0
  103. package/.next/standalone/.next/server/app/social/page.js.nft.json +1 -0
  104. package/.next/standalone/.next/server/app/social/page_client-reference-manifest.js +1 -0
  105. package/.next/standalone/.next/server/app/social.html +1 -0
  106. package/.next/standalone/.next/server/app/social.meta +5 -0
  107. package/.next/standalone/.next/server/app/social.rsc +7 -0
  108. package/.next/standalone/.next/server/app-paths-manifest.json +17 -9
  109. package/.next/standalone/.next/server/chunks/{682.js → 1682.js} +1 -1
  110. package/.next/standalone/.next/server/chunks/3644.js +1 -0
  111. package/.next/standalone/.next/server/chunks/4376.js +1 -0
  112. package/.next/standalone/.next/server/chunks/4471.js +2 -0
  113. package/.next/standalone/.next/server/chunks/534.js +1 -0
  114. package/.next/standalone/.next/server/chunks/5972.js +12 -0
  115. package/.next/standalone/.next/server/chunks/7809.js +2 -0
  116. package/.next/standalone/.next/server/chunks/9276.js +2 -0
  117. package/.next/standalone/.next/server/chunks/9777.js +1 -0
  118. package/.next/standalone/.next/server/middleware-build-manifest.js +1 -1
  119. package/.next/standalone/.next/server/pages/404.html +1 -1
  120. package/.next/standalone/.next/server/pages/500.html +1 -1
  121. package/.next/standalone/.next/server/pages/_app.js +1 -1
  122. package/.next/standalone/.next/server/pages/_document.js +1 -1
  123. package/.next/standalone/.next/server/pages/_document.js.nft.json +1 -1
  124. package/.next/standalone/.next/server/pages/_error.js +1 -1
  125. package/.next/standalone/.next/server/pages/_error.js.nft.json +1 -1
  126. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  127. package/.next/standalone/.next/server/webpack-runtime.js +1 -1
  128. package/.next/standalone/data/email-campaigns/welcome-2026-02-20.md +13 -32
  129. package/.next/standalone/data/ideas.json +29 -9
  130. package/.next/standalone/data/payments.json +33 -0
  131. package/.next/standalone/data/social.json +13 -0
  132. package/.next/standalone/package.json +5 -1
  133. package/.next/standalone/scripts/analyze.ts +26 -3
  134. package/.next/standalone/scripts/skills/social-media.ts +535 -0
  135. package/.next/static/chunks/444-125b7b0fa8cbdb81.js +1 -0
  136. package/.next/static/chunks/746-ea7c3e4e69c14385.js +1 -0
  137. package/.next/static/chunks/app/goals/[id]/{page-91b8382d44e93925.js → page-8dbeab5cc8cf0988.js} +1 -1
  138. package/.next/static/chunks/app/goals/{page-ecaa4a2761757014.js → page-794526d1e1a0856a.js} +1 -1
  139. package/.next/static/chunks/app/hypotheses/[id]/{page-894b08de47a73af9.js → page-65032da79ae146c5.js} +1 -1
  140. package/.next/static/chunks/app/hypotheses/page-8314da4be7c533bd.js +1 -0
  141. package/.next/static/chunks/app/ideas/[id]/page-dc9746061e58eea5.js +1 -0
  142. package/.next/static/chunks/app/layout-eeef7928298d2198.js +1 -0
  143. package/.next/static/chunks/app/page-fb66ff080390f20a.js +1 -0
  144. package/.next/static/chunks/app/roadmap/[id]/{page-3848fd96de497d11.js → page-c8c4baf233e0d480.js} +1 -1
  145. package/.next/static/chunks/app/roadmap/page-b15554a207ed2813.js +1 -0
  146. package/.next/static/chunks/app/sessions/page-42fb8edb15b9da1c.js +1 -0
  147. package/.next/static/chunks/app/settings/page-d2d630a799b6b495.js +1 -0
  148. package/.next/static/chunks/app/social/page-6c61fb0c2546313e.js +1 -0
  149. package/.next/static/chunks/{main-c0637f9544446589.js → main-98052d4291bccc96.js} +1 -1
  150. package/.next/static/css/02298496de89e16e.css +3 -0
  151. package/README.md +18 -0
  152. package/dist/bin/vibebusiness.js +307 -26
  153. package/dist/scripts/analyze.js +24 -3
  154. package/dist/scripts/chat.js +1 -0
  155. package/dist/scripts/generate-idea.js +1 -0
  156. package/dist/scripts/heartbeat.js +12850 -4578
  157. package/dist/scripts/implement.js +1 -0
  158. package/dist/scripts/init.js +46 -6
  159. package/dist/scripts/scan.js +1 -0
  160. package/package.json +5 -1
  161. package/templates/commands/email-marketing.md +148 -10
  162. package/templates/commands/launch-campaign.md +84 -0
  163. package/templates/commands/promo-copy.md +186 -0
  164. package/.next/standalone/.next/server/chunks/276.js +0 -2
  165. package/.next/standalone/.next/server/chunks/416.js +0 -1
  166. package/.next/standalone/.next/server/chunks/471.js +0 -2
  167. package/.next/standalone/.next/server/chunks/617.js +0 -1
  168. package/.next/standalone/.next/server/chunks/644.js +0 -1
  169. package/.next/standalone/.next/server/chunks/972.js +0 -12
  170. package/.next/static/chunks/444-6c0edb23956d018d.js +0 -1
  171. package/.next/static/chunks/783-3af6dbdb6afb55f4.js +0 -1
  172. package/.next/static/chunks/app/hypotheses/page-2cf90570526c76d3.js +0 -1
  173. package/.next/static/chunks/app/ideas/[id]/page-e0cca1557b59f7e0.js +0 -1
  174. package/.next/static/chunks/app/layout-ae8acf4955ee5472.js +0 -1
  175. package/.next/static/chunks/app/page-6a52a6950963129a.js +0 -1
  176. package/.next/static/chunks/app/roadmap/page-94d002cf0e37260f.js +0 -1
  177. package/.next/static/chunks/app/sessions/page-8085e6da5e28c7e4.js +0 -1
  178. package/.next/static/chunks/app/settings/page-34f70eef4a23eb4c.js +0 -1
  179. package/.next/static/css/501d0ac30341ebbe.css +0 -3
  180. /package/.next/static/chunks/{117-b74c3899e29d85d7.js → 117-23260fd0b5f0bd9a.js} +0 -0
  181. /package/.next/static/chunks/app/_not-found/{page-2573b25f318b094f.js → page-a7be1c556b396c8e.js} +0 -0
  182. /package/.next/static/chunks/{fd9d1056-2182e078483b259b.js → fd9d1056-8c714984d5b17b60.js} +0 -0
  183. /package/.next/static/{k40DKimnEdAtBs_zywSQ4 → zsq0nh_UpsL0_XvQlU2YE}/_buildManifest.js +0 -0
  184. /package/.next/static/{k40DKimnEdAtBs_zywSQ4 → zsq0nh_UpsL0_XvQlU2YE}/_ssgManifest.js +0 -0
@@ -153,6 +153,7 @@ var COMPETITORS_FILE = path2.join(DATA_DIR, "competitors.json");
153
153
  var POSITIONING_FILE = path2.join(DATA_DIR, "positioning.json");
154
154
  var PAGES_FILE = path2.join(DATA_DIR, "pages.json");
155
155
  var PAYMENTS_FILE = path2.join(DATA_DIR, "payments.json");
156
+ var SOCIAL_FILE = path2.join(DATA_DIR, "social.json");
156
157
  var TEMPLATES_DIR = path2.join(__dirname, "..", "..", "templates");
157
158
  var COMMAND_TEMPLATES_DIR = path2.join(TEMPLATES_DIR, "commands");
158
159
 
@@ -132,6 +132,7 @@ var CONFIG_DIR2 = path3.join(process.env.HOME || "", ".vibebusiness");
132
132
  var LICENSE_FILE = path3.join(CONFIG_DIR2, "license.json");
133
133
  var TRIAL_DURATION_DAYS = 14;
134
134
  var OFFLINE_GRACE_DAYS = 30;
135
+ var LICENSE_API_URL = "https://vibebusiness.com/api/license/validate";
135
136
  var TIER_LIMITS = {
136
137
  trial: { maxRepos: 999 },
137
138
  // unlimited during trial
@@ -166,6 +167,25 @@ function maskKey(key) {
166
167
  if (key.length <= 8) return "****";
167
168
  return key.slice(0, 4) + "****" + key.slice(-4);
168
169
  }
170
+ async function callValidationAPI(key) {
171
+ try {
172
+ const controller = new AbortController();
173
+ const timeout = setTimeout(() => controller.abort(), 1e4);
174
+ const res = await fetch(LICENSE_API_URL, {
175
+ method: "POST",
176
+ headers: { "Content-Type": "application/json" },
177
+ body: JSON.stringify({ key }),
178
+ signal: controller.signal
179
+ });
180
+ clearTimeout(timeout);
181
+ if (!res.ok) {
182
+ return { valid: false };
183
+ }
184
+ return await res.json();
185
+ } catch {
186
+ return null;
187
+ }
188
+ }
169
189
  function startTrial() {
170
190
  const now = /* @__PURE__ */ new Date();
171
191
  const expiresAt = new Date(now.getTime() + TRIAL_DURATION_DAYS * 24 * 60 * 60 * 1e3);
@@ -228,9 +248,30 @@ async function validateLicense() {
228
248
  }
229
249
  const lastValidated = stored.lastValidated ? new Date(stored.lastValidated) : null;
230
250
  const daysSinceValidation = lastValidated ? (now.getTime() - lastValidated.getTime()) / (24 * 60 * 60 * 1e3) : Infinity;
231
- if (daysSinceValidation > 7) {
232
- const needsOnlineCheck = daysSinceValidation > OFFLINE_GRACE_DAYS;
233
- if (needsOnlineCheck) {
251
+ if (daysSinceValidation > 7 && stored.key) {
252
+ const apiResult = await callValidationAPI(stored.key);
253
+ if (apiResult === null) {
254
+ if (daysSinceValidation > OFFLINE_GRACE_DAYS) {
255
+ return {
256
+ status: "expired",
257
+ tier: stored.tier,
258
+ keyMasked: maskKey(stored.key),
259
+ lastValidated: stored.lastValidated,
260
+ expiresAt: stored.expiresAt,
261
+ maxRepos: 0,
262
+ message: `License validation expired (last checked ${Math.floor(daysSinceValidation)} days ago). Connect to the internet to re-validate.`
263
+ };
264
+ }
265
+ } else if (apiResult.valid) {
266
+ stored.lastValidated = now.toISOString();
267
+ stored.status = "valid";
268
+ if (apiResult.email) stored.email = apiResult.email;
269
+ if (apiResult.tier) stored.tier = apiResult.tier;
270
+ saveStoredLicense(stored);
271
+ } else {
272
+ stored.status = "expired";
273
+ stored.lastValidated = now.toISOString();
274
+ saveStoredLicense(stored);
234
275
  return {
235
276
  status: "expired",
236
277
  tier: stored.tier,
@@ -238,11 +279,9 @@ async function validateLicense() {
238
279
  lastValidated: stored.lastValidated,
239
280
  expiresAt: stored.expiresAt,
240
281
  maxRepos: 0,
241
- message: `License validation expired (last checked ${Math.floor(daysSinceValidation)} days ago). Connect to the internet to re-validate.`
282
+ message: "Subscription expired. Renew at https://vibebusiness.com/pricing to continue."
242
283
  };
243
284
  }
244
- stored.lastValidated = now.toISOString();
245
- saveStoredLicense(stored);
246
285
  }
247
286
  return {
248
287
  status: "valid",
@@ -443,6 +482,7 @@ var COMPETITORS_FILE = path6.join(DATA_DIR, "competitors.json");
443
482
  var POSITIONING_FILE = path6.join(DATA_DIR, "positioning.json");
444
483
  var PAGES_FILE = path6.join(DATA_DIR, "pages.json");
445
484
  var PAYMENTS_FILE = path6.join(DATA_DIR, "payments.json");
485
+ var SOCIAL_FILE = path6.join(DATA_DIR, "social.json");
446
486
  var TEMPLATES_DIR = path6.join(__dirname, "..", "..", "templates");
447
487
  var COMMAND_TEMPLATES_DIR = path6.join(TEMPLATES_DIR, "commands");
448
488
 
@@ -300,6 +300,7 @@ var COMPETITORS_FILE = path2.join(DATA_DIR, "competitors.json");
300
300
  var POSITIONING_FILE = path2.join(DATA_DIR, "positioning.json");
301
301
  var PAGES_FILE = path2.join(DATA_DIR, "pages.json");
302
302
  var PAYMENTS_FILE = path2.join(DATA_DIR, "payments.json");
303
+ var SOCIAL_FILE = path2.join(DATA_DIR, "social.json");
303
304
  var TEMPLATES_DIR = path2.join(__dirname, "..", "..", "templates");
304
305
  var COMMAND_TEMPLATES_DIR = path2.join(TEMPLATES_DIR, "commands");
305
306
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibebusiness",
3
- "version": "1.2.39",
3
+ "version": "1.2.42",
4
4
  "description": "AI-powered autonomous business analyst. Research. Build. Ship. Grow.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "private": false,
@@ -69,5 +69,9 @@
69
69
  "typescript": "^5.4.5",
70
70
  "uuid": "^9.0.1",
71
71
  "vitest": "^4.0.18"
72
+ },
73
+ "dependencies": {
74
+ "stripe": "^20.3.1",
75
+ "twitter-api-v2": "^1.29.0"
72
76
  }
73
77
  }
@@ -3,6 +3,7 @@
3
3
  ## Usage
4
4
  ```
5
5
  /email-marketing setup # Guided Loops.so setup wizard
6
+ /email-marketing verify # Verify the email pipeline is working end-to-end
6
7
  /email-marketing campaign welcome # Generate a welcome email campaign
7
8
  /email-marketing campaign onboarding # Generate an onboarding drip email
8
9
  /email-marketing campaign feature-announcement # New feature announcement
@@ -19,6 +20,77 @@
19
20
 
20
21
  Parse `$ARGUMENTS` to determine mode. The first word is the mode, the rest are arguments.
21
22
 
23
+ ## Copy Quality Framework
24
+
25
+ When generating ANY email campaign, follow these rules. They override generic instincts.
26
+
27
+ ### Positioning Integration (Required)
28
+
29
+ Before writing, load `data/positioning.json` and extract:
30
+ - **Pain points** — Lead with one that matches the campaign's audience
31
+ - **Messaging pillars** — Weave 1-2 into the body (Autonomous Intelligence, Full Lifecycle Closure, Built for Indie Hackers, Compounding Value)
32
+ - **Objection handlers** — Preempt 1 relevant objection (e.g., "not a ChatGPT wrapper", "can I trust AI?")
33
+ - **Social proof** — Include 1 credibility anchor (user count, autonomous shipping proof, market analysis)
34
+ - **CTA bank** — Pull CTA text from positioning rather than inventing generic ones
35
+ - **Headlines** — Use copy_bank headlines as inspiration for subject lines
36
+
37
+ ### Subject Lines
38
+
39
+ Write 3 variations using these formulas:
40
+ 1. **Curiosity + outcome**: "The 1 thing that changes how you decide what to build"
41
+ 2. **Specific benefit**: "Your first business analysis in 60 seconds"
42
+ 3. **Pattern interrupt**: "Every dev tool waits for you. This one doesn't."
43
+
44
+ Rules:
45
+ - Under 50 characters (avoid mobile truncation)
46
+ - No "Welcome to [Product]!" or "We're excited!"
47
+ - Test: would YOU open this from an unknown sender?
48
+
49
+ ### Opening Lines
50
+
51
+ NEVER use:
52
+ - "Hey there," / "Hi there," / "Hello,"
53
+ - "Welcome to [Product]!"
54
+ - "We're excited to have you!"
55
+ - "Hope this email finds you well"
56
+
57
+ INSTEAD, use one of these patterns:
58
+ - **Pain-point hook**: "You signed up because you're tired of guessing what to build next."
59
+ - **Outcome statement**: "One command. Your entire business strategy. That's what you just unlocked."
60
+ - **Observation**: "Most dev tools help you write code faster. None of them tell you what code to write."
61
+ - **Direct + warm**: "You're in. Here's the short version of what happens next."
62
+
63
+ ### Body Copy Rules
64
+
65
+ - **Length**: 80-150 words for welcome; 150-250 for educational/onboarding
66
+ - **Paragraphs**: Max 2-3 sentences each
67
+ - **One idea per email** — don't feature-dump
68
+ - **Benefits over features**: "decides what to ship next" not "uses AI analysis"
69
+ - **Bold key phrases** for scannability
70
+ - **Address one objection** naturally (not as a FAQ — weave it in)
71
+ - **Include social proof** inline, not as a separate section
72
+
73
+ ### CTA Rules
74
+
75
+ - **Primary CTA**: One clear action button. First-person verb: "Start my analysis" not "Get started"
76
+ - **Secondary CTA**: One reply/engagement prompt: "Reply and tell me..."
77
+ - **No vague CTAs**: "Get Started" is banned. Be specific: "Run your first analysis", "See what it finds"
78
+ - **Place primary CTA after the core benefit**, not at the very end
79
+
80
+ ### Preview Text
81
+
82
+ Formula: [Pain point or hook] + [time/effort] + [outcome]
83
+ - "Stop guessing what to build. 60 seconds to your first strategy."
84
+ - "Your AI analyst just found 12 ideas you missed."
85
+
86
+ ### Tone
87
+
88
+ - **Founder voice** — write as a person, not a brand
89
+ - **Confident, not hype** — "This will change how you work" not "We're SO excited!!!"
90
+ - **Respect the reader's time** — if it can be said in fewer words, do it
91
+ - **Technical credibility** — don't dumb things down for developers
92
+ - **CLI-native language** — reference terminal, commands, repos — not "dashboards" or "platforms"
93
+
22
94
  ---
23
95
 
24
96
  ### Mode: `setup`
@@ -51,7 +123,66 @@ Interactive Loops.so setup wizard.
51
123
  }
52
124
  ```
53
125
 
54
- 5. **Print Summary**: What was set up, what was already configured, next steps (run `/email-marketing campaign welcome` to create first email).
126
+ 5. **Print Dashboard Setup Checklist**: After the API setup steps above, print a clear checklist of manual steps the user must complete in the Loops dashboard (the Loops API cannot create templates or automations programmatically):
127
+
128
+ ```
129
+ ## Manual Loops Dashboard Setup Required
130
+
131
+ The Loops API cannot create templates or automations programmatically.
132
+ Complete these steps in the Loops dashboard (https://app.loops.so):
133
+
134
+ ### 1. Create Mailing List
135
+ - Go to: Audience → Lists → Create List
136
+ - Name: "Beta Waitlist"
137
+
138
+ ### 2. Create Transactional Email Template
139
+ - Go to: Transactional → New Transactional Email
140
+ - Name: "Welcome — Waitlist"
141
+ - Copy subject/body from: data/email-campaigns/welcome-2026-02-20.md
142
+ - Set reply-to: your personal email
143
+
144
+ ### 3. Create Automation
145
+ - Go to: Automations → New Automation
146
+ - Trigger: Event → "waitlist_joined"
147
+ - Action: Send transactional email → "Welcome — Waitlist"
148
+ - Activate the automation
149
+
150
+ ### 4. Verify Pipeline
151
+ - Run: /email-marketing verify
152
+ ```
153
+
154
+ 6. **Print Summary**: What was set up, what was already configured, next steps (run `/email-marketing verify` to test the pipeline).
155
+
156
+ ---
157
+
158
+ ### Mode: `verify`
159
+
160
+ Verify that the full email pipeline (API → mailing lists → templates → automations) is working.
161
+
162
+ 1. **Verify API Key**: Call `GET /api/v1/api-key` — print PASS or FAIL
163
+ 2. **Check Mailing Lists**: Call the Loops API to list mailing lists — print PASS if at least 1 exists, FAIL with instructions otherwise
164
+ 3. **Check Transactional Templates**: Call the Loops API to list transactional email templates — print PASS if at least 1 exists, FAIL with instructions otherwise
165
+ 4. **Test Pipeline End-to-End**:
166
+ - Create a test contact with email `test-verify-{timestamp}@example.com`
167
+ - Set properties: `source: "verify_test"`, `userGroup: "test"`
168
+ - Send a `waitlist_joined` event for that contact
169
+ - Print PASS if both API calls succeed
170
+ 5. **Print Results Checklist**:
171
+ ```
172
+ ## Email Pipeline Verification
173
+
174
+ [PASS/FAIL] API Key — valid (team: {teamName})
175
+ [PASS/FAIL] Mailing Lists — {count} found
176
+ [PASS/FAIL] Transactional Templates — {count} found
177
+ [PASS/FAIL] Test Event — waitlist_joined sent to test contact
178
+
179
+ {If all pass:}
180
+ All checks passed! Your email pipeline is ready.
181
+ Submit a real email on your waitlist form to confirm delivery.
182
+
183
+ {If any fail:}
184
+ Some checks failed. Complete the manual setup steps above, then re-run /email-marketing verify.
185
+ ```
55
186
 
56
187
  ---
57
188
 
@@ -68,18 +199,25 @@ Supported types: `welcome`, `onboarding`, `feature-announcement`, `re-engagement
68
199
 
69
200
  2. **Generate Campaign** based on type:
70
201
 
71
- **`welcome`** — First email after signup:
72
- - Subject line (3 variations)
73
- - Preview text
74
- - Body: warm greeting → what they signed up for → what to expect → single CTA
75
- - Tone: enthusiastic but professional, use brand voice from positioning
76
- - Include personalization tokens: `{{firstName}}`, `{{source}}`
202
+ **`welcome`** — First email after waitlist/signup:
203
+ - Subject line (3 variations using formulas above)
204
+ - Preview text (using formula above)
205
+ - Body structure:
206
+ 1. Pain-point opening (from positioning pain_points lead with "decision paralysis")
207
+ 2. One-sentence value prop (what they signed up for, in bold)
208
+ 3. How it's different (vs Cursor/Copilot — the brain/hands distinction)
209
+ 4. What to expect (2-3 bullet points: early access timing, build-in-public updates, no spam)
210
+ 5. Engagement CTA: "Reply and tell me: what's the one thing you wish AI could handle?"
211
+ 6. Founder sign-off with P.S. (address one objection: BYOK/privacy, cost, or trust)
212
+ - Tone: founder letter, personal, confident — NOT corporate welcome
213
+ - Include personalization tokens: `{{source}}` (no `{{firstName}}` — waitlist form collects email only)
214
+ - DO NOT include: feature lists, setup instructions, or multiple CTAs
77
215
 
78
216
  **`onboarding`** — Guide new users to first value:
79
217
  - Subject line (3 variations)
80
- - Body: acknowledge signup → quickstart stepslink to docs → CTA to first action
81
- - Focus on time-to-value messaging from positioning
82
- - Include personalization: `{{firstName}}`
218
+ - Body: acknowledge signup → one quick-win action expected outcome → CTA to first action
219
+ - Focus on time-to-value: "60 seconds to your first analysis"
220
+ - Include personalization: `{{source}}`
83
221
 
84
222
  **`feature-announcement`** — New feature shipped:
85
223
  - Subject line (3 variations)
@@ -0,0 +1,84 @@
1
+ # /launch-campaign — Multi-Channel Marketing Campaign Orchestrator
2
+
3
+ ## Usage
4
+ ```
5
+ /launch-campaign ship {ideaId} # Full ship campaign
6
+ /launch-campaign milestone {kpiId} # Milestone celebration campaign
7
+ /launch-campaign status # List active/completed campaigns
8
+ ```
9
+
10
+ ## Input
11
+ - `$ARGUMENTS` — required: campaign type and parameters
12
+
13
+ ## Process
14
+
15
+ Parse `$ARGUMENTS` to determine the campaign type.
16
+
17
+ ### Type: `ship {ideaId}`
18
+
19
+ Orchestrate a full ship announcement campaign across all configured channels.
20
+
21
+ 1. **Load Context**:
22
+ - Read `data/ideas.json` — find the shipped idea by ID
23
+ - Read `data/positioning.json` — for copy quality
24
+ - Read `data/social.json` — check if X is configured
25
+ - Check if Loops email is configured (LOOPS_API_KEY in env)
26
+ - Check `data/business-context.json` — ContentFlow config
27
+
28
+ 2. **Generate Campaign Plan**:
29
+ Based on what channels are configured, queue these sub-tasks in TODO.md:
30
+ - `generate-visual-{ideaId}` — Ship card PNG (if not already generated)
31
+ - `video-render-ship-{ideaId}` — Ship video (if ContentFlow configured)
32
+ - `copy-tweet-ship` — Generate positioning-driven tweet copy
33
+ - `social-draft-ship-visual` — Create tweet draft with media (after card/video ready)
34
+ - `email-campaign-feature-announcement` — Email announcement draft
35
+ - `copy-social-linkedin` — LinkedIn post copy
36
+
37
+ 3. **Write Campaign State**: Save to `data/campaigns/{ideaId}-{YYYY-MM-DD}.json`:
38
+ ```json
39
+ {
40
+ "id": "campaign-{ideaId}-{date}",
41
+ "type": "ship",
42
+ "idea_id": "{ideaId}",
43
+ "created_at": "{ISO date}",
44
+ "status": "active",
45
+ "sub_tasks": [
46
+ { "task_id": "generate-visual-{ideaId}", "status": "queued" },
47
+ { "task_id": "video-render-ship-{ideaId}", "status": "queued" },
48
+ { "task_id": "copy-tweet-ship", "status": "queued" },
49
+ { "task_id": "social-draft-ship-visual", "status": "queued" },
50
+ { "task_id": "email-campaign-feature-announcement", "status": "queued" },
51
+ { "task_id": "copy-social-linkedin", "status": "queued" }
52
+ ],
53
+ "channels": ["x", "email", "linkedin"]
54
+ }
55
+ ```
56
+
57
+ 4. **Add Sub-Tasks to TODO.md**: Write each sub-task as a high-priority TODO item.
58
+ Sub-tasks execute on subsequent heartbeats (natural pacing, not all at once).
59
+
60
+ 5. **Print Campaign Summary**: What was queued, which channels, estimated timeline.
61
+
62
+ ### Type: `milestone {kpiId}`
63
+
64
+ Orchestrate a milestone celebration campaign.
65
+
66
+ 1. **Load KPI Data**: Find the KPI in `data/goals.json`
67
+ 2. **Queue Sub-Tasks**:
68
+ - `copy-tweet-milestone` — Milestone tweet copy
69
+ - `social-draft-milestone` — Tweet draft
70
+ - `email-campaign-milestone` — Celebration email
71
+ 3. **Save Campaign State**: Same format as ship, but type "milestone"
72
+
73
+ ### Type: `status`
74
+
75
+ List all campaigns and their sub-task completion status.
76
+
77
+ 1. Read all files from `data/campaigns/`
78
+ 2. For each campaign, check sub-task completion (cross-reference with TODO.md)
79
+ 3. Print summary table
80
+
81
+ ## Output
82
+ - Campaign state: `data/campaigns/{id}.json`
83
+ - Sub-tasks: Added to `TODO.md` as high-priority items
84
+ - Print: Campaign summary with channel list and task queue
@@ -0,0 +1,186 @@
1
+ # /promo-copy — Positioning-Driven Promotional Copy Generator
2
+
3
+ ## Usage
4
+ ```
5
+ /promo-copy tweet-ship # Ship announcement tweet (≤280 chars)
6
+ /promo-copy tweet-milestone # KPI milestone tweet
7
+ /promo-copy tweet-update # Product update tweet
8
+ /promo-copy tweet-thread # Multi-tweet thread (3-5 tweets)
9
+ /promo-copy ad-google {keyword} # Google Ads copy (3 headlines + 2 descriptions)
10
+ /promo-copy ad-meta {audience} # Meta/Instagram ad copy
11
+ /promo-copy linkedin # LinkedIn post (≤3000 chars)
12
+ /promo-copy landing {slug} # Landing page copy block
13
+ /promo-copy email-subject {campaign} # 5 email subject line variations
14
+ ```
15
+
16
+ ## Input
17
+ - `$ARGUMENTS` — required: copy type and optional parameters
18
+
19
+ ## Process
20
+
21
+ Parse `$ARGUMENTS` to determine the copy type. The first token is the type, the rest are parameters.
22
+
23
+ ## Positioning Integration (Required)
24
+
25
+ Before writing ANY copy, load `data/positioning.json` and extract:
26
+ - **Pain points** — Lead with the most relevant one for this channel/audience
27
+ - **Messaging pillars** — Weave 1-2 into the copy naturally
28
+ - **Objection handlers** — Preempt 1 relevant objection where appropriate
29
+ - **Social proof** — Include 1 credibility anchor (user count, shipped features, market validation)
30
+ - **CTA bank** — Pull CTAs from positioning rather than inventing generic ones
31
+ - **Headlines/Tagline** — Use copy_bank headlines as inspiration
32
+ - **Tone** — Match the founder's voice from positioning (confident, technical, direct)
33
+
34
+ Also load:
35
+ - `data/ideas.json` — For ship/milestone tweets, get specific feature details
36
+ - `data/goals.json` — For milestone copy, get KPI data
37
+ - `data/business-context.json` — Product info, audience, value proposition
38
+
39
+ ## Copy Quality Rules
40
+
41
+ These rules apply to ALL copy types. They override generic instincts.
42
+
43
+ ### Tone & Voice
44
+ - **Founder voice** — Write as a person, not a brand or marketing department
45
+ - **Confident, not hype** — "This changes how you work" not "We're SO excited!!!"
46
+ - **Technical credibility** — Don't dumb things down for developers
47
+ - **Respect the reader** — If it can be said in fewer words, do it
48
+ - **No corporate speak** — No "leverage", "synergy", "ecosystem", "revolutionize"
49
+
50
+ ### CTA Rules
51
+ - First-person verbs: "Start my analysis" not "Get started"
52
+ - Be specific: "Run your first analysis" not "Learn more"
53
+ - One CTA per copy piece (except threads/landing pages)
54
+
55
+ ### Banned Phrases
56
+ - "Game-changer", "Revolutionize", "Disrupt"
57
+ - "We're excited to announce"
58
+ - "Stay tuned", "Watch this space"
59
+ - "It's that simple" (if it takes more than 1 step, it's not)
60
+ - Generic hashtags like #startup #entrepreneur (use specific ones)
61
+
62
+ ---
63
+
64
+ ### Type: `tweet-ship`
65
+
66
+ Generate a "just shipped" tweet for the most recently shipped idea.
67
+
68
+ 1. Load the most recently shipped idea from `data/ideas.json`
69
+ 2. Write 3 tweet variations (pick the best one):
70
+ - **Hook-first**: Lead with the problem it solves, then reveal the feature
71
+ - **Result-first**: Lead with the outcome, then explain what shipped
72
+ - **Story-first**: Brief build narrative → what shipped → result
73
+ 3. Include: the feature name, what it does for users, 1-2 relevant hashtags
74
+ 4. Must be ≤280 characters
75
+ 5. Tone: excited but authentic, build-in-public energy
76
+
77
+ ### Type: `tweet-milestone`
78
+
79
+ Generate a milestone celebration tweet.
80
+
81
+ 1. Load KPI data from `data/goals.json` — find KPIs at or above target
82
+ 2. Write the tweet: metric + achievement + what it means + hashtag
83
+ 3. Include a forward-looking hook: "Next target: ..."
84
+ 4. Must be ≤280 characters
85
+
86
+ ### Type: `tweet-update`
87
+
88
+ Generate a product update tweet from positioning data.
89
+
90
+ 1. Lead with tagline or value proposition hook
91
+ 2. Include 1 specific differentiator
92
+ 3. End with CTA or hashtag
93
+ 4. Must be ≤280 characters
94
+
95
+ ### Type: `tweet-thread`
96
+
97
+ Generate a 3-5 tweet thread on a positioning topic.
98
+
99
+ 1. Tweet 1: Hook (pain point or bold claim)
100
+ 2. Tweet 2-3: Evidence/story (what you built, why it's different)
101
+ 3. Tweet 4: Social proof or result
102
+ 4. Tweet 5: CTA
103
+ 5. Each tweet ≤280 characters, numbered with emoji (1/, 2/, etc.)
104
+
105
+ ### Type: `ad-google {keyword}`
106
+
107
+ Generate Google Ads copy for a target keyword.
108
+
109
+ 1. **3 Headlines** (max 30 characters each):
110
+ - H1: Keyword + core benefit
111
+ - H2: Differentiator
112
+ - H3: Social proof or urgency
113
+ 2. **2 Descriptions** (max 90 characters each):
114
+ - D1: Expand on benefit, address pain point
115
+ - D2: CTA + differentiator
116
+ 3. Include the keyword naturally (no keyword stuffing)
117
+
118
+ ### Type: `ad-meta {audience}`
119
+
120
+ Generate Meta/Instagram ad copy.
121
+
122
+ 1. **Primary text** (125 chars ideal, 250 max): Hook + benefit + CTA
123
+ 2. **Headline** (40 chars max): Core value proposition
124
+ 3. **Description** (30 chars max): Supporting detail
125
+ 4. **CTA button**: Choose from (Learn More, Sign Up, Get Started, Try Free)
126
+ 5. Write for the specified audience segment
127
+
128
+ ### Type: `linkedin`
129
+
130
+ Generate a LinkedIn post for professional audience.
131
+
132
+ 1. **Hook line** (first line visible before "see more"): Bold claim or question
133
+ 2. **Body** (500-1500 chars): Problem → solution → proof → insight
134
+ 3. **CTA**: Engagement prompt ("What's your take?" or link to product)
135
+ 4. Format: Short paragraphs, line breaks between thoughts, 1-2 emoji max
136
+ 5. Total ≤3000 characters
137
+
138
+ ### Type: `landing {slug}`
139
+
140
+ Generate a landing page copy block.
141
+
142
+ 1. **Headline** (8-12 words): Outcome-focused, addresses primary pain point
143
+ 2. **Subheadline** (15-25 words): How the product delivers that outcome
144
+ 3. **3 Benefits**: Icon-worthy phrases (3-8 words each) with 1-sentence descriptions
145
+ 4. **CTA button text**: First-person, specific action
146
+ 5. **Social proof line**: One credibility statement
147
+
148
+ ### Type: `email-subject {campaign}`
149
+
150
+ Generate 5 email subject line variations for a campaign type.
151
+
152
+ 1. Load campaign context from `data/email-campaigns/` if available
153
+ 2. Generate 5 variations using these formulas:
154
+ - Curiosity + outcome
155
+ - Specific benefit + number
156
+ - Pattern interrupt
157
+ - Question format
158
+ - FOMO / urgency (authentic, not fake)
159
+ 3. Each under 50 characters
160
+ 4. Include preview text for each (50-90 chars)
161
+
162
+ ---
163
+
164
+ ## Output
165
+
166
+ Save the generated copy to `data/copy/{type}-{slug}-{YYYY-MM-DD}.md`:
167
+
168
+ ```markdown
169
+ # {Type} Copy — {Date}
170
+
171
+ ## Metadata
172
+ - Type: {type}
173
+ - Generated: {date}
174
+ - Positioning version: {last_updated from positioning.json}
175
+ - Parameters: {any extra params}
176
+
177
+ ## Copy
178
+
179
+ {The generated copy, clearly formatted}
180
+
181
+ ## Variations
182
+
183
+ {Alternative versions if applicable}
184
+ ```
185
+
186
+ Print a summary: copy preview, character count, file path.