The script pipeline
A script goes from a topic to a hand-off in eleven stages, S0 to S11. Research comes first (S1 to S3), then the thesis and the declared structure (S4, S5), then the draft with the hook written last (S6), two passes over it (S7), a gate loop run by one command (S8), a read-aloud pass (S9), optional blind readers (S10), and the hand-off (S11). The command check.js runs every automatable gate, says which stage the files show, and prints what to do next. Stop only at BAR MET or when the user says stop.
- Start and resume with:
node .claude/skills/video-script-production/scripts/check.js --dir research/<slug>/script --version vN - Order that matters: research before prose; chain before prose; hook last; add (texture), then subtract (voice), then clarify, then lint.
- Humans decide: the title, naming a private person, running readers (subagents), and committing.
- Honest status: reaching the v6 bar on a new topic "in one go" is a design intent. Moser Baer took five rounds of the user's feedback to reach v6 (seven to v7); Cafe Coffee Day v1 was the first test of a new topic and reached the bar on the rules of that morning.
The eleven stages at a glance
| # | Stage | You produce | Tool | Leave when |
|---|---|---|---|---|
| S0 | Set up | the folder; lessons read | scaffold.js | learnings.md and rules.json read; slug chosen |
| S1 | Rival-video brief | report.md, synthesis.json | src/topic-research/cli.js | brief exists; contested claims and verification queries listed |
| S2 | Teardown | teardown/SYNTHESIS.md | skill winning-video-teardown | table stakes and differentiators known |
| S3 | Fact base | FACTS.md | web search and fetch | 5+ sourced rows per beat-worth; causal links sourced; magnitudes cross-checked; people researched |
| S4 | Thesis and packaging | chain.cdl; script sections 1 and 2 | opening-protocol.md | four scored candidates, one chosen; title tension stated; withheld list written |
| S5 | Chain and texture plan | chain-vN.json complete | chain-schema.md, texture.md | every section filled |
| S6 | Draft the voice-over | SCRIPT-vN.md section 3 | extract-vo.js | every beat has VO; hook written last |
| S7 | Two passes (and a clarity pass) | the same file | SKILL.md Steps 4a to 4c | the pass questions all answered |
| S8 | Gate loop | lint/, STATUS-vN.md | check.js | 0 FAIL, 0 WARN, damage test, ledger, timecodes, bar numbers |
| S9 | Read-aloud pass | edits; Read-aloud pass: done | extract-vo.js, checklist | checklist answered; S8 green again |
| S10 | Reader pass (needs the user's OK) | reader reports; fixes backed by quotes | extract-vo.js --mode blind | fixes applied and S8 green, or Reader pass: skipped: <reason> |
| S11 | Hand-off | HANDOFF-vN.md; final message; research record | handoff-template.md, session-log.js | check.js says BAR MET |
Quick start
# 1. scaffold (once per topic; --from vM writes the next version from the last)
node .claude/skills/video-script-production/scripts/scaffold.js --dir research/<slug>/script --version v1 --beats 13 --title "<working title>"
# 2. after every stage
node .claude/skills/video-script-production/scripts/check.js --dir research/<slug>/script --version v1 [--prev v0] [--fix] [--no-selftest]
scaffold.js writes the script template (every section the ledger check expects), the chain template (every section the linter reads), FACTS.md (once per topic) and HANDOFF-vN.md. It refuses to overwrite. Run check.js once straight away: it will fail, which proves the harness runs.
A fresh session, even one on a small model, can run the whole pipeline from references/launch-prompt.md, a prompt with six fields that change per topic (topic, entity, slug, version, language, subagent and commit permissions). The Cafe Coffee Day copy is in docs/PROMPT-cafe-coffee-day.md.
Ground rules and defaults
- Research before prose. The user's repeated instruction. The thesis changed once (v4) and the story changed once (v5) because of a source nobody had opened.
- Say plainly what is unproven. Every hand-off states it.
- No subagents, commits, pushes or publishing unless the user asks.
- Keep the user's direction. Change as little as the lesson needs.
- Never edit
rules.jsonto pass. Fix the script. - Ask only for decisions that are the user's: title, naming a private person, running the readers, commit and push. Everything else has a default.
- Shell hygiene. Heredocs and
sedswallow backslashes. Write code and regexes with the Write or Edit tool.check.jsscans for stray control characters.
| Decision | Default | Why |
|---|---|---|
| Language | English | Hinglish later; chain, pulls, figures and cast carry over; parables are rewritten in local terms. |
| "First 60 mins" | The first 60 seconds | The user wrote 60 mins; it can only mean seconds. Say so in the hand-off. |
| Length | 12 to 20 minutes; name the cut candidates | v4 was 12.9 min, v6 19.6, v7 20.2. |
| Beats | 12 to 15 beats of 40 to 105 s; hook last to write | beat_words in rules.json (90 to 260 words). |
| Hook | 60 to 110 s; over 75 s it must carry the B8 elements | The user found a 73 s hook "thin". |
| Voice | Earnest about facts and people, aloof about verdicts | texture.md. |
| Title | A working title and 2 or 3 alternates; flag any word that outruns the evidence; never silently pick | The user has not chosen for Moser Baer. |
| Private people | Name only someone on record in a national outlet; flag it | Mahesh Sharma. |
| Allegations | State what is alleged and what a court decided; never "villain", "scam", "fraud" without a conviction | Moser Baer beat 12. |
| Commit / push | Do not | The user has not asked since 156897f. |
The stages in detail
S0. Set up
- Read
references/learnings.mdand apply its [method] and [measure] points; its [content] points are hypotheses. Readscripts/rules.json: its thresholds are the current definition of the lessons. - Choose the slug (the topic lower-cased with dashes, as
topic-researchdoes) and createresearch/<slug>/script/. - Run
scaffold.js, thencheck.jsto prove the harness works.
S1 and S2. Rival videos
See page 05. In short: run topic-research in the background; read search.json selected and swap off-angle videos; mine the report into FACTS.md as [CHECK] rows; then write the teardown synthesis (option A, B or C).
S3. Fact base
See page 05. The output is FACTS.md. If a causal claim has no source, change the thesis, not the evidence.
S4. Thesis and packaging
Follow references/opening-protocol.md steps 1 to 5 (details on page 08):
- Write the packaging question Q0: what the title and thumbnail promise, in one sentence.
- Write the viewer's priors: what a typical viewer already believes. Curiosity needs a prior to push against.
- Write 3 to 5 candidate loops ("You think X. The record shows Y. So what is Z?"), including the generic one every rival asks. Score each 0 or 1 on seven criteria (specific, breaks a prior, lands on the viewer, shape-hintable, unspoiled, deliverable, scalable). Choose the highest; record the rest as rejected with reasons.
- Write the destination hint (under 20 words, no route terms) and the withheld list (terms that must not appear in the hook).
- Write the one-line thesis, the named idea or governing metaphor, the promise ladder (three rungs and one unannounced bonus), and the title options. State any title and evidence tension to the user.
S5. The chain and the texture plan
Fill chain-vN.json completely before writing prose (field reference on page 08). In this order:
- The beats as one-line statements with
arctags (origin, rise, turn, response, fall, people, blame, lesson), and typed junctions (THEREFORE, BUT, BECAUSE) with a reason; for a BUT, name the expectation the previous beat planted. Run the three junction tests (say-it-aloud, swap, shared noun). - For each beat fill Understand, Care, Change, Compel. If Change is empty the beat is information, not progress: merge or cut.
- Hero numbers (at most 7), each with a stake line before it and a landing after it. Everything else goes to a graphic or the ledger.
- The promise ladder and one unannounced bonus; the peak reveal goes after the midpoint.
- Pulls: for every minute of runtime write what the viewer is waiting for. Declare at least four pulls of at least three kinds, one a person at risk, one a motif that returns at the close.
- The cast: a protagonist with a want, a counterpart, a witness who pays, viewer stakes. The persona lines and the two-sided calls. The figures: one governing metaphor chosen by four tests, a gloss by analogy for each hard term, one or two parables. The hook elements.
- The clarity plan: tags for every person, the witness's cost line, the audience's known terms, spoken counts, named ideas, names that appear once and why, which beats are dense and need a headline.
The quotes can be placeholders until S6; they are verified in S8.
S6. Draft the voice-over
- Beat by beat in the contract order, hook last. Writing the hook first locked in a three-tease opening in v3.
- One
**VO:**line per paragraph; graphics in italic parentheses; no citations in the voice-over (they go in the ledger). - Open a beat on a person or a picture, then the claim, then the number, then a landing (a person, the viewer or a picture, with no figure). The care line comes before the beat's first figure. Name a person before any "he" or "she".
- Say a hinge, not a signpost. "Here is the second number I promised" is a list, not a link.
- Name the central idea once and reuse the name. Gloss every term of art at first use, by analogy. Use derived figures only with the arithmetic in the ledger.
- Write it to be said: contractions where people use them, sentences you can say in one breath, no staged announcements ("Here is what matters"), no denial of something nobody said before the point ("It was not X. It was Y."). State the point.
- Hedge what you cannot show, aloud ("I have not found where that money went"). Every "I" must be true of whoever records it.
- Use
examples/moser-baer-v7/andexamples/moser-baer-v6/(each with a README) as models of how each chain field appears in the text. Copy the form, never the sentences or facts.
S7. The three passes
4a, the texture pass (adds words). Read once per question: who is in every beat and what do they want; where is "you"; what lands after each number; is there a run of more than two number-heavy 30-second stretches; does the governing metaphor return and state its limit; is there an earnest and an aloof line in each third; is every "I" true; does any "he" or "she" at a hinge have a name in the same or the previous sentence.
4b, the voice pass (removes words). Read the whole script aloud at speaking pace and follow references/voice.md: mark, rewrite by pattern, specificity test, keep the honest hedges, do not over-correct. It changes how the script sounds, never what it claims.
4c, the clarity pass. Read each beat once for the K, L, M questions: who is a stranger here, what has to be decoded, is the turn spoken, where is the cost said, does a dense beat open with a headline, does the hook end as a trailer. Add the headline last, once the details are final.
Add, then subtract, then clarify, then lint. One plan (in the chain), one additive pass, one subtractive pass. Three sequential passes would each rewrite the last (the reasoning is in texture.md).
S8. The gate loop
S/check.js --dir <scriptDir> --version vN [--prev vM] [--fix] [--no-selftest]
S/lint.js --script SCRIPT-vN.md --chain chain-vN.json --label vN --out <dir>
S/selftest.js --script SCRIPT-vN.md --chain chain-vN.json
S/ledger-check.js --script SCRIPT-vN.md --chain chain-vN.json [--facts FACTS.md] --strict
S/retime.js --script SCRIPT-vN.md --write
S/compare.js --a lint-vA.json --b lint-vB.json --sa A.md --sb B.md --out compare.md
(S is .claude/skills/video-script-production/scripts.) Fix every FAIL in the script, never in rules.json. Read every WARN and decide; the heuristic ones can be false alarms, in which case reword instead of raising a budget. references/lint-fixes.md lists what each rule usually means and the fix that worked. Expect 3 to 5 loops with the cheat sheet (v6 took about ten without it). Use --no-selftest while drafting and run the damage test before you stop; use --fix to refresh heading timecodes. Details of every gate: page 09.
S9. The read-aloud pass
S/extract-vo.js --script SCRIPT-vN.md --mode timed, then read the whole thing as spoken text once and go through references/read-aloud-checklist.md (26 items, on page 09). A pass that found nothing is suspicious. Fix, re-run S8 (edits can break a declared quote), and write Read-aloud pass: done (<date>; what was found) in the hand-off.
S10. The reader pass (only if the user has asked for subagents)
Give each of two readers only the blind text (extract-vo.js --mode blind: numbered paragraphs, no headings, no chain, no notes). One is a first-time viewer, one a skeptical editor; prompts are in references/reader-prompts.md. Readers return their report as text. Fix only what a reader backs with a quote; each disagreement with the declared chain is a defect in the script, not in the reader. If not authorised, write Reader pass: skipped: not authorised and put it first under "Decisions for you". Limits: two readers, one run, the same model family as the author, honour-system blindness.
S11. Hand-off and close
- Complete
HANDOFF-vN.md.check.jsreads three lines from it, which must start at the beginning of a line:Read-aloud pass: done (...),Reader pass: done | skipped: <reason> | pending,Unproven: <one sentence>. Below them: Decisions for the user, Open items before filming (every [CHECK] and [V-search] row plus the persona's "I" claims), What changed from the previous version. - Write the final message with
references/handoff-template.md: the state in one or two sentences, the script, what the user asked for (with the evidence), pipeline changes, things you should know (corrections, assumptions, unverified sources, tensions with our own data, length and cut candidates), decisions for the user, file paths. - Run
session-log.jsto write the research record. - Append what the run taught to
learnings.mdas [method], [measure] or [content]; add a row totools.mdfor any tool you made. - Run
check.jslast. Do not commit or push unless asked.
Before sending: check.js printed BAR MET or you named which gate is open; every number in the message came from a tool output you just read; the research record, learnings, tools registry and memory notes are current.
If you must stop early: the maturity ladder
Each rung is a legitimate intermediate result. Say which you reached.
| Rung | What exists | Looks like |
|---|---|---|
| L0 | Rival brief and teardown | What rivals say, and what they get wrong. |
| L1 | Fact base and thesis (S3, S4) | A verified story and a chosen question; no prose. |
| L2 | Chain and texture plan (S5) | The whole script declared; lint mostly warns "not found in the text". |
| L3 | Draft with 0 FAIL (S6 to S8) | Moser Baer v4 and v5: structure sound, voice partly machine-like, story or texture incomplete. |
| L4 | The v6 bar: BAR MET except the reader pass | Moser Baer v6 and v7; Cafe Coffee Day v1. |
| L5 | L4 plus a reader pass and fixes | What v4 had after its two readers; the target for the next script. |
What check.js reads from the folder
It infers the stage from files. report.md or synthesis.json in the topic folder (the parent of script/) means S1. teardown/SYNTHESIS.md means S2. Five or more [V], [V-search] or [CHECK] markers in FACTS.md plus the script file means S3. A chosen candidate and a cdl.question in the chain means S4. A named human, a figure with a quote and an earnest persona quote means S5. More than 600 spoken words means S6. The Moser Baer v7 status shows "S1 to S6" next to a green set of gates because the stages after S6 leave no file marker; the judgement gates come from the three lines in HANDOFF-vN.md. The inference is a hint, not proof that the stage was done well.
What this does not guarantee
That a second topic reaches the bar in one go has not been demonstrated beyond the Cafe Coffee Day run, which used the pre-round-7 rules and was done by one session with no subagents and no reader pass. The runbook, gate runner and cheat sheets are built so the later rounds' lessons are in from the start. The first run on each new topic is the test: record the deltas in learnings.md and adjust the runbook.
Written 2026-10-27 from the repository files and the project memory notes. If a page and a file disagree, the file is right: fix the page.