Synced from virality/SKILL.md in content-extraction skill on 2026-05-18. Edit upstream in the skill; this file is overwritten on next sync.

A Friend — Virality Sub-Agent (multi-stage)

Sub-orchestrator inside afriend-content-extraction. Three stages: source-analysis (S1) → candidates (S2) → refinement-loop (S3). Each stage writes a decision-ready markdown artifact Daniel reviews BEFORE cuts execute. Does NOT auto-merge into cut-plan.json.

The single-essay virality-pass.md format from earlier iterations was rejected — too verbose, un-actionable. This skill replaces it with a thin router pointing to three operational stage files. Each stage’s output is short, scannable, and feeds the next stage cleanly.

Architecture (3 stages, one entrypoint)

parent skill Mode 1/2/3 extraction
        │
        ▼
   ┌────────┐    transcript.txt + transcript-words.json + silence-map.json
   │   S1   │  ──────────────────────────────────────────────────────────►  source-analysis.md
   │ source │
   │ analy- │    (≤150 lines, flat inventory, NO scoring)
   │  sis   │
   └────────┘
        │
        ▼
   ┌────────┐    S1 output + brand pack + virality canon
   │   S2   │  ──────────────────────────────────────────────────────────►  candidates.md
   │  can-  │
   │didates │    (5-7 equal-tier candidates, ~250 line cap, decision-ready)
   └────────┘
        │
        ▼
   Daniel reads candidates.md, runs:  /afriend-content-extraction --pick C-XX,C-YY
        │
        ▼
   ┌────────┐    selected candidate(s)
   │   S3   │  ──────────────────────────────────────────────────────────►  cut-plan.json (draft)
   │ refine-│
   │  ment  │    composes via Phase 1: silence-tighten → preview gate → --expand-pre/post recovery
   └────────┘    iterate ~5s round-trip until happy → --approve → out/clips/

Each stage’s full spec lives in virality/stages/. This file is the router — it tells the parent skill WHEN each stage runs, points to the stage file for HOW.

Stage files

  • virality/stages/01-source-analysis.md — S1 spec: inventory format, tag legend, silence-map summary, tail-30s candidates auto-flag
  • virality/stages/02-candidates.md — S2 spec: diversity rubric, per-candidate field schema, equal-tier rule, hard gates
  • virality/stages/03-refinement.md — S3 spec: —pick command parsing, beat# → segments mapping, draft-cut-plan composition

When invoked

Strong triggers (auto-activated as parent Step 4d.5):

  • Parent skill in Mode 1/2/3 (post-recording extraction).
  • transcript.txt + transcript-words.json + silence-map.json exist in session folder.
  • Parent reached Step 4c (build arcs) — virality runs after this, before Step 4f (Schwartzberg).

Manual triggers:

  • Daniel: “run virality on this”, “give me candidates”, “kürzer, schärfer”, “this is too long”
  • Daniel: /afriend-content-extraction --candidates-only for re-running S1+S2 on existing session
  • Daniel: /afriend-content-extraction --pick C-XX after reviewing candidates.md

If unsure: ask once “Virality candidates auf source?” — then proceed.

What this sub-agent does (and doesn’t do)

DOES:

  1. S1: Surfaces what’s IN source. Pure inventory. Beat# table (start/end/duration/quote-prefix/pillar-tag/beat-type-tag/source-position). NO scoring, NO opinions.
  2. S2: Generates 5-7 candidate clips. Equal-tier (no ranking). Spread across pillars / duration bands / arc shapes / format-fits.
  3. S3: Composes draft cut-plan from picks. Beat# refs resolve to segments verbatim. Phase 1 silence-tighten + preview-gate + recovery flags compose downstream.

Does NOT:

  • Auto-merge into cut-plan.json. Daniel decides; parent skill writes via —pick.
  • Synthesize new lines. Every quote verbatim from transcript.txt. Sub-agent only re-orders existing beats.
  • Rank candidates. Equal-tier. Diversity surfaces options; Daniel picks.
  • Run cuts. Cuts execute via Phase 1 cut_with_ffmpeg.py AFTER —pick + tighten + preview.
  • Smooth Daniel’s cadence. Verbatim contract is hard rule.
  • Generate B-roll cues. Parent skill’s job (Step 5).

Where this sub-agent runs in parent workflow

