taketomarket 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.
Files changed (123) hide show
  1. package/.claude-plugin/plugin.json +10 -0
  2. package/LICENSE +21 -0
  3. package/README.md +419 -0
  4. package/agents/ttm-producer.md +53 -0
  5. package/bin/lib/campaign.cjs +553 -0
  6. package/bin/lib/commit.cjs +105 -0
  7. package/bin/lib/core.cjs +172 -0
  8. package/bin/lib/deviation.cjs +149 -0
  9. package/bin/lib/drift-log.cjs +219 -0
  10. package/bin/lib/health.cjs +438 -0
  11. package/bin/lib/slug.cjs +59 -0
  12. package/bin/lib/state.cjs +96 -0
  13. package/bin/ttm-tools.cjs +157 -0
  14. package/gates/base-gates.md +266 -0
  15. package/gates/discipline/.gitkeep +0 -0
  16. package/gates/gate-evaluation.md +341 -0
  17. package/gates/meta-gates.md +19 -0
  18. package/install.js +307 -0
  19. package/package.json +53 -0
  20. package/playbooks/.gitkeep +0 -0
  21. package/playbooks/aeo.md +223 -0
  22. package/playbooks/affiliate.md +272 -0
  23. package/playbooks/base.md +110 -0
  24. package/playbooks/email.md +306 -0
  25. package/playbooks/events.md +320 -0
  26. package/playbooks/linkedin.md +263 -0
  27. package/playbooks/paid-ads.md +318 -0
  28. package/playbooks/pr-media.md +296 -0
  29. package/playbooks/seo.md +284 -0
  30. package/playbooks/social.md +305 -0
  31. package/playbooks/youtube.md +325 -0
  32. package/references/context-loading.md +107 -0
  33. package/references/learnings-extraction.md +94 -0
  34. package/references/measurement-template.md +48 -0
  35. package/references/meta-gate-evaluation.md +169 -0
  36. package/references/positioning-check-report.md +197 -0
  37. package/references/review-checklist.md +78 -0
  38. package/references/ship-checklist-items.md +94 -0
  39. package/settings.json +4 -0
  40. package/skills/ttm-aeo-check/SKILL.md +20 -0
  41. package/skills/ttm-affiliate-kit/SKILL.md +19 -0
  42. package/skills/ttm-archive/SKILL.md +13 -0
  43. package/skills/ttm-brand-refresh/SKILL.md +19 -0
  44. package/skills/ttm-brief/SKILL.md +14 -0
  45. package/skills/ttm-competitor-scan/SKILL.md +19 -0
  46. package/skills/ttm-email-preflight/SKILL.md +19 -0
  47. package/skills/ttm-fix/SKILL.md +13 -0
  48. package/skills/ttm-health/SKILL.md +12 -0
  49. package/skills/ttm-icp-refresh/SKILL.md +19 -0
  50. package/skills/ttm-init/SKILL.md +12 -0
  51. package/skills/ttm-keyword-map/SKILL.md +19 -0
  52. package/skills/ttm-learn/SKILL.md +14 -0
  53. package/skills/ttm-measure/SKILL.md +14 -0
  54. package/skills/ttm-new-campaign/SKILL.md +13 -0
  55. package/skills/ttm-next/SKILL.md +12 -0
  56. package/skills/ttm-positioning-check/SKILL.md +19 -0
  57. package/skills/ttm-positioning-shift/SKILL.md +19 -0
  58. package/skills/ttm-produce/SKILL.md +14 -0
  59. package/skills/ttm-repurpose/SKILL.md +20 -0
  60. package/skills/ttm-research/SKILL.md +13 -0
  61. package/skills/ttm-resume/SKILL.md +13 -0
  62. package/skills/ttm-review/SKILL.md +13 -0
  63. package/skills/ttm-seo-audit/SKILL.md +20 -0
  64. package/skills/ttm-ship/SKILL.md +13 -0
  65. package/skills/ttm-state/SKILL.md +13 -0
  66. package/skills/ttm-verify/SKILL.md +14 -0
  67. package/templates/agents-md.md +65 -0
  68. package/templates/campaign-brief.md +74 -0
  69. package/templates/campaign-research.md +39 -0
  70. package/templates/campaign-state.md +40 -0
  71. package/templates/claude-md.md +65 -0
  72. package/templates/deviation-log.md +12 -0
  73. package/templates/drift-log.md +17 -0
  74. package/templates/fix-brief.md +59 -0
  75. package/templates/fix-log.md +22 -0
  76. package/templates/measurement-report.md +75 -0
  77. package/templates/migration-plan.md +24 -0
  78. package/templates/production-manifest.json +20 -0
  79. package/templates/reference-files/brand.md +45 -0
  80. package/templates/reference-files/calendar.md +30 -0
  81. package/templates/reference-files/channels.md +40 -0
  82. package/templates/reference-files/competitors.md +40 -0
  83. package/templates/reference-files/icp.md +50 -0
  84. package/templates/reference-files/learnings.md +40 -0
  85. package/templates/reference-files/metrics.md +42 -0
  86. package/templates/reference-files/positioning.md +38 -0
  87. package/templates/reference-files/state.md +27 -0
  88. package/templates/verification-report.md +59 -0
  89. package/workflows/discipline/.gitkeep +0 -0
  90. package/workflows/discipline/aeo-check.md +180 -0
  91. package/workflows/discipline/affiliate-kit.md +147 -0
  92. package/workflows/discipline/email-preflight.md +150 -0
  93. package/workflows/discipline/keyword-map.md +125 -0
  94. package/workflows/discipline/repurpose.md +329 -0
  95. package/workflows/discipline/seo-audit.md +169 -0
  96. package/workflows/lifecycle/.gitkeep +0 -0
  97. package/workflows/lifecycle/brief-positioning-check.md +90 -0
  98. package/workflows/lifecycle/brief.md +355 -0
  99. package/workflows/lifecycle/fix.md +495 -0
  100. package/workflows/lifecycle/learn.md +405 -0
  101. package/workflows/lifecycle/measure.md +379 -0
  102. package/workflows/lifecycle/produce.md +383 -0
  103. package/workflows/lifecycle/research.md +264 -0
  104. package/workflows/lifecycle/review.md +432 -0
  105. package/workflows/lifecycle/ship.md +521 -0
  106. package/workflows/lifecycle/verify.md +507 -0
  107. package/workflows/reference-mgmt/.gitkeep +0 -0
  108. package/workflows/reference-mgmt/brand-refresh.md +193 -0
  109. package/workflows/reference-mgmt/competitor-scan.md +228 -0
  110. package/workflows/reference-mgmt/icp-refresh.md +200 -0
  111. package/workflows/reference-mgmt/positioning-check.md +339 -0
  112. package/workflows/reference-mgmt/positioning-shift.md +368 -0
  113. package/workflows/setup/.gitkeep +0 -0
  114. package/workflows/setup/init-questions.md +225 -0
  115. package/workflows/setup/init-validation.md +155 -0
  116. package/workflows/setup/init.md +449 -0
  117. package/workflows/setup/new-campaign.md +134 -0
  118. package/workflows/utility/.gitkeep +0 -0
  119. package/workflows/utility/archive.md +334 -0
  120. package/workflows/utility/health.md +166 -0
  121. package/workflows/utility/next.md +187 -0
  122. package/workflows/utility/resume.md +249 -0
  123. package/workflows/utility/state.md +207 -0
