// reference management
Positioning Check
/ttm-positioning-check
Sample recent assets and report positioning drift percentage, types, and bleeding analysis. Auto-triggers when potential positioning drift is detected.
Overview
ttm-positioning-check audits a campaign's brief and assets against the positioning invariant declared in POSITIONING.md. It samples recent campaign assets across all active campaigns within a configurable time window (default 30 days), compares each asset to the positioning invariant, calculates a positioning drift percentage, categorizes the drift types, and performs a bleeding analysis (where positioning leaks into the wrong territory).
The output is a drift report: which claims diverge, by how much, and whether the drift is small enough to correct in place or large enough to require a positioning shift. Positioning drift is the single most common cause of inconsistent marketing across a year, so this skill acts as the linter for it. Run it after producing if anything feels off, and run it before shipping a campaign that hits a new channel or audience.
Invoke it with ttm-positioning-check. It auto-triggers when potential positioning drift is detected, and can also be auto-suggested by the ship workflow after every 3rd campaign ships since the last audit. Each run reports findings with three options: Correct, Accept + log, or Escalate to a positioning shift.
How it works
This skill follows the workflow at ${CLAUDE_PLUGIN_ROOT}/workflows/reference-mgmt/positioning-check.md. It is a positioning drift audit workflow: it samples recent assets across all campaigns within a configurable time window, evaluates each against the GATE-01 positioning drift checks, generates a structured audit report, and appends the results to .taketomarket/DRIFT-LOG.md.
Required reading for the workflow: ${CLAUDE_PLUGIN_ROOT}/references/context-loading.md, ${CLAUDE_PLUGIN_ROOT}/gates/gate-evaluation.md, and ${CLAUDE_PLUGIN_ROOT}/references/positioning-check-report.md.
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-positioning-check 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-positioning-checkUse this exact check (bash) to decide whether to print: node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" first-run check ttm-positioning-check --raw -- the JSON seen field is true once the explainer has run before.
Explainer for /ttm-positioning-check
/ttm-positioning-checkaudits a campaign's brief and assets against the positioning invariant declared in POSITIONING.md. Output is a drift report: which claims diverge, by how much, and whether the drift is small enough to correct in-place or large enough to require a positioning shift.Why it matters: positioning drift is the single most common cause of inconsistent marketing across a year. This skill is the linter for that -- run it after producing if anything feels off, and absolutely run it before shipping a campaign that hits a new channel or audience.
(Canonical source: references/inline-education-blurbs.md. Embedded verbatim because workflows do not @-resolve files at runtime.)
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 the 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:Step 1: Load context
takeToMarket > LOADING CONTEXT FOR POSITIONING AUDITLoad 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
Load Tier 2 (full content) for drift evaluation:
.taketomarket/POSITIONING.md(needed for all 3 GATE-01 checks)
If .taketomarket/POSITIONING.md does not exist: Error: "No POSITIONING.md found. Run /ttm-init first to set up your marketing workspace." Exit.
Step 2: Parse time window
Parse optional --since argument from $ARGUMENTS. Default: 30d (per D-01).
WINDOW=$(echo "$ARGUMENTS" | grep -oP '(?<=--since\s)\S+' || echo "30d")Extract number and unit:
- Format:
Ndwhere N is a number and d = days - Example:
30d= last 30 days,90d= last 90 days,7d= last 7 days - Calculate cutoff date from current date minus N days
Display:
takeToMarket > AUDIT WINDOW: last ${WINDOW}Step 3: Enumerate campaigns and assets
takeToMarket > ENUMERATING CAMPAIGNSRun campaign enumeration via CLI:
CAMPAIGNS_JSON=$(node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" campaign list --since ${WINDOW} --raw)Parse the JSON result. Expected format: { "campaigns": [...], "count": N }. If count is 0:
takeToMarket > NO CAMPAIGNS FOUND
No campaigns with assets in the last ${WINDOW}. Nothing to audit.Exit. Per Pitfall 2: the CLI already excludes archived campaigns from the results.
For each campaign in the result:
- Read the campaign's ASSETS/ directory:
- Glob:
.taketomarket/CAMPAIGNS/${SLUG}/ASSETS/*
- Glob:
- Collect all asset files found
- Also read
.taketomarket/CAMPAIGNS/${SLUG}/DEVIATIONS.mdif it exists- Filter for rows where Gate =
positioning_drift(GATE-01 deviations per D-13) - Store these as accepted deviations for the cross-reference section
- Filter for rows where Gate =
Display:
takeToMarket > FOUND ${ASSET_COUNT} assets across ${CAMPAIGN_COUNT} campaignsStep 4: Evaluate each asset against GATE-01
takeToMarket > EVALUATING POSITIONING DRIFTFor each collected asset:
- Read the full asset content from disk.
- Evaluate against GATE-01's 3 checks (from
@gate-evaluation.md), described below. - Record per-check result: PASS / WARN / FAIL with evidence.
- Calculate per-asset drift %: (WARN count + FAIL count) / 3 * 100.
Check 1: Differentiator Alignment
Does the asset restate or naturally extend the primary differentiator from POSITIONING.md? Or does it introduce a different claim?
- PASS: Asset reinforces the primary differentiator
- WARN: Asset is neutral -- neither reinforces nor contradicts
- FAIL: Asset introduces a different/competing claim
Check 2: Proof Point Sourcing
Are all factual claims in the asset backed by proof points in the POSITIONING.md proof point library?
- PASS: All claims backed by POSITIONING.md proof points
- WARN: Some claims present but not all sourced
- FAIL: Claims contradict or fabricate proof points
Check 3: Must-Not-Say Compliance
Does the asset contain any terms from the POSITIONING.md must-not-say list?
- PASS: No must-not-say terms found
- WARN: Terms appear in non-customer-facing context
- FAIL: Must-not-say terms in customer-facing copy
Display progress for each asset:
[${INDEX}/${TOTAL}] ${ASSET_NAME} (${CAMPAIGN_SLUG}): ${DRIFT_PCT}% driftStep 5: Calculate aggregates
After evaluating all assets:
- Total assets evaluated: count of all sampled assets
- Aggregate drift %: total (WARN + FAIL results) / (total assets * 3) * 100
- Count by drift category:
- Differentiator Alignment: count of WARN + FAIL on Check 1 across all assets
- Proof Point Sourcing: count of WARN + FAIL on Check 2 across all assets
- Must-Not-Say Violations: count of WARN + FAIL on Check 3 across all assets
- Cross-reference accepted deviations from DEVIATIONS.md files collected in Step 3 (per D-13)
Step 5b: Bleeding analysis
takeToMarket > ANALYZING MUST-NOT-SAY BLEEDINGFrom the per-asset evaluation results collected in Step 4, extract all assets where Check 3 (Must-Not-Say Compliance) returned WARN or FAIL. For each must-not-say violation:
- Classify the asset as customer-facing or non-customer-facing:
- Customer-facing: landing pages, blog posts, ad copy, social posts, email campaigns, any asset intended for external audience consumption
- Non-customer-facing: internal briefs, research docs, planning notes, strategy docs
- When ambiguous, classify as customer-facing (conservative default per
@positioning-check-report.mdBleeding Analysis rules)
- Determine bleeding status:
- Check 3 = FAIL (customer-facing asset): Mark as BLEEDING (Critical)
- Check 3 = WARN (non-customer-facing asset): Mark as NOT BLEEDING (Advisory)
- Extract the specific must-not-say term and surrounding context (10 words before and after the term occurrence) for inclusion in the Bleeding Analysis report section.
Calculate bleeding metrics:
- BLEEDING_COUNT: Number of assets with Check 3 = FAIL (customer-facing violations)
- MNS_VIOLATION_COUNT: Total assets with Check 3 = WARN or FAIL
- BLEEDING_RATE: BLEEDING_COUNT / MNS_VIOLATION_COUNT * 100 (0% if no violations)
Display:
Bleeding: ${BLEEDING_COUNT} of ${MNS_VIOLATION_COUNT} must-not-say violations in customer-facing materialsThese values feed into the Bleeding Analysis section of the report generated in Step 7.
Step 6: Trend comparison
Read .taketomarket/DRIFT-LOG.md. Find the most recent entry with Event = audit.
If a prior audit entry exists (per D-03):
- Parse the Details column to extract the prior aggregate drift percentage
- Expected format:
"Nd audit: X% drift, Y findings across Z assets" - Extract X as the prior drift percentage
- Expected format:
- Calculate delta: current aggregate drift % - prior aggregate drift %
- Determine trend:
- Delta > +5%: UP (drift increasing -- positioning adherence worsening)
- Delta < -5%: DOWN (drift decreasing -- positioning adherence improving)
- Delta between -5% and +5%: STABLE (no significant change)
- Set TREND_ARROW and TREND_DETAIL for the report
If no prior audit entry exists:
- Set TREND_ARROW = ""
- Set TREND_DETAIL = "First audit -- no trend data available."
Step 7: Generate report
Follow the report format from @positioning-check-report.md. Generate the full audit report including:
- Header with audit window and asset count
- Aggregate drift percentage with trend arrow
- Per-asset results table (asset x check matrix with drift %)
- Drift type breakdown (count per category)
- Bleeding analysis (must-not-say violations classified by asset type with bleeding count and rate)
- Findings detail for every WARN and FAIL result
- Accepted deviations cross-reference
- Trend comparison (if prior audit exists)
- Recommendations based on aggregate drift thresholds
Display the report to stdout (per A1 -- this is a cross-campaign audit, not scoped to a single campaign directory).
Step 8: Log to DRIFT-LOG.md
Append the audit results to .taketomarket/DRIFT-LOG.md via CLI:
node "${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs" drift-log append \
--event-type audit \
--source "/ttm-positioning-check" \
--details "${WINDOW} audit: ${AGGREGATE_DRIFT}% drift, ${DRIFT_COUNT} findings across ${ASSET_COUNT} assets" \
--affected ${ASSET_COUNT}Display:
takeToMarket > AUDIT LOGGED TO .taketomarket/DRIFT-LOG.mdStep 9: Completion banner
========================================
takeToMarket > POSITIONING AUDIT COMPLETE
========================================
Window: last ${WINDOW} | Assets audited: ${ASSET_COUNT}
Aggregate drift: ${AGGREGATE_DRIFT}% ${TREND_ARROW}
Campaigns covered: ${CAMPAIGN_COUNT}
Drift logged to: .taketomarket/DRIFT-LOG.md
Next steps:
- Run /ttm-fix [campaign-slug] to address specific FAIL results
- Run /ttm-positioning-shift if aggregate drift > 30% warrants a positioning changeSuccess criteria
- All assets from campaigns within the time window evaluated against GATE-01's 3 checks
- Per-asset drift percentage calculated (WARN+FAIL / 3 * 100)
- Aggregate drift percentage calculated across all sampled assets
- Drift categorized by type (differentiator, proof point, must-not-say)
- Bleeding analysis classifies must-not-say violations by asset type (customer-facing vs non-customer-facing)
- Accepted deviations cross-referenced from campaign DEVIATIONS.md files
- Trend comparison shown if a prior audit exists in DRIFT-LOG.md
- Report displayed to stdout in the standard format
- Audit results appended to DRIFT-LOG.md via CLI
- Recommendations provided based on aggregate drift thresholds
Output
- Audit report displayed to stdout (cross-campaign, no file written)
.taketomarket/DRIFT-LOG.mdupdated with audit entry via CLI
The workflow steps that enumerate campaigns, append to the drift log, and check first-run state are backed by the bundled script ${CLAUDE_PLUGIN_ROOT}/bin/ttm-tools.cjs.
What if this doesn't fit?
Looks like /ttm-positioning-check can't do that yet.
- Want a new skill?
/ttm-request-skill - Existing skill needs work?
/ttm-improve-skill