Mode 3 (video-only) workflow:

  Step 0  — Ingest (session folder, source.mp4)
  Step 1  — Whisper word-level (transcript-words.json)
  Step 2  — Brand pack refresh
  Step 3  — Read transcript + rank scroll-stoppers (informational)
  Step 4  — silence_detect.py (silence-map.json)         ← MOVED here from old Step 5.5
  Step 4d.5a — VIRALITY S1 (source-analysis.md)          ← THIS SUB-ORCHESTRATOR
  Step 4d.5b — VIRALITY S2 (candidates.md)               ← THIS SUB-ORCHESTRATOR
  Step 4d.5c — wait for Daniel's --pick                  ← interactive gate
  Step 4d.5d — VIRALITY S3 composes draft cut-plan       ← THIS SUB-ORCHESTRATOR
  Step 5  — Phase 1: silence_to_cutplan.py --mode tighten
  Step 6  — Phase 1: cut_with_ffmpeg.py --propose (preview)
  Step 7  — Daniel reviews proposal/, optionally --expand-pre/post
  Step 8  — cut_with_ffmpeg.py --approve → out/clips/

Silence-detect now runs BEFORE virality (S1 needs silence-map for inventory). Order is fixed.

Hard gates (enforced before any output reaches Daniel)

These apply to S1 + S2 output. S3 inherits from cut-plan.json schema validation.

  1. Verbatim: every quote in S1 inventory + S2 candidates is verbatim substring of transcript.txt (whitespace-tolerant).
  2. No synthesis: sub-agent CANNOT generate new lines. Only re-order existing beats.
  3. No banned vocab in surface text: titles, framing, sub-agent commentary. Banned: revolutionize, seamless, AI-powered, game-changer, leverage, exclamation points anywhere.
  4. Two-beat cadence preserved: if a proposed re-arc breaks Daniel’s natural two-beat structure, flag with CADENCE-BREAK warning.
  5. Code-switching preserved: German/English mix in any verbatim quote stays exactly as Daniel said it.
  6. Tail-of-source search required: S1 MUST flag tail-30s candidates explicitly. S2 MUST consider them — at least 1 candidate per candidates.md should lead with a tail-source beat (Rule A enforcement).
  7. Daniel’s 5-test gate is final: sub-agent’s candidate doesn’t bypass Daniel’s “feels like me” check. Sub-agent proposes; Daniel disposes.

Any hard-gate failure auto-injects the named tag (e.g. BRAND-NONNEGOTIABLE-VIOLATION, CADENCE-BREAK) inside the affected stage’s output rather than silently emitting. Daniel sees what failed and why.

Knowledge canon (read at runtime by sub-agent)

The sub-agent operates against a fixed canon. New knowledge gets added to references/, never to virality/SKILL.md.

FileOwns
references/shortform-virality.mdParent rubric (Tier-1/2/3, hook archetypes, Schwartzberg three-test, retention floors)
references/attention-preservation.mdTemporal mechanics (second-hook landing window 12-18s, loopability, rewatch triggers, micro-cliffhangers, anti-brain-rot)
references/essence-extraction-framework.mdSchärfung / Trim / Essenz operational framework. Compression math. Kernel test.
references/aesthetic-register-anti-slick.md7-axis register (punchy/sharp/real/essence-loaded/considered/perceptive/illuminated) + anti-pattern detection (motivational-speaker, hustle-bro, productivity-influencer, TED-pacing, brain-rot)
_brand/pillars.md7 pillars + per-pillar trigger/anti-pattern
_brand/voice-preservation.mdBanned vocab, two-beat cadence, code-switching, tool-naming rule, “feels like me” gate
_brand/campaign-state.mdWhat’s been shipped, anti-duplication awareness

Failure modes + mitigations

FailureDetectionMitigation
Sub-agent picks wrong arcsDaniel rejects all candidatesRe-run S2 with different diversity dimensions surfaced. Log rejection in refinement-log.md to tune sub-agent bias.
Sub-agent over-trims at chunk boundariesDaniel listens to preview, hears jam-cut—expand-pre/—expand-post per Phase 1 recovery (~5s iteration).
Aesthetic register false-positive7-axis flags real Daniel as “slick”Surfaces ⚠ not ✗; two ⚠ = warning, not block. Daniel decides.
Verbatim drift in S2 surface textHard gate: every quote is substring of transcript.txtBlock emission, surface BRAND-NONNEGOTIABLE-VIOLATION tag.
Same arc shape across all candidatesS2 diversity rule requires ≥3 dimensionsSub-agent forced to spread; if source genuinely homogeneous, surfaces note explaining why <5 candidates emit.
Manual override pathDaniel always wants final say—pick selects which candidates compose into cut-plan; un-picked ones discarded. Sub-agent never writes cut-plan.json directly.

Refinement protocol

When Daniel rejects a candidate:

  1. Note in refinement-log.md — what was rejected, why.
  2. Look for pattern across rejections — same diversity dimension repeatedly weak?
  3. Tune in this SKILL.md or in the relevant stage file (stages/01-source-analysis.md, stages/02-candidates.md, stages/03-refinement.md).

When Daniel picks a candidate that produces a strong-shipped clip:

  1. Note in refinement-log.md — what was picked, what made it work.
  2. Surface positive pattern to relevant reference canon.

The sub-agent’s quality compounds with iterations. Each session feeds the next session’s bias.