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.
- package/.claude-plugin/plugin.json +10 -0
- package/LICENSE +21 -0
- package/README.md +419 -0
- package/agents/ttm-producer.md +53 -0
- package/bin/lib/campaign.cjs +553 -0
- package/bin/lib/commit.cjs +105 -0
- package/bin/lib/core.cjs +172 -0
- package/bin/lib/deviation.cjs +149 -0
- package/bin/lib/drift-log.cjs +219 -0
- package/bin/lib/health.cjs +438 -0
- package/bin/lib/slug.cjs +59 -0
- package/bin/lib/state.cjs +96 -0
- package/bin/ttm-tools.cjs +157 -0
- package/gates/base-gates.md +266 -0
- package/gates/discipline/.gitkeep +0 -0
- package/gates/gate-evaluation.md +341 -0
- package/gates/meta-gates.md +19 -0
- package/install.js +307 -0
- package/package.json +53 -0
- package/playbooks/.gitkeep +0 -0
- package/playbooks/aeo.md +223 -0
- package/playbooks/affiliate.md +272 -0
- package/playbooks/base.md +110 -0
- package/playbooks/email.md +306 -0
- package/playbooks/events.md +320 -0
- package/playbooks/linkedin.md +263 -0
- package/playbooks/paid-ads.md +318 -0
- package/playbooks/pr-media.md +296 -0
- package/playbooks/seo.md +284 -0
- package/playbooks/social.md +305 -0
- package/playbooks/youtube.md +325 -0
- package/references/context-loading.md +107 -0
- package/references/learnings-extraction.md +94 -0
- package/references/measurement-template.md +48 -0
- package/references/meta-gate-evaluation.md +169 -0
- package/references/positioning-check-report.md +197 -0
- package/references/review-checklist.md +78 -0
- package/references/ship-checklist-items.md +94 -0
- package/settings.json +4 -0
- package/skills/ttm-aeo-check/SKILL.md +20 -0
- package/skills/ttm-affiliate-kit/SKILL.md +19 -0
- package/skills/ttm-archive/SKILL.md +13 -0
- package/skills/ttm-brand-refresh/SKILL.md +19 -0
- package/skills/ttm-brief/SKILL.md +14 -0
- package/skills/ttm-competitor-scan/SKILL.md +19 -0
- package/skills/ttm-email-preflight/SKILL.md +19 -0
- package/skills/ttm-fix/SKILL.md +13 -0
- package/skills/ttm-health/SKILL.md +12 -0
- package/skills/ttm-icp-refresh/SKILL.md +19 -0
- package/skills/ttm-init/SKILL.md +12 -0
- package/skills/ttm-keyword-map/SKILL.md +19 -0
- package/skills/ttm-learn/SKILL.md +14 -0
- package/skills/ttm-measure/SKILL.md +14 -0
- package/skills/ttm-new-campaign/SKILL.md +13 -0
- package/skills/ttm-next/SKILL.md +12 -0
- package/skills/ttm-positioning-check/SKILL.md +19 -0
- package/skills/ttm-positioning-shift/SKILL.md +19 -0
- package/skills/ttm-produce/SKILL.md +14 -0
- package/skills/ttm-repurpose/SKILL.md +20 -0
- package/skills/ttm-research/SKILL.md +13 -0
- package/skills/ttm-resume/SKILL.md +13 -0
- package/skills/ttm-review/SKILL.md +13 -0
- package/skills/ttm-seo-audit/SKILL.md +20 -0
- package/skills/ttm-ship/SKILL.md +13 -0
- package/skills/ttm-state/SKILL.md +13 -0
- package/skills/ttm-verify/SKILL.md +14 -0
- package/templates/agents-md.md +65 -0
- package/templates/campaign-brief.md +74 -0
- package/templates/campaign-research.md +39 -0
- package/templates/campaign-state.md +40 -0
- package/templates/claude-md.md +65 -0
- package/templates/deviation-log.md +12 -0
- package/templates/drift-log.md +17 -0
- package/templates/fix-brief.md +59 -0
- package/templates/fix-log.md +22 -0
- package/templates/measurement-report.md +75 -0
- package/templates/migration-plan.md +24 -0
- package/templates/production-manifest.json +20 -0
- package/templates/reference-files/brand.md +45 -0
- package/templates/reference-files/calendar.md +30 -0
- package/templates/reference-files/channels.md +40 -0
- package/templates/reference-files/competitors.md +40 -0
- package/templates/reference-files/icp.md +50 -0
- package/templates/reference-files/learnings.md +40 -0
- package/templates/reference-files/metrics.md +42 -0
- package/templates/reference-files/positioning.md +38 -0
- package/templates/reference-files/state.md +27 -0
- package/templates/verification-report.md +59 -0
- package/workflows/discipline/.gitkeep +0 -0
- package/workflows/discipline/aeo-check.md +180 -0
- package/workflows/discipline/affiliate-kit.md +147 -0
- package/workflows/discipline/email-preflight.md +150 -0
- package/workflows/discipline/keyword-map.md +125 -0
- package/workflows/discipline/repurpose.md +329 -0
- package/workflows/discipline/seo-audit.md +169 -0
- package/workflows/lifecycle/.gitkeep +0 -0
- package/workflows/lifecycle/brief-positioning-check.md +90 -0
- package/workflows/lifecycle/brief.md +355 -0
- package/workflows/lifecycle/fix.md +495 -0
- package/workflows/lifecycle/learn.md +405 -0
- package/workflows/lifecycle/measure.md +379 -0
- package/workflows/lifecycle/produce.md +383 -0
- package/workflows/lifecycle/research.md +264 -0
- package/workflows/lifecycle/review.md +432 -0
- package/workflows/lifecycle/ship.md +521 -0
- package/workflows/lifecycle/verify.md +507 -0
- package/workflows/reference-mgmt/.gitkeep +0 -0
- package/workflows/reference-mgmt/brand-refresh.md +193 -0
- package/workflows/reference-mgmt/competitor-scan.md +228 -0
- package/workflows/reference-mgmt/icp-refresh.md +200 -0
- package/workflows/reference-mgmt/positioning-check.md +339 -0
- package/workflows/reference-mgmt/positioning-shift.md +368 -0
- package/workflows/setup/.gitkeep +0 -0
- package/workflows/setup/init-questions.md +225 -0
- package/workflows/setup/init-validation.md +155 -0
- package/workflows/setup/init.md +449 -0
- package/workflows/setup/new-campaign.md +134 -0
- package/workflows/utility/.gitkeep +0 -0
- package/workflows/utility/archive.md +334 -0
- package/workflows/utility/health.md +166 -0
- package/workflows/utility/next.md +187 -0
- package/workflows/utility/resume.md +249 -0
- 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>
|