# Frontrun

> Turns raw market voice (reviews, comments, support tickets, sales notes, posts, transcripts) into source-backed marketing briefs. Sequences five specialists with explicit gates and graceful degradation so every claim traces to a real sentence someone said. The operator stays the editor. Triggers on: frontrun, run frontrun, mine my market voice, turn reviews into angles, voice of customer briefs, source-backed positioning, what is my market actually saying, extract angles from comments, where is my category moving.

- Skill: `themattberman/frontrun` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add themattberman/frontrun`
- Raw SKILL.md: https://api.skillmd.com/api/skills/themattberman/frontrun/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: TheMattBerman (https://skillmd.com/u/themattberman)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/themattberman/frontrun

---


# Frontrun

raw market language in. sharp positioning angles out.

this is the orchestrator. it sequences five specialists, holds the gates, and degrades gracefully when the pool is thin or a source type is missing. it never inlines specialist logic. each specialist does exactly one job and is independently invocable.

the villain it attacks: AI writing from the training-data average instead of from what the market is actually saying right now. medium is the enemy of good. the kit's job is to stop the guessing and make the agent listen first.

what it is not:
-> not social listening. social listening gives dashboards. this gives briefs.
-> not a VOC summarizer. it refuses to flatten "double-books room 3" into "scheduling concerns."
-> not a scraper. it ingests voice, it does not collect it.
-> not the decision-maker. the agent mines and surfaces. the human picks what is real and on-brand.

## When to use

use this skill when the operator has raw market voice (a CSV, or a folder of `.md`/`.txt` files) and wants it turned into a ranked angle slate plus action briefs, each with receipts.

do not use this orchestrator when:
-> the operator wants to ingest and index sources only: route to `source-intake`.
-> the operator already has an indexed corpus and wants evidence cards plus a voice map: route to `voice-extractor`.
-> the operator wants objections mapped from an existing card set: route to `objection-mapper`.
-> the operator wants the scored angle slate from existing cards: route to `angle-synthesizer`.
-> the operator wants briefs forged from an existing slate: route to `brief-forge`.

the orchestrator's only job is sequencing, gating, and degradation. when a stage needs work done, it invokes the specialist that owns that stage. it does not do that specialist's job itself.

## Dependencies

the run packet is defined once in `references/run-contract.md`. this table does not redefine it. it maps each specialist to its role and the artifacts it owns.

| Specialist | Role | Output files it owns |
|---|---|---|
| `source-intake` | ingests the CSV/folder, normalizes, indexes, computes corpus sufficiency | `00-intake.md`, `00b-scope-contract.md`, `01-source-index.md`, `raw/` |
| `voice-extractor` | reads `raw/` plus the source index, emits the atomic evidence cards and the forward voice map | `02-evidence-cards.json`, `03-voice-map.md` |
| `objection-mapper` | reads the cards, emits the defensive objection map (what to answer) | `04-objection-map.md` |
| `angle-synthesizer` | scores and ranks opportunities into the slate, only `direct_quote`/`strong_inference` items | `06-angle-slate.md` |
| `brief-forge` | forges the one-shot action briefs and the serial watchlist | `07-brief-pack.md`, `08-watchlist.md` |

competitor and creator maps (`04b-competitor-map.md`, `05-creator-map.md`) are conditional stages owned by the specialists closest to them: the competitor map is produced as part of objection/angle work using the competitor fields in the cards, and the creator map is produced from creator-voice cards. both are gated on the corpus actually containing those source types (see degradation).

## Stages

confirm the base path before any write. confirm scope at intake. get human approval before the angle slate is finalized. those three gates are non-negotiable.

### Stage 0: Intake and scope

confirm the run base path with the operator. runs are written to the current working directory, never inside the kit install dir:

```
frontrun-runs/YYYY-MM-DD-<market-slug>/
```

GATE (base path): do not write a single file until the operator confirms this resolved path. `<market-slug>` is lowercase, hyphenated, `@` dropped from handles.

ask the operator for scope: market/category, business type (`saas`/`dtc`/`other`), known competitors, the source types they are bringing, the audience, and the goal of this run.

GATE (scope): read the confirmed scope back to the operator before proceeding. scope decided here is captured at import time and never re-guessed later.

### Stage 1: source-intake

invoke `source-intake`. it runs `scripts/normalize_sources.py` on the operator's CSV/folder, populates `raw/`, and writes `00-intake.md`, `00b-scope-contract.md`, and `01-source-index.md`. it captures `speaker_type` and `source_type` at import, never inferred downstream. it computes `thin_pool` in `00b-scope-contract.md`.

wait for source-intake to return before the next stage. read `00b-scope-contract.md` to learn `thin_pool` and which source types are present. those two facts drive every degradation decision below.

### Stage 2: voice-extractor

invoke `voice-extractor`, passing the path to `01-source-index.md` and `raw/`. it emits `02-evidence-cards.json` (validating against `voice-evidence-card.schema.json`, verbatim kept separate from interpretation, one confidence label per card, the `diffusing` flag when a phrase appears in both user voice and creator voice) and `03-voice-map.md` (FORWARD: desires, myths, enemy beliefs, buying language, emotional language).

wait for it to return. the cards are now the spine. everything downstream cites `evidence_id`s.

### Stage 3: objection-mapper

invoke `objection-mapper`, passing `02-evidence-cards.json`. it emits `04-objection-map.md` (DEFENSIVE: objections, anxieties, workarounds, trust gaps, trigger events). hold the boundary: voice-map is what to say, objection-map is what to answer. never write the same cluster twice.

### Stage 4 (conditional): competitor map

if the corpus contains competitor-labeled or competitor-themed cards, produce `04b-competitor-map.md`: per competitor `known_for`, `frustration_points`, `claim_they_own`, `where_not_to_attack`, `wedge`, `switch_trigger`. "do not attack their genuine strength" is the load-bearing field.

DEGRADATION: no competitor signal in the corpus -> skip `04b-competitor-map.md`. record the skip and the reason in the manifest `stages` array as `status: skipped`.

### Stage 5 (conditional): creator map

if the corpus contains creator-voice cards (`voice_layer: creator`), produce `05-creator-map.md`: per creator `lane`, `audience_fit`, `amplified_language`, `hooks_formats`, `recommendation` (`pitch`/`mine_for_hooks`/`watch`/`ignore`), and a one-line `reason` per recommendation (never a bare tag). a creator may carry two tags.

DEGRADATION: no creator sources -> skip `05-creator-map.md`, and note the skip in the manifest `stages` array as `status: skipped`. the run still completes. creator voice is a leading indicator, not a requirement.

### Stage 6: angle-synthesizer

invoke `angle-synthesizer`, passing `02-evidence-cards.json` (plus `04b` and `05` if present). it scores each candidate on the six dimensions, applies the usefulness multiplier and the hard promotion gate, and writes `06-angle-slate.md`. only `direct_quote` and `strong_inference` items reach the slate. `weak_pattern` and `do_not_use_yet` are barred here and routed to the watchlist.

DEGRADATION: if `thin_pool == true`, cap the slate at 3 angles and require the `corpus_limitation_note` from `00b-scope-contract.md` to be surfaced at the top of the slate. never launder comment noise into survey math.

GATE (human approval): present the ranked slate to the operator. do not finalize `06-angle-slate.md` or proceed to brief-forge until the operator confirms which angles are real and on-brand. the operator stays the editor. the operator may cut, reorder, or send an angle back for re-scoring.

### Stage 7: brief-forge

invoke `brief-forge`, passing the approved slate and the cards. it forges the one-shot action briefs into `07-brief-pack.md` (ad / landing-page / SEO / competitor-positioning / creator-partnership / product-messaging, plus the category-watchlist brief). every brief ends in an `operator_action` with at least one `source_receipts` entry and a `what_we_would_NOT_say` list of length >= 2.

### Stage 8: watchlist

still within brief-forge's remit, write `08-watchlist.md`: the serial artifact. rising phrases with `delta_vs_last_run`, creators framing the category, and noise to ignore. this is the only time-delta artifact and the reason to re-run next week. if a prior run exists in the base path, diff against it.

### Stage 9: manifest

write `run-manifest.json` (validates against `run-manifest.schema.json`). recompute every count and distribution from disk: `source_count`, `evidence_count`, `confidence_distribution`, `source_type_distribution`, `thin_pool`, `angle_count`, the `files` present/missing map, the `stages` array (each specialist with `status` complete/skipped/degraded/failed and its `output`), and `validation_status`. the manifest must agree with what is actually on disk. if `validate_run.py` is available, run it and record the result; otherwise stamp `validation_status: not_run`.

report the run folder path and a short summary: sources indexed, evidence cards by confidence, which conditional maps ran or were skipped, angle count (and whether capped by thin pool), briefs forged, and what the run could not establish.

## Graceful degradation summary

| Condition | Effect |
|---|---|
| no creator sources | skip `05-creator-map.md`, mark `stages[].status: skipped` |
| no competitor signal | skip `04b-competitor-map.md`, mark `stages[].status: skipped` |
| `thin_pool == true` | cap `06-angle-slate.md` at 3 angles, surface `corpus_limitation_note`, mark angle stage `degraded` |
| a stage fails | mark `stages[].status: failed` in the manifest, report it plainly, do not fabricate the missing artifact |
| `validate_run.py` absent | stamp `validation_status: not_run`, still emit the manifest |

honest limits are the credibility engine. always end a run with what it could not establish, not just what it found.

## References

- `references/run-contract.md`: the run-folder contract and the load-bearing traceability rule. the packet is defined there. point to it, never redefine it.
- `references/scoring-rubric.md`: the six-dimension opportunity scorecard, the usefulness multiplier, the hard promotion gate, the diffusing flag, and the four confidence labels.
- `references/anti-patterns.md`: the anti-generic rules, most enforced as required schema fields, the rest held by judgment. banned-phrase list and the honest-limits doctrine.

