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,169 @@
1
+ <purpose>
2
+ Technical and content SEO audit of a URL or content. Evaluates against SEO playbook
3
+ gate definitions and generates a structured PASS/WARN/FAIL report per check.
4
+ Single-pass analysis workflow per D-07.
5
+ </purpose>
6
+
7
+ <required_reading>
8
+ @${CLAUDE_PLUGIN_ROOT}/references/context-loading.md
9
+ @${CLAUDE_PLUGIN_ROOT}/playbooks/seo.md
10
+ </required_reading>
11
+
12
+ <constraints>
13
+ ## POSITIONING.md is READ-ONLY
14
+
15
+ **Do NOT modify `.marketing/POSITIONING.md` during this workflow.**
16
+
17
+ POSITIONING.md is an architectural invariant. If you detect positioning drift:
18
+ - Flag the issue and recommend running /ttm-positioning-check
19
+
20
+ Only /ttm-positioning-shift and /ttm-init may modify POSITIONING.md.
21
+ </constraints>
22
+
23
+ <process>
24
+
25
+ ## Text-Mode Detection
26
+
27
+ **Text mode (`--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS`
28
+ or if the runtime is not Claude Code. When TEXT_MODE is active, replace every
29
+ `AskUserQuestion` call with a plain-text numbered list.
30
+
31
+ Detection:
32
+ ```bash
33
+ if echo "$ARGUMENTS" | grep -q -- '--text'; then TEXT_MODE=true; fi
34
+ ```
35
+
36
+ If `AskUserQuestion` tool is not available in the current runtime, set `TEXT_MODE=true`.
37
+
38
+ ---
39
+
40
+ ## Step 1: Load Context
41
+
42
+ ```
43
+ takeToMarket > LOADING CONTEXT FOR SEO AUDIT
44
+ ```
45
+
46
+ **Tier 1 summaries** (lines 1 to `<!-- END_SUMMARY -->`) from all 9 `.marketing/` reference files.
47
+ **Tier 2 (full):** `.marketing/CHANNELS.md` (channel-specific SEO config).
48
+ **Playbook gates:** @${CLAUDE_PLUGIN_ROOT}/playbooks/seo.md
49
+
50
+ If `.marketing/POSITIONING.md` does not exist: Error and exit.
51
+
52
+ ---
53
+
54
+ ## Step 2: Get Audit Target
55
+
56
+ Ask: "What would you like to audit? Provide a URL, file path, or paste content directly."
57
+
58
+ Parse input:
59
+ - **URL** (starts with `http://` or `https://`): Attempt WebFetch for page content.
60
+ - **WebFetch available (SEARCH_MODE=web):** Fetch and analyze.
61
+ - **WebFetch NOT available (SEARCH_MODE=manual):** Ask user to paste page content.
62
+ - **File path:** Read the file directly.
63
+ - **Pasted content:** Use directly.
64
+
65
+ Store as `AUDIT_CONTENT` and `AUDIT_TARGET`.
66
+
67
+ ---
68
+
69
+ ## Step 3: Run SEO Gate Checks
70
+
71
+ ```
72
+ takeToMarket > RUNNING SEO GATE CHECKS
73
+ ```
74
+
75
+ Evaluate `AUDIT_CONTENT` against 8 SEO discipline gates:
76
+
77
+ **1. Search Intent Match (DISC-SEO-02)**
78
+ - PASS: Content format and opening directly match the search intent
79
+ - WARN: Content addresses query but format is mixed or answer is buried
80
+ - FAIL: Content format contradicts the search intent
81
+
82
+ **2. Keyword Placement (DISC-SEO-01)**
83
+ Target keyword in: title tag, H1, first 100 words, meta description, H2.
84
+ - PASS: Keyword in title, H1, first 100 words; title 50-60 chars
85
+ - WARN: Missing from 1-2 placements; title 45-49 or 61-70 chars
86
+ - FAIL: Missing from title or H1; title under 30 or over 70 chars
87
+
88
+ **3. Content Structure**
89
+ Heading hierarchy (H1 > H2 > H3), no skipped levels, H2 sections 150-400 words.
90
+ - PASS: Single H1, logical hierarchy, no skipped levels
91
+ - WARN: Minor hierarchy issues or uneven section lengths
92
+ - FAIL: No H1, multiple H1s, or broken hierarchy
93
+
94
+ **4. Internal Linking Density (DISC-SEO-04)**
95
+ - PASS: 3-6 internal links per 1000 words with descriptive anchors
96
+ - WARN: 1-2 internal links per 1000 words
97
+ - FAIL: 0 internal links
98
+
99
+ **5. Schema Markup (DISC-SEO-03)**
100
+ Article, FAQ, HowTo, or Product schema with required fields.
101
+ - PASS: Appropriate schema type with all required fields
102
+ - WARN: Schema present but incomplete
103
+ - FAIL: No schema for content that qualifies
104
+
105
+ **6. Entity Coverage**
106
+ Key entities search engines associate with the topic.
107
+ - PASS: References relevant entities (people, orgs, concepts)
108
+ - WARN: Some coverage but missing key entities
109
+ - FAIL: No recognizable entity references
110
+
111
+ **7. Thin Content Detection (DISC-SEO-05)**
112
+ - PASS: 800+ words standard (300+ programmatic); original analysis present
113
+ - WARN: 500-799 words; mostly summarized
114
+ - FAIL: Under 500 words; boilerplate content
115
+
116
+ **8. Core Web Vitals Budget (DISC-SEO-07)**
117
+ - PASS: Optimized images with dimensions, lazy-load, no render blockers
118
+ - WARN: Images missing dimensions or unoptimized formats
119
+ - FAIL: Heavy unoptimized media or render-blocking embeds
120
+
121
+ Per check: assign PASS / WARN / FAIL with specific evidence.
122
+
123
+ ---
124
+
125
+ ## Step 4: Generate Report
126
+
127
+ Display structured report:
128
+ ```
129
+ ========================================
130
+ takeToMarket > SEO AUDIT REPORT
131
+ ========================================
132
+ Target: [URL or filename]
133
+ Date: [current date]
134
+ Overall: [X/8 PASS] [Y/8 WARN] [Z/8 FAIL]
135
+
136
+ | # | Gate | Result | Evidence |
137
+ |---|------------------------|--------|-----------------------|
138
+ | 1 | Search Intent Match | [P/W/F] | [brief evidence] |
139
+ | 2 | Keyword Placement | [P/W/F] | [brief evidence] |
140
+ | 3 | Content Structure | [P/W/F] | [brief evidence] |
141
+ | 4 | Internal Linking | [P/W/F] | [brief evidence] |
142
+ | 5 | Schema Markup | [P/W/F] | [brief evidence] |
143
+ | 6 | Entity Coverage | [P/W/F] | [brief evidence] |
144
+ | 7 | Thin Content Detection | [P/W/F] | [brief evidence] |
145
+ | 8 | Core Web Vitals Budget | [P/W/F] | [brief evidence] |
146
+
147
+ FINDINGS (WARN/FAIL details):
148
+ - [Gate]: [Issue and recommendation]
149
+
150
+ RECOMMENDATIONS (priority-ordered):
151
+ 1. [Highest-impact fix]
152
+ 2. [Next priority]
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Step 5: Completion
158
+
159
+ ```
160
+ ========================================
161
+ takeToMarket > SEO AUDIT COMPLETE
162
+ ========================================
163
+ Target: ${AUDIT_TARGET} | Result: [X/8 PASS] [Y/8 WARN] [Z/8 FAIL]
164
+ ```
165
+
166
+ Offer: "Save this report to .marketing/AUDITS/seo-audit-[date].md? (yes/no)"
167
+ If yes: create `.marketing/AUDITS/` directory if needed and write the report.
168
+
169
+ </process>
File without changes
@@ -0,0 +1,90 @@
1
+ # Positioning Check Rules
2
+
3
+ ## Usage
4
+
5
+ Referenced by `workflows/lifecycle/brief.md` via @-syntax.
6
+ Applied after brief content is fully generated to detect positioning drift.
7
+ This is a soft gate per D-05 -- the brief is ALWAYS generated regardless of gate result.
8
+ Drift produces a warning, not a block.
9
+
10
+ ---
11
+
12
+ ## Check 1: Positioning Anchor Alignment
13
+
14
+ **Field:** Brief's "Positioning Anchor > Key message"
15
+ **Checks against:** POSITIONING.md primary differentiator phrase
16
+
17
+ - PASS: Brief's positioning anchor restates or naturally extends the primary differentiator
18
+ - WARN: Brief's anchor partially overlaps but introduces claims not present in POSITIONING.md
19
+ - FAIL: Brief's anchor uses a different differentiation claim entirely
20
+
21
+ **Drift detail format:** "Positioning anchor '[brief anchor]' does not align with primary differentiator '[positioning differentiator]'"
22
+
23
+ ## Check 2: ICP Segment Match
24
+
25
+ **Field:** Brief's "ICP Segment > Primary segment"
26
+ **Checks against:** POSITIONING.md target audience
27
+
28
+ - PASS: Brief's ICP segment matches or is a sub-segment of the POSITIONING.md target audience
29
+ - WARN: Brief targets an adjacent audience not explicitly in POSITIONING.md
30
+ - FAIL: Brief targets a completely different audience
31
+
32
+ **Drift detail format:** "ICP segment '[brief segment]' does not match target audience '[positioning audience]'"
33
+
34
+ ## Check 3: Proof Point Sourcing
35
+
36
+ **Field:** Brief's "Proof Points" table
37
+ **Checks against:** POSITIONING.md must-include proof points
38
+
39
+ - PASS: All proof points in the brief are sourced from POSITIONING.md proof point library
40
+ - WARN: Brief includes proof points not in the library (may be valid new evidence)
41
+ - FAIL: Brief makes claims with no proof point sourcing at all
42
+
43
+ **Drift detail format:** "Proof point '[claim]' not found in POSITIONING.md proof point library"
44
+
45
+ ## Check 4: Must-Not-Say Terms
46
+
47
+ **Field:** Entire brief content
48
+ **Checks against:** POSITIONING.md must-not-say terms list
49
+
50
+ - PASS: No must-not-say terms found in brief
51
+ - FAIL: One or more must-not-say terms detected
52
+
53
+ **Drift detail format:** "Must-not-say term '[term]' found in brief [section]"
54
+
55
+ ## Check 5: Hook-Positioning Coherence
56
+
57
+ **Field:** Brief's "Hook" section
58
+ **Checks against:** POSITIONING.md primary differentiator and category
59
+
60
+ - PASS: Hook reinforces the positioning -- uses aligned language and framing
61
+ - WARN: Hook is neutral -- does not reinforce but does not contradict
62
+ - FAIL: Hook contradicts the positioning or uses competitor framing
63
+
64
+ **Drift detail format:** "Hook framing '[hook summary]' contradicts positioning category '[category]'"
65
+
66
+ ---
67
+
68
+ ## Gate Result Logic
69
+
70
+ - If ALL checks PASS: gate result = "pass"
71
+ - If ANY check is WARN or FAIL: gate result = "warn"
72
+ - The brief is ALWAYS generated regardless of gate result (per D-05)
73
+
74
+ ## Drift Warning Template
75
+
76
+ When gate result is "warn", insert at the TOP of BRIEF.md after the title line:
77
+
78
+ ```
79
+ <!--
80
+ !! POSITIONING DRIFT WARNING !!
81
+ The following items may not align with your positioning:
82
+ - [drift detail from each failing check]
83
+ Review .marketing/POSITIONING.md and adjust the brief if needed.
84
+ Run /ttm-positioning-check for a full audit.
85
+ -->
86
+ ```
87
+
88
+ This is an HTML comment so it is visible in source but not rendered.
89
+ The warning uses specific drift detail format strings from each failing check
90
+ so the user can pinpoint exactly what drifted and from what reference value.
@@ -0,0 +1,355 @@
1
+ <purpose>
2
+ Campaign brief generation workflow with outcome metric enforcement (LIFE-04) and
3
+ positioning check gate (LIFE-05). Collects all mandatory brief fields (D-07),
4
+ validates outcome metrics with guided re-prompting (D-06), runs 5-check positioning
5
+ gate that warns on drift without blocking (D-05), and writes the completed brief
6
+ to CAMPAIGNS/<slug>/BRIEF.md. This is the gate between campaign planning and
7
+ content production.
8
+ </purpose>
9
+
10
+ <required_reading>
11
+ @${CLAUDE_PLUGIN_ROOT}/references/context-loading.md
12
+ @${CLAUDE_PLUGIN_ROOT}/workflows/lifecycle/brief-positioning-check.md
13
+ @${CLAUDE_PLUGIN_ROOT}/templates/campaign-brief.md
14
+ </required_reading>
15
+
16
+ <constraints>
17
+ ## POSITIONING.md is READ-ONLY
18
+
19
+ **Do NOT modify `.marketing/POSITIONING.md` during this workflow.**
20
+
21
+ POSITIONING.md is an architectural invariant. If you detect positioning drift:
22
+ - In verify: use the Escalate option to launch /ttm-positioning-shift
23
+ - In other workflows: flag the issue and recommend running /ttm-positioning-check
24
+
25
+ Only /ttm-positioning-shift and /ttm-init may modify POSITIONING.md.
26
+ </constraints>
27
+
28
+ <process>
29
+
30
+ ## Text-Mode Detection
31
+
32
+ **Text mode (`--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS`
33
+ or if the runtime is not Claude Code. When TEXT_MODE is active, replace every
34
+ `AskUserQuestion` call with a plain-text numbered list.
35
+
36
+ Detection:
37
+ ```bash
38
+ if echo "$ARGUMENTS" | grep -q -- '--text'; then TEXT_MODE=true; fi
39
+ ```
40
+
41
+ If `AskUserQuestion` tool is not available in the current runtime, set `TEXT_MODE=true`.
42
+
43
+ When TEXT_MODE is active, replace each AskUserQuestion with a plain-text numbered list:
44
+ ```
45
+ [HEADER]
46
+ [QUESTION]
47
+ 1. [OPTION_1_LABEL] -- [OPTION_1_DESCRIPTION]
48
+ 2. [OPTION_2_LABEL] -- [OPTION_2_DESCRIPTION]
49
+ ...
50
+ Type the number of your choice:
51
+ ```
52
+
53
+ For multiSelect questions, instruct the user: "Type the numbers of your choices separated by commas (e.g., 1,3,5):"
54
+
55
+ ---
56
+
57
+ ## Step 1: Load Context
58
+
59
+ ```
60
+ takeToMarket > LOADING CONTEXT
61
+ ```
62
+
63
+ Extract SLUG from $ARGUMENTS (strip `--text` flag if present):
64
+ ```bash
65
+ SLUG=$(echo "$ARGUMENTS" | sed 's/--text//g' | xargs)
66
+ ```
67
+
68
+ Read Tier 1 summaries from all 9 reference files (lines 1 to `<!-- END_SUMMARY -->`):
69
+ - `.marketing/POSITIONING.md`
70
+ - `.marketing/BRAND.md`
71
+ - `.marketing/ICP.md`
72
+ - `.marketing/CHANNELS.md`
73
+ - `.marketing/STATE.md` (frontmatter only)
74
+ - `.marketing/CALENDAR.md`
75
+ - `.marketing/COMPETITORS.md`
76
+ - `.marketing/METRICS.md`
77
+ - `.marketing/LEARNINGS.md`
78
+
79
+ Read Tier 2 (full content) for:
80
+ - `.marketing/ICP.md`
81
+ - `.marketing/CHANNELS.md`
82
+ - `.marketing/METRICS.md`
83
+ - `.marketing/CALENDAR.md`
84
+
85
+ Read full `.marketing/POSITIONING.md` (needed for positioning check gate in Step 6).
86
+
87
+ Read campaign-specific files (always full-load per context-loading.md rule 4):
88
+ - `.marketing/CAMPAIGNS/${SLUG}/STATE.md`
89
+ - `.marketing/CAMPAIGNS/${SLUG}/RESEARCH.md`
90
+
91
+ ---
92
+
93
+ ## Step 2: Validate Campaign and Phase Order (per D-08)
94
+
95
+ Check campaign exists:
96
+ ```bash
97
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign state "${SLUG}" --raw
98
+ ```
99
+
100
+ If result shows `exists: false`: Tell the user the campaign does not exist and suggest running `/ttm-new-campaign` first. Exit.
101
+
102
+ Read campaign state. Check the `phase` field:
103
+
104
+ - If phase is `"created"`:
105
+ Warn the user:
106
+ "Research not yet completed for this campaign. Brief quality will be limited without research data. Run `/ttm-research ${SLUG}` first for better results. Proceed without research?"
107
+ Wait for user confirmation. If user declines, exit.
108
+
109
+ - If phase is NOT `"created"` and NOT `"researched"`:
110
+ Warn the user:
111
+ "Campaign is in phase `${PHASE}`. Expected 'researched' before briefing. Running /ttm-brief now will overwrite the existing BRIEF.md. Proceed?"
112
+ Wait for user confirmation. If user declines, exit.
113
+
114
+ Check if RESEARCH.md has actual content (not just template placeholders):
115
+ - Read `.marketing/CAMPAIGNS/${SLUG}/RESEARCH.md`
116
+ - If file contains only `[GENERATED BY /ttm-research]` placeholders: set `RESEARCH_AVAILABLE=false`
117
+ - If file has real content beyond placeholders: set `RESEARCH_AVAILABLE=true`
118
+
119
+ ---
120
+
121
+ ## Step 3: Outcome Metric Enforcement (per D-06, LIFE-04)
122
+
123
+ ```
124
+ takeToMarket > GENERATING BRIEF
125
+ ```
126
+
127
+ **Collect campaign goal:**
128
+
129
+ Ask (freeform, NOT AskUserQuestion):
130
+ "What is the goal of this campaign? (One sentence describing the campaign's purpose)"
131
+
132
+ Store the response as `CAMPAIGN_GOAL`.
133
+
134
+ **Collect outcome metric:**
135
+
136
+ Ask (freeform):
137
+ "What is the outcome metric for this campaign? An outcome metric measures a business result, not an output action.
138
+
139
+ Examples:
140
+ - VALID: 'Increase trial signups by 20% within 30 days'
141
+ - VALID: 'Generate 50 qualified leads from organic search in Q2'
142
+ - NOT VALID: 'Publish 4 blog posts' (this is an output, not an outcome)
143
+
144
+ What business outcome will this campaign drive?"
145
+
146
+ **Validate the response:**
147
+
148
+ - FAIL if metric starts with output verbs: publish, write, send, create, post, design, build, launch (without a measurable outcome attached)
149
+ - FAIL if no target value (number, percentage, or specific benchmark) is present
150
+ - FAIL if no measurement window (timeframe) is present
151
+
152
+ **On FAIL (retry 1):** Re-prompt with explanation:
153
+ "That looks like an output metric, not an outcome. An output is what you produce (blog posts, emails). An outcome is the business result (signups, revenue, leads). Please provide: [specific business outcome] + [target value] + [measurement window]"
154
+
155
+ **On FAIL (retry 2):** Re-prompt once more with different framing:
156
+ "I still need a measurable business outcome. Think about what changes in your business AFTER the content is published. Example: 'Increase demo requests by 15% within 60 days of launch.' What business result are you targeting?"
157
+
158
+ **After 2 failed retries:** Block brief generation entirely. Tell user:
159
+ "Cannot generate a brief without a valid outcome metric. A brief without a measurable business outcome would produce untestable content. Run `/ttm-brief ${SLUG}` again when ready."
160
+ Exit.
161
+
162
+ **On PASS:** Store as `OUTCOME_METRIC`. Extract `target_value` and `measurement_window` from the response.
163
+
164
+ **Collect output metric:**
165
+
166
+ Ask (freeform):
167
+ "What are the output metrics? (Assets and volume to produce, e.g., '4 blog posts, 2 emails, 1 landing page')"
168
+
169
+ If the user provides an empty response or declines: set `OUTPUT_METRIC_MISSING=true`. Continue. This is allowed per D-06.
170
+
171
+ ---
172
+
173
+ ## Step 4: Collect Remaining Brief Fields (per D-07)
174
+
175
+ **ICP Segment:**
176
+ Read the primary segment from `.marketing/ICP.md` Tier 1 summary. Present it to the user:
177
+ "Your primary ICP segment is: [segment from ICP.md]. Is this correct for this campaign, or are you targeting a specific sub-segment?"
178
+ Store the confirmed or adjusted segment as `ICP_SEGMENT`.
179
+
180
+ **Channel Mix:**
181
+ Read active channels from `.marketing/CHANNELS.md`.
182
+
183
+ Use AskUserQuestion (or text-mode numbered list) with `multiSelect=true`:
184
+ - header: "Channel Selection"
185
+ - question: "Which channels will this campaign use?"
186
+ - options: One option per active channel from CHANNELS.md
187
+
188
+ After selection, for each selected channel ask:
189
+ "What is the role of [channel] in this campaign? (primary / support / amplification)"
190
+ Store channel selections with roles as `CHANNEL_MIX`.
191
+
192
+ **Hook:**
193
+ If `RESEARCH_AVAILABLE=true`: Present key findings from RESEARCH.md (ambient narrative, content gaps) and suggest hook angles based on them.
194
+ Ask: "What is the opening angle or attention-capture strategy for this campaign?"
195
+ Store as `HOOK`.
196
+
197
+ **Proof Points:**
198
+ Read proof points from `.marketing/POSITIONING.md` Proof Point Library table.
199
+ Display the available proof points. Ask:
200
+ "These are your approved proof points. Do you want to add any campaign-specific claims or evidence?"
201
+ Store base proof points plus any additions as `PROOF_POINTS`.
202
+
203
+ **Timeline:**
204
+ Ask: "What is the target ship date for this campaign?"
205
+ Derive remaining timeline dates backward from the ship date:
206
+ - Brief complete: today
207
+ - Production start: ship date minus appropriate buffer
208
+ - Review complete: ship date minus review buffer
209
+ - Measurement start: ship date
210
+ - Learn review: ship date + measurement window
211
+ Store as `TIMELINE`.
212
+
213
+ **Success Criteria:**
214
+ Ask: "What specific, measurable outcomes define success for this campaign beyond the outcome metric?"
215
+ Store as `SUCCESS_CRITERIA`.
216
+
217
+ **Failure Criteria:**
218
+ Ask: "What conditions should trigger a campaign pause or kill?"
219
+ Store as `FAILURE_CRITERIA`.
220
+
221
+ ---
222
+
223
+ ## Step 5: Generate BRIEF.md
224
+
225
+ Read the brief template:
226
+ ```
227
+ ${CLAUDE_PLUGIN_ROOT}/templates/campaign-brief.md
228
+ ```
229
+
230
+ Fill ALL `[GENERATED BY /ttm-brief]` placeholders with collected data:
231
+
232
+ - **Campaign Name:** From campaign STATE.md `name` field
233
+ - **Goal:** From `CAMPAIGN_GOAL`
234
+ - **Outcome Metric section:**
235
+ - Metric: `OUTCOME_METRIC`
236
+ - Target value: extracted `target_value`
237
+ - Measurement window: extracted `measurement_window`
238
+ - Data source: inferred from metric type or ask user
239
+ - **Output Metric section:** From output metrics collected in Step 3
240
+ - If `OUTPUT_METRIC_MISSING=true`, insert after the Output Metric section:
241
+ `<!-- OUTPUT_METRIC_MISSING: Add output metrics before /ttm-produce -->`
242
+ - **ICP Segment:** From `ICP_SEGMENT` (Step 4)
243
+ - **Positioning Anchor:**
244
+ - Key message: derived from POSITIONING.md primary differentiator, adapted for campaign
245
+ - Primary differentiator: quoted directly from POSITIONING.md
246
+ - **Hook:** From `HOOK` (Step 4)
247
+ - **Proof Points table:** From `PROOF_POINTS` -- POSITIONING.md proof library + campaign additions
248
+ - **Channel Mix table:** From `CHANNEL_MIX` with roles (Step 4)
249
+ - **Assets List table:** Derived from output metrics + channel mix
250
+ - **Success Criteria:** From `SUCCESS_CRITERIA` (Step 4)
251
+ - **Failure Criteria:** From `FAILURE_CRITERIA` (Step 4)
252
+ - **Dependencies:** Inferred from campaign context (reference files, tools, approvals needed)
253
+ - **Timeline table:** From `TIMELINE` (Step 4)
254
+
255
+ Store the generated content as `BRIEF_CONTENT`.
256
+
257
+ ---
258
+
259
+ ## Step 6: Positioning Check Gate (per D-05, LIFE-05)
260
+
261
+ ```
262
+ takeToMarket > POSITIONING CHECK
263
+ ```
264
+
265
+ Read the positioning check rules from `@${CLAUDE_PLUGIN_ROOT}/workflows/lifecycle/brief-positioning-check.md`.
266
+
267
+ Apply all 5 checks against `BRIEF_CONTENT`:
268
+
269
+ 1. **Positioning Anchor Alignment:** Compare brief's "Positioning Anchor > Key message" against POSITIONING.md primary differentiator phrase. Determine PASS/WARN/FAIL.
270
+
271
+ 2. **ICP Segment Match:** Compare brief's "ICP Segment > Primary segment" against POSITIONING.md target audience. Determine PASS/WARN/FAIL.
272
+
273
+ 3. **Proof Point Sourcing:** Check each proof point in the brief against POSITIONING.md proof point library. Determine PASS/WARN/FAIL.
274
+
275
+ 4. **Must-Not-Say Terms:** Scan entire brief content for any terms from POSITIONING.md must-not-say list. Determine PASS/FAIL.
276
+
277
+ 5. **Hook-Positioning Coherence:** Compare brief's hook against POSITIONING.md primary differentiator and category. Determine PASS/WARN/FAIL.
278
+
279
+ **Determine gate result:**
280
+ - If ALL checks PASS: gate result = `"pass"`
281
+ - If ANY check is WARN or FAIL: gate result = `"warn"`
282
+
283
+ **If gate result is "warn":** Insert the drift warning HTML comment block at the top of BRIEF_CONTENT, after the title line. List each specific drift item using the drift detail format string from the check rules:
284
+
285
+ ```
286
+ <!--
287
+ !! POSITIONING DRIFT WARNING !!
288
+ The following items may not align with your positioning:
289
+ - [drift detail from each failing check, using format strings from brief-positioning-check.md]
290
+ Review .marketing/POSITIONING.md and adjust the brief if needed.
291
+ Run /ttm-positioning-check for a full audit.
292
+ -->
293
+ ```
294
+
295
+ The brief is written unconditionally. NEVER block brief generation on positioning drift (per D-05).
296
+
297
+ ---
298
+
299
+ ## Step 7: Write BRIEF.md and Update State
300
+
301
+ Write `BRIEF_CONTENT` to `.marketing/CAMPAIGNS/${SLUG}/BRIEF.md`.
302
+
303
+ Update campaign state:
304
+ ```bash
305
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" phase briefed
306
+ TIMESTAMP=$(node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" timestamp --raw)
307
+ if [ -z "$TIMESTAMP" ]; then
308
+ echo "Error: could not get timestamp"; exit 1
309
+ fi
310
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" phase.briefed "$TIMESTAMP"
311
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" gate.outcome_metric pass
312
+ node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" gate.positioning_check [pass|warn]
313
+ ```
314
+
315
+ Replace `[pass|warn]` with the actual gate result from Step 6.
316
+
317
+ ---
318
+
319
+ ## Step 8: Display Summary
320
+
321
+ ```
322
+ takeToMarket > BRIEF COMPLETE
323
+
324
+ Brief saved to .marketing/CAMPAIGNS/${SLUG}/BRIEF.md
325
+
326
+ Outcome metric: [OUTCOME_METRIC]
327
+ Positioning check: [pass|warn]
328
+ Output metric: [defined|MISSING -- add before /ttm-produce]
329
+ Channels: [list of selected channels]
330
+ Assets: [count] planned
331
+
332
+ [If positioning_check=warn:]
333
+ !! Positioning drift detected -- see warning in BRIEF.md
334
+ Review .marketing/POSITIONING.md and adjust if needed.
335
+
336
+ Next: Run /ttm-produce ${SLUG}
337
+ ```
338
+
339
+ </process>
340
+
341
+ <success_criteria>
342
+ - [ ] Context loaded (Tier 1 all files, Tier 2 ICP/CHANNELS/METRICS/CALENDAR, full POSITIONING.md)
343
+ - [ ] Campaign validated and phase order checked (D-08)
344
+ - [ ] Outcome metric enforced -- valid business outcome with target value and measurement window (D-06, LIFE-04)
345
+ - [ ] Output metric collected or flagged as missing (D-06)
346
+ - [ ] All mandatory brief fields present in generated BRIEF.md (D-07)
347
+ - [ ] Positioning check gate executed with all 5 checks from brief-positioning-check.md (D-05, LIFE-05)
348
+ - [ ] BRIEF.md written unconditionally -- never blocked by positioning drift (D-05)
349
+ - [ ] Campaign state updated: phase=briefed, gate.outcome_metric, gate.positioning_check
350
+ - [ ] OUTPUT_METRIC_MISSING flag visible in BRIEF.md when applicable
351
+ </success_criteria>
352
+
353
+ <output>
354
+ - `.marketing/CAMPAIGNS/<slug>/BRIEF.md` (populated with all mandatory fields)
355
+ </output>