@@ -0,0 +1,383 @@
1
+ <purpose>
2
+ Production orchestration workflow for /ttm-produce. Generates content assets in
3
+ fresh Task() subagent contexts loaded with brief + positioning (full) + brand (full) +
4
+ ICP (full) + playbook (per D-03). Hero asset produced first (blocking), then
5
+ derivatives spawned in parallel (per D-01). Writes MANIFEST.json for verify
6
+ consumption (per D-11).
7
+ </purpose>
8
+
9
+ <required_reading>
10
+ @${CLAUDE_PLUGIN_ROOT}/references/context-loading.md
11
+ @${CLAUDE_PLUGIN_ROOT}/agents/ttm-producer.md
12
+ </required_reading>
13
+
14
+ <constraints>
15
+ ## POSITIONING.md is READ-ONLY
16
+
17
+ **Do NOT modify `.marketing/POSITIONING.md` during this workflow.**
18
+
19
+ POSITIONING.md is an architectural invariant. If you detect positioning drift:
20
+ - In verify: use the Escalate option to launch /ttm-positioning-shift
21
+ - In other workflows: flag the issue and recommend running /ttm-positioning-check
22
+
23
+ Only /ttm-positioning-shift and /ttm-init may modify POSITIONING.md.
24
+ </constraints>
25
+
26
+ <process>
27
+
28
+ ## Text-Mode Detection
29
+
30
+ **Text mode (`--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS`
31
+ or if the runtime is not Claude Code. When TEXT_MODE is active, replace every
32
+ `AskUserQuestion` call with a plain-text numbered list.
33
+
34
+ Detection:
35
+ ```bash
36
+ if echo "$ARGUMENTS" | grep -q -- '--text'; then TEXT_MODE=true; fi
37
+ ```
38
+
39
+ If `AskUserQuestion` tool is not available in the current runtime, set `TEXT_MODE=true`.
40
+
41
+ When TEXT_MODE is active, replace each AskUserQuestion with a plain-text numbered list:
42
+ ```
43
+ [HEADER]
44
+ [QUESTION]
45
+ 1. [OPTION_1_LABEL] -- [OPTION_1_DESCRIPTION]
46
+ 2. [OPTION_2_LABEL] -- [OPTION_2_DESCRIPTION]
47
+ ...
48
+ Type the number of your choice:
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Step 1: Load Context
54
+
55
+ ```
56
+ takeToMarket > LOADING CONTEXT
57
+ ```
58
+
59
+ Extract SLUG from $ARGUMENTS (strip `--text` flag if present):
60
+ ```bash
61
+ SLUG=$(echo "$ARGUMENTS" | sed 's/--text//g' | xargs)
62
+ ```
63
+
64
+ Read Tier 1 summaries from all 9 reference files (lines 1 to `<!-- END_SUMMARY -->`):
65
+ - `.marketing/POSITIONING.md`
66
+ - `.marketing/BRAND.md`
67
+ - `.marketing/ICP.md`
68
+ - `.marketing/CHANNELS.md`
69
+ - `.marketing/STATE.md` (frontmatter only)
70
+ - `.marketing/CALENDAR.md`
71
+ - `.marketing/COMPETITORS.md`
72
+ - `.marketing/METRICS.md`
73
+ - `.marketing/LEARNINGS.md`
74
+
75
+ Read Tier 2 (full content) for production context (per D-03):
76
+ - `.marketing/POSITIONING.md`
77
+ - `.marketing/BRAND.md`
78
+ - `.marketing/ICP.md`
79
+
80
+ Read campaign-specific files (always full-load per context-loading.md rule 4):
81
+ - `.marketing/CAMPAIGNS/${SLUG}/STATE.md`
82
+ - `.marketing/CAMPAIGNS/${SLUG}/BRIEF.md`
83
+
84
+ ---
85
+
86
+ ## Step 2: Validate Campaign State
87
+
88
+ Check campaign exists:
89
+ ```bash
90
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign state "${SLUG}" --raw
91
+ ```
92
+
93
+ If result shows `exists: false`: Tell the user the campaign does not exist and suggest running `/ttm-new-campaign` first. Exit.
94
+
95
+ Read campaign state. Check the `phase` field:
96
+
97
+ - If phase is `"briefed"`: This is the expected state. Proceed normally.
98
+
99
+ - If phase is `"created"` or `"researched"`:
100
+ Warn the user:
101
+ "Campaign has not been briefed yet. Run `/ttm-brief ${SLUG}` first to generate a brief before producing content."
102
+ Exit.
103
+
104
+ - If phase is `"produced"` or later (verified, reviewed, fixed, shipped, measured, learned):
105
+ Warn the user:
106
+ "Campaign is already in phase '${PHASE}'. Re-producing will overwrite existing assets in CAMPAIGNS/${SLUG}/ASSETS/. Proceed?"
107
+ Wait for user confirmation. If user declines, exit.
108
+
109
+ ---
110
+
111
+ ## Step 3: Parse Assets List from Brief
112
+
113
+ ```
114
+ takeToMarket > PARSING BRIEF
115
+ ```
116
+
117
+ Read `.marketing/CAMPAIGNS/${SLUG}/BRIEF.md`.
118
+
119
+ Extract the assets list from the brief. The brief contains an "Assets List" section (created by /ttm-brief) structured as a Markdown table with columns: asset type, channel, and role.
120
+
121
+ Parse each row into an asset entry:
122
+ - `type`: The asset type (e.g., blog-post, linkedin-post, email, landing-page)
123
+ - `channel`: The target channel (e.g., organic-search, linkedin, email)
124
+ - `is_hero`: `true` for the FIRST asset in the list, `false` for all others (per D-01)
125
+
126
+ The FIRST asset in the list is the hero asset. All others are derivatives.
127
+
128
+ If no assets list is found in the brief, or if the table is empty:
129
+ Error: "Brief has no assets list -- run `/ttm-brief ${SLUG}` first to generate a complete brief."
130
+ Exit.
131
+
132
+ Store the parsed list as `ASSETS_LIST` with the total count as `TOTAL_ASSETS`.
133
+
134
+ ---
135
+
136
+ ## Step 4: Resolve Playbooks
137
+
138
+ For each asset in `ASSETS_LIST`:
139
+
140
+ 1. Map the asset type to a discipline playbook using the PLAYBOOK_MAP lookup table:
141
+
142
+ **PLAYBOOK_MAP** (asset type slug -> playbook filename):
143
+
144
+ | Asset Type | Playbook File | Discipline |
145
+ |------------|--------------|------------|
146
+ | blog-post | seo.md | SEO |
147
+ | landing-page | seo.md | SEO |
148
+ | pillar-page | seo.md | SEO |
149
+ | programmatic-seo | seo.md | SEO |
150
+ | faq-page | aeo.md | AEO |
151
+ | knowledge-base | aeo.md | AEO |
152
+ | how-to-guide | aeo.md | AEO |
153
+ | email | email.md | Email |
154
+ | email-sequence | email.md | Email |
155
+ | newsletter | email.md | Email |
156
+ | linkedin-post | linkedin.md | LinkedIn |
157
+ | linkedin-article | linkedin.md | LinkedIn |
158
+ | linkedin-carousel | linkedin.md | LinkedIn |
159
+ | social-post | social.md | Social |
160
+ | twitter-thread | social.md | Social |
161
+ | instagram-carousel | social.md | Social |
162
+ | youtube-video | youtube.md | YouTube |
163
+ | youtube-short | youtube.md | YouTube |
164
+ | paid-ad | paid-ads.md | Paid Ads |
165
+ | google-ad | paid-ads.md | Paid Ads |
166
+ | meta-ad | paid-ads.md | Paid Ads |
167
+ | affiliate-kit | affiliate.md | Affiliate |
168
+ | affiliate-creative | affiliate.md | Affiliate |
169
+ | press-release | pr-media.md | PR/Media |
170
+ | media-pitch | pr-media.md | PR/Media |
171
+ | event-landing | events.md | Events |
172
+ | webinar-funnel | events.md | Events |
173
+ | event-recap | events.md | Events |
174
+
175
+ For the given asset type:
176
+ - Look up the asset type in PLAYBOOK_MAP
177
+ - If found: set `PLAYBOOK_FILE` to the mapped filename
178
+ - If NOT found: set `PLAYBOOK_FILE` to the asset type slug with `.md` extension (fallback: `${TYPE}.md`)
179
+
180
+ 2. Resolve the playbook file path: `${CLAUDE_PLUGIN_ROOT}/playbooks/${PLAYBOOK_FILE}`
181
+
182
+ 3. Check if the playbook file exists:
183
+ ```bash
184
+ test -f "${CLAUDE_PLUGIN_ROOT}/playbooks/${PLAYBOOK_FILE}"
185
+ ```
186
+
187
+ 4. If playbook exists: Record the full path as the asset's `playbook_path`.
188
+
189
+ 5. If playbook does NOT exist: Log a warning:
190
+ ```
191
+ takeToMarket > WARNING: No playbook found for "${TYPE}" (tried ${PLAYBOOK_FILE}) -- producing with base context only
192
+ ```
193
+ Set the asset's `playbook_path` to `"none"`.
194
+
195
+ This is the loading MECHANISM only -- playbook content files are created in Phase 8.
196
+
197
+ ---
198
+
199
+ ## Step 5: Produce Hero Asset
200
+
201
+ ```
202
+ takeToMarket > PRODUCING HERO ASSET
203
+ ```
204
+
205
+ Identify the hero asset (first entry in `ASSETS_LIST`).
206
+
207
+ Read the agent prompt template from `${CLAUDE_PLUGIN_ROOT}/agents/ttm-producer.md`.
208
+
209
+ Fill all placeholders with actual paths:
210
+ - `[BRIEF_PATH]` --> `.marketing/CAMPAIGNS/${SLUG}/BRIEF.md`
211
+ - `[POSITIONING_PATH]` --> `.marketing/POSITIONING.md`
212
+ - `[BRAND_PATH]` --> `.marketing/BRAND.md`
213
+ - `[ICP_PATH]` --> `.marketing/ICP.md`
214
+ - `[PLAYBOOK_PATH]` --> resolved playbook path from Step 4, or `"none"`
215
+ - `[OUTPUT_PATH]` --> `.marketing/CAMPAIGNS/${SLUG}/ASSETS/01-${HERO_TYPE}-${HERO_CHANNEL}.md`
216
+ - `[ASSET_TYPE]` --> hero asset type from brief (e.g., "blog-post")
217
+ - `[CHANNEL]` --> hero asset channel from brief (e.g., "organic-search")
218
+ - `[HERO_PATH]` --> `none` (this IS the hero asset)
219
+
220
+ Call Task() with the populated prompt.
221
+
222
+ **WAIT** for Task() to complete. The hero MUST finish before any derivatives are spawned.
223
+
224
+ After Task() returns, verify the hero file exists and has content:
225
+ ```bash
226
+ test -s ".marketing/CAMPAIGNS/${SLUG}/ASSETS/01-${HERO_TYPE}-${HERO_CHANNEL}.md"
227
+ ```
228
+
229
+ If the file is empty or missing:
230
+ Error: "Hero asset production failed -- file not written by subagent. Check the brief for completeness and try again."
231
+ Exit.
232
+
233
+ Store the hero filename as `HERO_FILE` for derivative reference.
234
+
235
+ ---
236
+
237
+ ## Step 6: Produce Derivative Assets
238
+
239
+ If `TOTAL_ASSETS` is 1 (hero only), skip this step.
240
+
241
+ ```
242
+ takeToMarket > PRODUCING DERIVATIVES (${N} assets)
243
+ ```
244
+ Where N = TOTAL_ASSETS - 1.
245
+
246
+ For each derivative asset in `ASSETS_LIST` (all entries after the hero):
247
+
248
+ 1. Read the agent prompt template from `${CLAUDE_PLUGIN_ROOT}/agents/ttm-producer.md`.
249
+
250
+ 2. Assign a sequential filename:
251
+ - Asset 2: `02-${TYPE}-${CHANNEL}.md`
252
+ - Asset 3: `03-${TYPE}-${CHANNEL}.md`
253
+ - etc.
254
+
255
+ 3. Fill all placeholders:
256
+ - `[BRIEF_PATH]` --> `.marketing/CAMPAIGNS/${SLUG}/BRIEF.md`
257
+ - `[POSITIONING_PATH]` --> `.marketing/POSITIONING.md`
258
+ - `[BRAND_PATH]` --> `.marketing/BRAND.md`
259
+ - `[ICP_PATH]` --> `.marketing/ICP.md`
260
+ - `[PLAYBOOK_PATH]` --> resolved playbook path from Step 4, or `"none"`
261
+ - `[OUTPUT_PATH]` --> `.marketing/CAMPAIGNS/${SLUG}/ASSETS/${NN}-${TYPE}-${CHANNEL}.md`
262
+ - `[ASSET_TYPE]` --> derivative asset type
263
+ - `[CHANNEL]` --> derivative asset channel
264
+ - `[HERO_PATH]` --> `.marketing/CAMPAIGNS/${SLUG}/ASSETS/${HERO_FILE}`
265
+
266
+ 4. Call Task() with the populated prompt.
267
+
268
+ All derivative Task() calls can run in parallel (per D-01 wave-parallel pattern).
269
+
270
+ After ALL derivative Task() calls complete, verify each derivative file exists and has content:
271
+ ```bash
272
+ test -s ".marketing/CAMPAIGNS/${SLUG}/ASSETS/${NN}-${TYPE}-${CHANNEL}.md"
273
+ ```
274
+
275
+ For any derivative that failed (file empty or missing):
276
+ - Log a warning: `takeToMarket > WARNING: Derivative ${NN}-${TYPE}-${CHANNEL}.md failed -- file not written`
277
+ - Continue with the remaining assets. Do NOT abort the entire production run.
278
+
279
+ Track successful and failed derivatives for the manifest.
280
+
281
+ ---
282
+
283
+ ## Step 7: Write Production Manifest
284
+
285
+ ```
286
+ takeToMarket > WRITING MANIFEST
287
+ ```
288
+
289
+ Read the manifest template from `${CLAUDE_PLUGIN_ROOT}/templates/production-manifest.json`.
290
+
291
+ Fill with actual values:
292
+
293
+ ```json
294
+ {
295
+ "campaign": "${SLUG}",
296
+ "produced_at": "${ISO_TIMESTAMP}",
297
+ "context_loaded": {
298
+ "brief": ".marketing/CAMPAIGNS/${SLUG}/BRIEF.md",
299
+ "positioning": ".marketing/POSITIONING.md",
300
+ "brand": ".marketing/BRAND.md",
301
+ "icp": ".marketing/ICP.md"
302
+ },
303
+ "hero": {
304
+ "asset_id": 1,
305
+ "name": "01-${HERO_TYPE}-${HERO_CHANNEL}",
306
+ "type": "${HERO_TYPE}",
307
+ "channel": "${HERO_CHANNEL}",
308
+ "playbook": "${HERO_PLAYBOOK_PATH_OR_NONE}",
309
+ "file": "ASSETS/01-${HERO_TYPE}-${HERO_CHANNEL}.md"
310
+ },
311
+ "derivatives": [
312
+ {
313
+ "asset_id": 2,
314
+ "name": "02-${TYPE}-${CHANNEL}",
315
+ "type": "${TYPE}",
316
+ "channel": "${CHANNEL}",
317
+ "playbook": "${PLAYBOOK_PATH_OR_NONE}",
318
+ "file": "ASSETS/02-${TYPE}-${CHANNEL}.md",
319
+ "derived_from": 1
320
+ }
321
+ ],
322
+ "total_assets": ${TOTAL_SUCCESSFUL_ASSETS}
323
+ }
324
+ ```
325
+
326
+ Generate the timestamp:
327
+ ```bash
328
+ TIMESTAMP=$(node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" timestamp --raw)
329
+ ```
330
+
331
+ Only include successfully produced assets (those that passed the `test -s` check) in the manifest.
332
+ If any derivatives failed, `total_assets` reflects only the successful count.
333
+
334
+ Write the completed manifest to `.marketing/CAMPAIGNS/${SLUG}/MANIFEST.json`.
335
+
336
+ The manifest is the ONLY bridge between produce and verify contexts (per D-11). Verify reads
337
+ this file to discover which assets exist and what context was loaded during production.
338
+
339
+ ---
340
+
341
+ ## Step 8: Update Campaign State and Summary
342
+
343
+ Update campaign phase:
344
+ ```bash
345
+ TIMESTAMP=$(node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" timestamp --raw)
346
+ if [ -z "$TIMESTAMP" ]; then
347
+ echo "Error: could not get timestamp"; exit 1
348
+ fi
349
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" phase produced
350
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" phase.produced "$TIMESTAMP"
351
+ ```
352
+
353
+ Display completion banner:
354
+ ```
355
+ takeToMarket > PRODUCTION COMPLETE
356
+
357
+ Assets produced: ${TOTAL_SUCCESSFUL_ASSETS}
358
+ Hero: 01-${HERO_TYPE}-${HERO_CHANNEL}.md
359
+ Derivatives: [list of derivative filenames]
360
+ Manifest: .marketing/CAMPAIGNS/${SLUG}/MANIFEST.json
361
+
362
+ [If any derivatives failed:]
363
+ WARNING: ${FAILED_COUNT} derivative(s) failed production. Check the manifest for details.
364
+
365
+ Next: Run /ttm-verify ${SLUG} to validate assets against quality gates
366
+ ```
367
+
368
+ </process>
369
+
370
+ <success_criteria>
371
+ - [ ] All assets from brief's assets list written to CAMPAIGNS/<slug>/ASSETS/
372
+ - [ ] Hero asset produced before derivatives (sequential then parallel)
373
+ - [ ] Each subagent loaded with brief + positioning (full) + brand (full) + ICP (full) + playbook
374
+ - [ ] MANIFEST.json written with all successful asset entries
375
+ - [ ] Campaign STATE.md updated to phase=produced with timestamp
376
+ - [ ] No playbook errors (graceful fallback for missing playbooks with warning)
377
+ - [ ] Failed derivatives logged but do not abort the run
378
+ </success_criteria>
379
+
380
+ <output>
381
+ - `.marketing/CAMPAIGNS/${SLUG}/ASSETS/*.md` (produced content files)
382
+ - `.marketing/CAMPAIGNS/${SLUG}/MANIFEST.json` (production manifest for /ttm-verify)
383
+ </output>
@@ -0,0 +1,264 @@
1
+ <purpose>
2
+ Market and audience research workflow that generates a structured RESEARCH.md for a
3
+ campaign. Detects WebSearch tool availability at runtime and falls back to manual paste
4
+ when web search tools are unavailable. Every insight is tagged with a confidence level
5
+ (HIGH/MEDIUM/LOW). Use after /ttm-new-campaign has created the campaign directory.
6
+ </purpose>
7
+
8
+ <required_reading>
9
+ @${CLAUDE_PLUGIN_ROOT}/references/context-loading.md
10
+ @${CLAUDE_PLUGIN_ROOT}/templates/campaign-research.md
11
+ </required_reading>
12
+
13
+ <process>
14
+
15
+ ## Step 1: Load Context
16
+
17
+ ```
18
+ takeToMarket > LOADING CONTEXT
19
+ ```
20
+
21
+ Read Tier 1 summary blocks (content between `<!-- _SUMMARY -->` and `<!-- END_SUMMARY -->`)
22
+ from all 9 `.marketing/` reference files:
23
+
24
+ - `.marketing/POSITIONING.md` (lines 1 to `<!-- END_SUMMARY -->`)
25
+ - `.marketing/BRAND.md` (lines 1 to `<!-- END_SUMMARY -->`)
26
+ - `.marketing/ICP.md` (lines 1 to `<!-- END_SUMMARY -->`)
27
+ - `.marketing/CHANNELS.md` (lines 1 to `<!-- END_SUMMARY -->`)
28
+ - `.marketing/STATE.md` (frontmatter only)
29
+ - `.marketing/CALENDAR.md` (lines 1 to `<!-- END_SUMMARY -->`)
30
+ - `.marketing/COMPETITORS.md` (lines 1 to `<!-- END_SUMMARY -->`)
31
+ - `.marketing/METRICS.md` (lines 1 to `<!-- END_SUMMARY -->`)
32
+ - `.marketing/LEARNINGS.md` (lines 1 to `<!-- END_SUMMARY -->`)
33
+
34
+ Read Tier 2 (full content) for:
35
+ - `.marketing/COMPETITORS.md` (per context-loading.md loading matrix -- research loads Tier 2 COMPETITORS.md)
36
+
37
+ ---
38
+
39
+ ## Step 2: Validate Campaign
40
+
41
+ Extract the campaign slug from `$ARGUMENTS`. Strip any `--text` flag if present:
42
+ ```bash
43
+ SLUG=$(echo "$ARGUMENTS" | sed 's/--text//g' | xargs)
44
+ ```
45
+
46
+ If `$SLUG` is empty: ask the user "Which campaign should I research? Provide the campaign slug or name."
47
+
48
+ Check the campaign exists:
49
+ ```bash
50
+ ls ".marketing/CAMPAIGNS/${SLUG}/STATE.md" 2>/dev/null && echo "exists" || echo "missing"
51
+ ```
52
+
53
+ **If "missing":**
54
+ Tell the user: "Campaign `${SLUG}` does not exist. Run `/ttm-new-campaign ${SLUG}` first to create it."
55
+ Exit -- do not continue.
56
+
57
+ **If "exists":**
58
+ Read campaign state:
59
+ ```bash
60
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign state "${SLUG}" --raw
61
+ ```
62
+
63
+ Read the full campaign STATE.md (campaign files are always full-loaded per context-loading.md rule 4):
64
+ - `.marketing/CAMPAIGNS/${SLUG}/STATE.md`
65
+
66
+ Store the campaign name from the state for use in RESEARCH.md generation.
67
+
68
+ ---
69
+
70
+ ## Step 3: Phase Order Check
71
+
72
+ Check the `phase` field from campaign state (Step 2).
73
+
74
+ **If phase is NOT "created":**
75
+ Warn the user: "Campaign `${SLUG}` is already in phase `${PHASE}`. Running research again will overwrite RESEARCH.md. Proceed anyway?"
76
+
77
+ Wait for user confirmation before continuing.
78
+
79
+ - If user confirms: continue to Step 4.
80
+ - If user declines: exit with message "Research cancelled."
81
+
82
+ **If phase is "created":**
83
+ Continue to Step 4.
84
+
85
+ ---
86
+
87
+ ## Step 4: Understand Campaign
88
+
89
+ Read the campaign name and any goal information from the campaign STATE.md.
90
+
91
+ Ask the user (freeform, not AskUserQuestion):
92
+ "What is the topic or focus of this campaign? What keywords or themes should I research?"
93
+
94
+ Store the response as `RESEARCH_TOPIC`.
95
+
96
+ ---
97
+
98
+ ## Step 5: Tool Detection and Research
99
+
100
+ Attempt a WebSearch call to detect tool availability. Use a minimal test query related
101
+ to the campaign topic.
102
+
103
+ ### When WebSearch is available (SEARCH_MODE=web)
104
+
105
+ ```
106
+ takeToMarket > RESEARCH MODE: WEB
107
+ ```
108
+
109
+ - Use WebSearch for SERP queries based on `RESEARCH_TOPIC` and campaign keywords
110
+ - Search for: market trends, competitor content, audience discussions, content gaps
111
+ - Use WebFetch for competitor page content extraction when specific URLs are found
112
+ - Cross-reference findings against `.marketing/COMPETITORS.md` (already loaded in Tier 2)
113
+ - Tag insights with confidence levels:
114
+ - **HIGH**: verified source URL or cited data from web search results
115
+ - **MEDIUM**: indirect evidence or partial match from search results
116
+ - **LOW**: inference drawn from patterns without direct evidence
117
+
118
+ ### When WebSearch is NOT available (SEARCH_MODE=manual)
119
+
120
+ ```
121
+ takeToMarket > RESEARCH MODE: MANUAL
122
+ ```
123
+
124
+ Tell the user:
125
+ ```
126
+ Web search tools are not available in this session.
127
+ To get the best research, please paste any of the following:
128
+
129
+ 1. Google search results for:
130
+ - "[RESEARCH_TOPIC] [year]"
131
+ - "[RESEARCH_TOPIC] best practices"
132
+ - "[RESEARCH_TOPIC] vs [competitor terms]"
133
+ 2. Any competitor blog posts or landing pages you want analyzed
134
+ 3. Reddit/forum discussions about [RESEARCH_TOPIC]
135
+ 4. Any other market data you have (reports, articles, social posts)
136
+
137
+ Paste your findings below and I will analyze them.
138
+ ```
139
+
140
+ Wait for the user to paste content.
141
+
142
+ Analyze pasted content against the loaded reference files (POSITIONING.md, ICP.md,
143
+ COMPETITORS.md summaries). Extract structured insights from the pasted material.
144
+
145
+ Tag all pasted insights as **MEDIUM** confidence (user-provided, not independently verified).
146
+ Insights cross-referenced against known COMPETITORS.md data may be elevated to HIGH.
147
+
148
+ ### Hybrid mode
149
+
150
+ If some insights come from web search and others from user paste, set method to "hybrid"
151
+ and tag each insight according to its actual source.
152
+
153
+ ---
154
+
155
+ ## Step 6: Generate RESEARCH.md
156
+
157
+ ```
158
+ takeToMarket > GENERATING RESEARCH
159
+ ```
160
+
161
+ Read the template:
162
+ ```
163
+ ${CLAUDE_PLUGIN_ROOT}/templates/campaign-research.md
164
+ ```
165
+
166
+ Fill all sections with research findings:
167
+
168
+ - Replace `[CAMPAIGN_NAME]` with the campaign name from STATE.md
169
+ - Replace `[SLUG]` with the campaign slug
170
+ - Set **Researched:** to current timestamp:
171
+ ```bash
172
+ node ${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs timestamp --raw
173
+ ```
174
+ - Set **Method:** to `web-search`, `manual-paste`, or `hybrid` based on Step 5
175
+
176
+ ### Section: Market Context
177
+ Fill the insight table with market-level findings. Each row must have:
178
+ - Insight text (specific, not generic)
179
+ - Confidence tag: HIGH, MEDIUM, or LOW
180
+ - Source (URL for web results, "user-provided" for paste, "inference" for AI analysis)
181
+
182
+ ### Section: Competitor Content Analysis
183
+ Fill the competitor table from research findings cross-referenced with COMPETITORS.md:
184
+ - Competitor name (from COMPETITORS.md or newly discovered)
185
+ - Content type (blog, landing page, social, video, etc.)
186
+ - Key message (their positioning or angle)
187
+ - Gap/Opportunity (where our positioning can differentiate)
188
+
189
+ ### Section: Audience Insights
190
+ Fill the insight table combining ICP.md Tier 1 summary with research findings:
191
+ - What the target audience cares about
192
+ - Pain points validated by research
193
+ - Language patterns observed
194
+
195
+ ### Section: Ambient Narrative
196
+ Write 2-3 paragraphs describing what the market already believes about this topic.
197
+ What is the conventional wisdom? What assumptions do most buyers hold? Where does
198
+ the market consensus create an opening for our positioning?
199
+
200
+ ### Section: Content Gaps
201
+ Fill the gaps table with opportunities where quality content is missing or weak:
202
+ - Gap description (specific topic or angle)
203
+ - Opportunity size: HIGH (no quality content exists), MEDIUM (content exists but is weak), LOW (content exists but can be improved)
204
+ - Difficulty: HIGH (requires deep expertise), MEDIUM (moderate effort), LOW (straightforward)
205
+
206
+ ### Section: Research Summary
207
+ Write a 2-3 sentence summary that `/ttm-brief` will consume. Focus on: the biggest
208
+ opportunity, the key audience insight, and the competitive angle.
209
+
210
+ Write the completed research to:
211
+ ```
212
+ .marketing/CAMPAIGNS/${SLUG}/RESEARCH.md
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Step 7: Update Campaign State
218
+
219
+ Update the campaign phase and timestamp:
220
+ ```bash
221
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" phase researched
222
+ ```
223
+
224
+ ```bash
225
+ TIMESTAMP=$(node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" timestamp --raw)
226
+ if [ -z "$TIMESTAMP" ]; then
227
+ echo "Error: could not get timestamp"; exit 1
228
+ fi
229
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" phase.researched "$TIMESTAMP"
230
+ ```
231
+
232
+ Count the total insights generated across all sections.
233
+
234
+ Display summary:
235
+ ```
236
+ takeToMarket > RESEARCH COMPLETE
237
+
238
+ Research saved to .marketing/CAMPAIGNS/${SLUG}/RESEARCH.md
239
+ Method: [web-search|manual-paste|hybrid]
240
+ Insights: [count] with confidence breakdown
241
+ HIGH: [count]
242
+ MEDIUM: [count]
243
+ LOW: [count]
244
+
245
+ Next: Run /ttm-brief ${SLUG}
246
+ ```
247
+
248
+ </process>
249
+
250
+ <success_criteria>
251
+ - [ ] Context loaded (Tier 1 all 9 files, Tier 2 COMPETITORS.md)
252
+ - [ ] Campaign validated and slug extracted from $ARGUMENTS
253
+ - [ ] Phase order checked (warn if not "created")
254
+ - [ ] User provided research topic
255
+ - [ ] Tool detection attempted before research (WebSearch probe)
256
+ - [ ] Research generated with all 5 sections filled
257
+ - [ ] Every insight tagged with confidence level (HIGH/MEDIUM/LOW)
258
+ - [ ] RESEARCH.md written to campaign directory using template
259
+ - [ ] Campaign state updated to phase=researched with timestamp
260
+ </success_criteria>
261
+
262
+ <output>
263
+ - `.marketing/CAMPAIGNS/<slug>/RESEARCH.md` (populated with research)
264
+ </output>