// 9-phase lifecycle
Brief
/ttm-brief
Generate a campaign brief with mandatory outcome metrics, positioning anchor, and channel mix. Use when the user says "brief", "plan campaign", or invokes /ttm-brief.
Overview
Invoked with ttm-brief (or when you say "brief" or "plan campaign"), this is the spec-writing step of the takeToMarket lifecycle. You describe the audience, the outcome metric, the channel, and the angle; the skill writes a structured BRIEF.md that the production wave will load. It enforces a mandatory, measurable business outcome, collects all required brief fields, and runs a 5-check positioning sanity check against your .taketomarket/POSITIONING.md so the brief can't silently contradict the positioning invariant.
Why it matters: a brief is the request payload that fans out to multiple parallel producer subagents. Vague briefs produce inconsistent assets that fail review. The structured-question format is the equivalent of writing a typed function signature before implementing the body. This is the gate between campaign planning and content production.
Run it as /ttm-brief [campaign-slug]. Expect the campaign to be in the researched phase first (run /ttm-discover before this for the best results).
How it works
The skill reads and follows the workflow at ${CLAUDE_PLUGIN_ROOT}/workflows/lifecycle/brief.md. The full workflow is reproduced below.
Step 0: First-run inline education
Read .taketomarket/CONFIG.md. Parse first_run_seen (object) and inline_education (boolean, default true).
If inline_education is false: skip this step. Else if first_run_seen.ttm-brief is not true, print the explainer below verbatim, then mark this skill as seen:
node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" first-run mark ttm-briefUse this exact check (bash) to decide whether to print: node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" first-run check ttm-brief --raw — the JSON seen field is true once the explainer has run before.
Explainer for /ttm-brief
/ttm-brief is the spec-writing step. You describe the audience, the outcome metric, the channel, and the angle; the skill writes a structured BRIEF.md that the production wave will load. It also runs a positioning sanity check against your .taketomarket/POSITIONING.md so the brief can't silently contradict the invariant.
Why it matters: a brief is the request payload that fans out to multiple parallel producer subagents. Vague briefs produce inconsistent assets that fail review. The structured-question format is the equivalent of writing a typed function signature before implementing the body.
(Canonical source: references/inline-education-blurbs.md. Embedded verbatim because workflows do not @-resolve files at runtime.)
Purpose
Campaign brief generation workflow with outcome metric enforcement (LIFE-04) and positioning check gate (LIFE-05). Collects all mandatory brief fields (D-07), validates outcome metrics with guided re-prompting (D-06), runs a 5-check positioning gate that warns on drift without blocking (D-05), and writes the completed brief to CAMPAIGNS/<slug>/BRIEF.md. This is the gate between campaign planning and content production.
Required reading
@${CLAUDE_PLUGIN_ROOT}/references/context-loading.md@${CLAUDE_PLUGIN_ROOT}/workflows/lifecycle/brief-positioning-check.md@${CLAUDE_PLUGIN_ROOT}/templates/campaign-brief.md
Constraints
Process
Text-Mode Detection
Text mode (--text flag): Set TEXT_MODE=true if --text is present in $ARGUMENTS or if the runtime is not Claude Code. When TEXT_MODE is active, replace every AskUserQuestion call with a plain-text numbered list.
Detection:
if echo "$ARGUMENTS" | grep -q -- '--text'; then TEXT_MODE=true; fiIf AskUserQuestion tool is not available in the current runtime, set TEXT_MODE=true.
When TEXT_MODE is active, replace each AskUserQuestion with a plain-text numbered list:
[HEADER]
[QUESTION]
1. [OPTION_1_LABEL] -- [OPTION_1_DESCRIPTION]
2. [OPTION_2_LABEL] -- [OPTION_2_DESCRIPTION]
...
Type the number of your choice:For multiSelect questions, instruct the user: "Type the numbers of your choices separated by commas (e.g., 1,3,5):"
Step 1: Load Context
takeToMarket > LOADING CONTEXTExtract SLUG from $ARGUMENTS (strip --text flag if present):
SLUG=$(echo "$ARGUMENTS" | sed 's/--text//g' | xargs)Read Tier 1 summaries from all 9 reference files (lines 1 to <!-- END_SUMMARY -->):
.taketomarket/POSITIONING.md.taketomarket/BRAND.md.taketomarket/ICP.md.taketomarket/CHANNELS.md.taketomarket/STATE.md(frontmatter only).taketomarket/CALENDAR.md.taketomarket/COMPETITORS.md.taketomarket/METRICS.md.taketomarket/LEARNINGS.md
Read Tier 2 (full content) for:
.taketomarket/ICP.md.taketomarket/CHANNELS.md.taketomarket/METRICS.md.taketomarket/CALENDAR.md
Read full .taketomarket/POSITIONING.md (needed for positioning check gate in Step 6).
Read campaign-specific files (always full-load per context-loading.md rule 4):
.taketomarket/CAMPAIGNS/${SLUG}/STATE.md.taketomarket/CAMPAIGNS/${SLUG}/RESEARCH.md
Step 2: Validate Campaign and Phase Order (per D-08)
Check campaign exists:
node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign state "${SLUG}" --rawIf result shows exists: false: Tell the user the campaign does not exist and suggest running /ttm-new-campaign first. Exit.
Read campaign state. Check the phase field:
- If phase is
"created": Warn the user — "Research not yet completed for this campaign. Brief quality will be limited without research data. Run/ttm-discover ${SLUG}first for better results. Proceed without research?" Wait for user confirmation. If user declines, exit. - If phase is NOT
"created"and NOT"researched": Warn the user — "Campaign is in phase${PHASE}. Expected 'researched' before briefing. Running /ttm-brief now will overwrite the existing BRIEF.md. Proceed?" Wait for user confirmation. If user declines, exit.
Check if RESEARCH.md has actual content (not just template placeholders):
- Read
.taketomarket/CAMPAIGNS/${SLUG}/RESEARCH.md - If file contains only
[GENERATED BY /ttm-discover]placeholders: setRESEARCH_AVAILABLE=false - If file has real content beyond placeholders: set
RESEARCH_AVAILABLE=true
Step 3: Outcome Metric Enforcement (per D-06, LIFE-04)
takeToMarket > GENERATING BRIEFCollect campaign goal:
Ask (freeform, NOT AskUserQuestion): "What is the goal of this campaign? (One sentence describing the campaign's purpose)" Store the response as CAMPAIGN_GOAL.
Collect outcome metric:
Ask (freeform): "What is the outcome metric for this campaign? An outcome metric measures a business result, not an output action.
Examples:
- VALID: 'Increase trial signups by 20% within 30 days'
- VALID: 'Generate 50 qualified leads from organic search in Q2'
- NOT VALID: 'Publish 4 blog posts' (this is an output, not an outcome)
What business outcome will this campaign drive?"
Validate the response:
- FAIL if metric starts with output verbs: publish, write, send, create, post, design, build, launch (without a measurable outcome attached)
- FAIL if no target value (number, percentage, or specific benchmark) is present
- FAIL if no measurement window (timeframe) is present
On FAIL (retry 1): Re-prompt with explanation: "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]"
On FAIL (retry 2): Re-prompt once more with different framing: "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?"
After 2 failed retries: Block brief generation entirely. Tell user: "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." Exit.
On PASS: Store as OUTCOME_METRIC. Extract target_value and measurement_window from the response.
Collect output metric:
Ask (freeform): "What are the output metrics? (Assets and volume to produce, e.g., '4 blog posts, 2 emails, 1 landing page')"
If the user provides an empty response or declines: set OUTPUT_METRIC_MISSING=true. Continue. This is allowed per D-06.
Step 4: Collect Remaining Brief Fields (per D-07)
ICP Segment:
Read the primary segment from .taketomarket/ICP.md Tier 1 summary. Present it to the user: "Your primary ICP segment is: [segment from ICP.md]. Is this correct for this campaign, or are you targeting a specific sub-segment?" Store the confirmed or adjusted segment as ICP_SEGMENT.
Channel Mix:
Read active channels from .taketomarket/CHANNELS.md.
Use AskUserQuestion (or text-mode numbered list) with multiSelect=true:
- header: "Channel Selection"
- question: "Which channels will this campaign use?"
- options: One option per active channel from CHANNELS.md
After selection, for each selected channel ask: "What is the role of [channel] in this campaign? (primary / support / amplification)" Store channel selections with roles as CHANNEL_MIX.
Hook:
If RESEARCH_AVAILABLE=true: Present key findings from RESEARCH.md (ambient narrative, content gaps) and suggest hook angles based on them. Ask: "What is the opening angle or attention-capture strategy for this campaign?" Store as HOOK.
Proof Points:
Read proof points from .taketomarket/POSITIONING.md Proof Point Library table. Display the available proof points. Ask: "These are your approved proof points. Do you want to add any campaign-specific claims or evidence?" Store base proof points plus any additions as PROOF_POINTS.
Timeline:
Ask: "What is the target ship date for this campaign?" Derive remaining timeline dates backward from the ship date:
- Brief complete: today
- Production start: ship date minus appropriate buffer
- Review complete: ship date minus review buffer
- Measurement start: ship date
- Learn review: ship date + measurement window
Store as TIMELINE.
Success Criteria:
Ask: "What specific, measurable outcomes define success for this campaign beyond the outcome metric?" Store as SUCCESS_CRITERIA.
Failure Criteria:
Ask: "What conditions should trigger a campaign pause or kill?" Store as FAILURE_CRITERIA.
Step 5: Generate BRIEF.md
Read the brief template:
${CLAUDE_PLUGIN_ROOT}/templates/campaign-brief.mdFill ALL [GENERATED BY /ttm-brief] placeholders with collected data:
- Campaign Name: From campaign STATE.md
namefield - Goal: From
CAMPAIGN_GOAL - Outcome Metric section: Metric:
OUTCOME_METRIC; Target value: extractedtarget_value; Measurement window: extractedmeasurement_window; Data source: inferred from metric type or ask user - Output Metric section: From output metrics collected in Step 3. If
OUTPUT_METRIC_MISSING=true, insert after the Output Metric section:<!-- OUTPUT_METRIC_MISSING: Add output metrics before /ttm-produce --> - ICP Segment: From
ICP_SEGMENT(Step 4) - Positioning Anchor: Key message: derived from POSITIONING.md primary differentiator, adapted for campaign; Primary differentiator: quoted directly from POSITIONING.md
- Hook: From
HOOK(Step 4) - Proof Points table: From
PROOF_POINTS— POSITIONING.md proof library + campaign additions - Channel Mix table: From
CHANNEL_MIXwith roles (Step 4) - Assets List table: Derived from output metrics + channel mix
- Success Criteria: From
SUCCESS_CRITERIA(Step 4) - Failure Criteria: From
FAILURE_CRITERIA(Step 4) - Dependencies: Inferred from campaign context (reference files, tools, approvals needed)
- Timeline table: From
TIMELINE(Step 4)
Store the generated content as BRIEF_CONTENT.
Step 6: Positioning Check Gate (per D-05, LIFE-05)
takeToMarket > POSITIONING CHECKRead the positioning check rules from @${CLAUDE_PLUGIN_ROOT}/workflows/lifecycle/brief-positioning-check.md.
Apply all 5 checks against BRIEF_CONTENT:
- Positioning Anchor Alignment: Compare brief's "Positioning Anchor > Key message" against POSITIONING.md primary differentiator phrase. Determine PASS/WARN/FAIL.
- ICP Segment Match: Compare brief's "ICP Segment > Primary segment" against POSITIONING.md target audience. Determine PASS/WARN/FAIL.
- Proof Point Sourcing: Check each proof point in the brief against POSITIONING.md proof point library. Determine PASS/WARN/FAIL.
- Must-Not-Say Terms: Scan entire brief content for any terms from POSITIONING.md must-not-say list. Determine PASS/FAIL.
- Hook-Positioning Coherence: Compare brief's hook against POSITIONING.md primary differentiator and category. Determine PASS/WARN/FAIL.
Determine gate result:
- If ALL checks PASS: gate result =
"pass" - If ANY check is WARN or FAIL: gate result =
"warn"
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:
<!--
!! POSITIONING DRIFT WARNING !!
The following items may not align with your positioning:
- [drift detail from each failing check, using format strings from brief-positioning-check.md]
Review .taketomarket/POSITIONING.md and adjust the brief if needed.
Run /ttm-positioning-check for a full audit.
-->The brief is written unconditionally. NEVER block brief generation on positioning drift (per D-05).
Step 7: Write BRIEF.md and Update State
Write BRIEF_CONTENT to .taketomarket/CAMPAIGNS/${SLUG}/BRIEF.md.
Update campaign state:
node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" phase briefed
TIMESTAMP=$(node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" timestamp --raw)
if [ -z "$TIMESTAMP" ]; then
echo "Error: could not get timestamp"; exit 1
fi
node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" phase.briefed "$TIMESTAMP"
node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" gate.outcome_metric pass
node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign update "${SLUG}" gate.positioning_check [pass|warn]Replace [pass|warn] with the actual gate result from Step 6.
Step 8: Display Summary
takeToMarket > BRIEF COMPLETE
Brief saved to .taketomarket/CAMPAIGNS/${SLUG}/BRIEF.md
Outcome metric: [OUTCOME_METRIC]
Positioning check: [pass|warn]
Output metric: [defined|MISSING -- add before /ttm-produce]
Channels: [list of selected channels]
Assets: [count] planned
[If positioning_check=warn:]
!! Positioning drift detected -- see warning in BRIEF.md
Review .taketomarket/POSITIONING.md and adjust if needed.
Next: Run /ttm-produce ${SLUG}Success criteria
- Context loaded (Tier 1 all files, Tier 2 ICP/CHANNELS/METRICS/CALENDAR, full POSITIONING.md)
- Campaign validated and phase order checked (D-08)
- Outcome metric enforced — valid business outcome with target value and measurement window (D-06, LIFE-04)
- Output metric collected or flagged as missing (D-06)
- All mandatory brief fields present in generated BRIEF.md (D-07)
- Positioning check gate executed with all 5 checks from brief-positioning-check.md (D-05, LIFE-05)
- BRIEF.md written unconditionally — never blocked by positioning drift (D-05)
- Campaign state updated: phase=briefed, gate.outcome_metric, gate.positioning_check
- OUTPUT_METRIC_MISSING flag visible in BRIEF.md when applicable
Output
.taketomarket/CAMPAIGNS/<slug>/BRIEF.md(populated with all mandatory fields)
What if this doesn't fit?
Looks like /ttm-brief can't do that yet.
- Want a new skill?
/ttm-request-skill - Existing skill needs work?
/ttm-improve-skill