Rishikesh Ranjan — rishikeshranjan.com

// 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.

phase 2manual invocation
allowed-tools:ReadWriteBashGlobGrepAskUserQuestion

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-brief

Use 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; fi

If 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 CONTEXT

Extract 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}" --raw

If 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: set RESEARCH_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 BRIEF

Collect 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.md

Fill ALL [GENERATED BY /ttm-brief] placeholders with collected data:

  • Campaign Name: From campaign STATE.md name field
  • Goal: From CAMPAIGN_GOAL
  • Outcome Metric section: Metric: OUTCOME_METRIC; Target value: extracted target_value; Measurement window: extracted measurement_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_MIX with 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 CHECK

Read the positioning check rules from @${CLAUDE_PLUGIN_ROOT}/workflows/lifecycle/brief-positioning-check.md.

Apply all 5 checks against BRIEF_CONTENT:

  1. Positioning Anchor Alignment: Compare brief's "Positioning Anchor > Key message" against POSITIONING.md primary differentiator phrase. Determine PASS/WARN/FAIL.
  2. ICP Segment Match: Compare brief's "ICP Segment > Primary segment" against POSITIONING.md target audience. Determine PASS/WARN/FAIL.
  3. Proof Point Sourcing: Check each proof point in the brief against POSITIONING.md proof point library. Determine PASS/WARN/FAIL.
  4. Must-Not-Say Terms: Scan entire brief content for any terms from POSITIONING.md must-not-say list. Determine PASS/FAIL.
  5. 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