forced-narrative-exact
Skill1 starsChanged 3 months agoMITView on GitHub
Generate exhaustive, literal, frame-accurate forced-narrative reports from video masters containing burned-in dialogue subtitles. Use when a user requests a forced-narrative inventory, burned-in subtitle report, exact on-screen dialogue transcription, or start/end SMPTE timecodes for every subtitle, especially when embedded tmcd timecode, multiple program passes, textless duplicates, and exclusive frame boundaries must be handled consistently.
In this repository16 other files it gives its agents.
- AGENTS.mdAGENTS.md
- site/AGENTS.mdAGENTS.md
- site/CLAUDE.mdCLAUDE.md
- audioSkill
- captions-complianceSkill
- downloadSkill
- imageSkill
- inspectSkill
- install-media-toolsSkill
- program-masterSkill
- shotsSkill
- speech-captionsSkill
- subtitlesSkill
- timecodeSkill
- video-transformationSkill
- vision-analysisSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
16 rules. About 0 are common, 10 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈10
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 15
Prefer this skill over vision-analysis when the deliverable is an exhaustive, frame-accurate burned-in dialogue inventory …
- Distinctive: line 19
Before analyzing frames or publishing a report, read:
- Very specific: line 29
Write outputs beneath $MEDIASKILLS_DATA_DIR/generated/ when set, otherwise .mediaskills/generated/ in the current workspace.
- Very specific: line 43
If your tools showed a filesystem path when loading this SKILL.md, strip SKILL.md and use that folder.
- Very specific: line 44
If you already ran another mediaskills script (for example .../audio/scripts/extract.py), this skill is a sibling of that folder: same …
- Very specific: line 67
Prefer absolute paths for --input / --output when cwd is uncertain.
- Distinctive: line 72
Before running any script, treat these two failures differently:
- Very specific: line 75
Only escalate sandbox permissions if the error is explicitly a permission denial (e.g.
- Distinctive: line 85
Do not assume the full file is one program pass.
- Distinctive: line 108
Write the seed JSON described in references/formats.md.
- Distinctive: line 120
Treat low-confidence, very short, OCR-thin, or transition-adjacent cues as mandatory visual-review items.
- Distinctive: line 134
When the master contains a verified, frame-aligned textless duplicate, compare every texted source frame with its aligned textless frame …
- Distinctive: line 152
If no verified textless duplicate exists, state that this backstop was unavailable and compensate with full chronological frame review …
- Distinctive: line 169
Never label OCR output as exact until every cue has passed agent transcription review and boundary-frame QC.
- Distinctive: line 171
Run the golden self-test after changing report builders, validators, or fixtures:
- Distinctive: line 184
Never label OCR as exact until every cue passed agent transcription review and boundary-frame QC.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Forced Narrative Exact
Produce a complete forced-narrative inventory whose text is literal and whose start/end boundaries are source-frame accurate. Use OCR only to discover candidates; the agent must inspect the pictures and approve every cue.
Prefer this skill over vision-analysis when the deliverable is an exhaustive, frame-accurate burned-in dialogue inventory (Markdown/JSON/CSV/SRT) with exclusive-end frame QC. Use vision-analysis for broader on-screen text/graphics inventories from interval or shot frames.
Required reading
Before analyzing frames or publishing a report, read:
- references/report-contract.md for inclusion, transcription, timing, and QC rules.
- references/formats.md before creating a seed or override JSON.
Inputs and dependencies
- Accept a local video readable by
ffmpegandffprobe. - Require
tesseract; the scripts useuv runto provide Python packages. - Require an image-capable agent for final transcription and visual QC. If image viewing is unavailable, stop after the candidate scan and state that the result is not publication-ready.
- Write outputs beneath
$MEDIASKILLS_DATA_DIR/generated/when set, otherwise.mediaskills/generated/in the current workspace.
Running scripts
This skill's scripts live in scripts/ alongside this file. Before running any script, resolve its absolute path from this skill's own directory — do not assume the shell cwd is the skill folder, the repo root, or the workspace. Stay in the workspace (so media paths resolve) and pass the absolute script path to uv run:
uv run <skill_directory>/scripts/scan_caption_band.py --input "<path-to-media>" --interval 0.5<skill_directory> is a placeholder. Never pass those angle brackets to the shell — the command will fail. Replace it with a real absolute directory before invoking uv run.
How to get that directory (do this yourself; do not ask the user first; do not skip the skill):
- If your tools showed a filesystem path when loading this
SKILL.md, stripSKILL.mdand use that folder. - If you already ran another mediaskills script (for example
.../audio/scripts/extract.py), this skill is a sibling of that folder: same parent, directory nameforced-narrative-exact. - Otherwise search standard install locations and confirm the script exists:
NAME=forced-narrative-exact
for d in \
"$HOME/.agents/skills/$NAME" \
"$HOME/.cursor/skills/$NAME" \
"$HOME/.codex/skills/$NAME" \
"$HOME/.claude/skills/$NAME" \
"$PWD/.agents/skills/$NAME" \
"$PWD/.cursor/skills/$NAME" \
"$PWD/skills/$NAME"
do
if [ -f "$d/SKILL.md" ] && [ -e "$d/scripts/scan_caption_band.py" ]; then
SKILL_DIR=$(cd "$d" && pwd)
break
fi
done
[ -n "$SKILL_DIR" ] || { echo "mediaskills: $NAME not found" >&2; exit 1; }
uv run "$SKILL_DIR/scripts/scan_caption_band.py" --input "<path-to-media>" --interval 0.5Prefer absolute paths for --input / --output when cwd is uncertain.
Missing binaries vs permissions
Before running any script, treat these two failures differently:
- If a required binary (
uv,ffmpeg,ffprobe,tesseract) reportsNo such file or directoryorcommand not found: this is a missing or unreachable binary, not a permissions issue. Escalating sandbox permissions will not fix it. Runcommand -v uv,command -v ffmpeg,command -v ffprobe, andcommand -v tesseractto see whether they resolve at all. If not, install or re-link them (install-media-toolsdoctor/install) rather than retrying with wider permissions. - Only escalate sandbox permissions if the error is explicitly a permission denial (e.g.
Operation not permitted,Permission denied).
Workflow
1. Establish source timing and scope
Probe the video before scanning. Record exact FPS as a fraction, frame count, dimensions, duration, and embedded tmcd start. Preserve drop-frame punctuation (;).
Identify the program regions in master order. Inspect slates and separators. If a second pass is explicitly textless or is a verified textless duplicate, scan it to confirm absence but do not duplicate cues. Record the pass decision in the seed and final scope.
Do not assume the full file is one program pass. Do not infer forced narrative from audio transcription.
2. Run dense candidate discovery
Scan the subtitle band at 2 fps (--interval 0.5) over every pass that may contain burned-in dialogue. Use the bottom 30.56% of the picture by default; adjust after viewing representative frames.
uv run <skill_directory>/scripts/scan_caption_band.py \
--input /path/to/master.mp4 \
--start 80 --end 793 \
--interval 0.5For a 1280×720 source whose subtitles occupy the same zone as the reference report, use --crop 0,500,1280,220.
The scan JSON and retained JPGs are discovery material, not the report. OCR false positives and punctuation errors are expected. OCR can also return no useful text for a real subtitle, especially for a thin, single-line white cue over a bright or textured background, so OCR silence is never evidence that a frame is textless.
3. Build the agent-verified seed
Review all scan frames in chronological batches. Inspect frames around every OCR cluster, plus transition frames between clusters. Write one seed cue for each distinct visible subtitle state.
Transcribe directly from the image. Preserve visible speaker labels, brackets, capitalization, punctuation, apostrophes, numerals, and line breaks. Split successive subtitle states even when they form one grammatical sentence. Speaker/context metadata is internal only and must not become a separate Markdown or CSV report column.
Write the seed JSON described in references/formats.md. Approximate windows should bracket the full cue with roughly 0.5 seconds of tolerance; they are not final timings.
4. Refine every cue to source frames
uv run <skill_directory>/scripts/refine_boundaries.py \
--input /path/to/master.mp4 \
--seed /path/to/forced_narrative_seed.jsonThe refiner constructs a white-text template from a midpoint frame, scans a padded source-frame window, and selects the contiguous matching run containing the reference frame. It records the first matching frame as start_frame and the first nonmatching frame after it as end_frame_exclusive.
Treat low-confidence, very short, OCR-thin, or transition-adjacent cues as mandatory visual-review items. Inspect the frame immediately before start, the start frame, the last included frame, and the exclusive end frame. Supply corrections with --overrides using the override schema; never widen timings by guesswork.
5. Build the four report artifacts
uv run <skill_directory>/scripts/build_report.py \
--refined /path/to/forced_narrative_refined.json \
--overrides /path/to/forced_narrative_overrides.jsonThis writes stable, paired .md, .json, .csv, and .srt artifacts. Embedded source TC is primary in Markdown and JSON. File-relative TC, seconds, and frame numbers remain in JSON/CSV. Markdown and CSV omit a separate speaker/context column; visible labels remain literal cue text. SRT uses file-relative elapsed time.
6. Run the completeness backstop
When the master contains a verified, frame-aligned textless duplicate, compare every texted source frame with its aligned textless frame after building the draft report. This is mandatory because it can find real subtitles that OCR never recognized.
Determine the texted-to-textless frame offset separately for every act or snap-in region. Then run:
uv run <skill_directory>/scripts/audit_completeness.py \
--input /path/to/master.mp4 \
--report /path/to/forced_narrative_report.json \
--region 1925,11313,36019 \
--region 11337,20049,36019 \
--output /path/to/completeness_audit.json \
--contacts-dir /path/to/completeness_contactsThe audit subtracts frames already covered by report cues and retains every remaining difference interval. It samples the first frame, last frame, and every 12 frames within each interval. Inspect every contact sheet; do not collapse a long activity cluster to one maximum-difference representative. A brief blank gap or a visible text change creates a distinct subtitle state even when nearby differences belong to the same scene.
Record every candidate in a review JSON using the schema in references/formats.md, then rerun the audit with --review. Use missing_dialogue for an omitted cue and subtitle_boundary_residual for clipped cue frames. Both dispositions block publication: correct the seed/refinement, rebuild the report, and rerun the audit. Delivery requires a final audit with every remaining interval classified as excluded_non_dialogue_text or alignment_artifact and publication_ready: true.
If no verified textless duplicate exists, state that this backstop was unavailable and compensate with full chronological frame review around every discovery cluster and transition; do not invent a textless alignment.
7. Validate before delivery
uv run <skill_directory>/scripts/validate_report.py \
--report /path/to/video_forced_narrative_report.json \
--input /path/to/master.mp4 \
--completeness-audit /path/to/completeness_audit_reviewed.jsonPass --completeness-audit whenever a verified textless duplicate exists. Do not deliver when validation reports an error. Also complete the visual gates in the report contract; structural validation cannot prove transcription completeness when a textless backstop is unavailable.
Mandatory delivery
Present the complete Markdown table, not a sample. State the cue count, source FPS/drop-frame mode, embedded source start, pass scope, and exclusive-end convention. Link the Markdown report and paired JSON, CSV, and SRT.
Never label OCR output as exact until every cue has passed agent transcription review and boundary-frame QC. When a verified textless duplicate exists, also require a reviewed, publication-ready completeness audit.
Run the golden self-test after changing report builders, validators, or fixtures:
uv run <skill_directory>/scripts/self_test.py --work-dir /absolute/path/forced-narrative-self-testOr from the repo root: ./scripts/smoke.sh --self-test.
Acceptance checks (agent must pass before delivery)
- Contract: exit 0,
ok: true, everyoutput_pathsentry exists and is non-empty. - Skill gate:
validate_report.pysucceeds; when a textless duplicate exists, completeness audit haspublication_ready: true. - Spot-check: complete the four-frame visual QC and sampling gates in references/report-contract.md.
- Never label OCR as exact until every cue passed agent transcription review and boundary-frame QC.
- On failure: fix seed/refinement and rebuild; do not deliver partial tables.
Do not use for
- speech-to-text captions from audio (use
speech-captions) - sidecar SRT/VTT compliance or format conversion (use
captions-compliance/subtitles) - broad graphics/title/lower-third inventories without exclusive frame-accurate dialogue delivery (use
vision-analysis) - program act/commercial structure (use
program-master)
Related skills: inspect, program-master, timecode, and vision-analysis.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

