About video-editing-skill
A skill that plans and renders edits for talking-head videos from transcripts. It is for creators who want an approval-based first cut, with captions, chapters, audio cleanup, and optional social posting through WoopSocial.
Key features
- 01Transcript-based cut planning
- 02Approval before rendering
- 03Pause and filler removal
- 04Punch-ins and audio cleanup
- 05Captions and chapter output
- 06Optional WoopSocial posting
Use cases
- 01Preparing a first edit of a talking-head recording
- 02Creating a vertical video with burned-in captions
- 03Generating YouTube captions and chapters
- 04Posting an approved edit through WoopSocial
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ social-media-skills/ video-editing-skill --skill video-editing-skillAfter installing, type/video-editing-skillin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
evals/evals.jsonexamples/nasa-interview/CREDITS.mdedit.jsontranscript.txtexamples/nasa-interview/output/captions.srtchapters.txtedit-report.mdmanifest.jsonfonts/OFL-Poppins.txtreferences/editing-rules.mdwoopsocial.mdscripts/check_setup.pyedit_video.pytranscribe.pyupload_parts.pyDetails
From the project READMEVideo Editing Skill
A raw talking-head recording is usually 20 to 40% dead air: pauses, "um"s, false starts, the sentence said twice. Cutting that by hand takes longer than recording. This skill does the first edit: it reads the transcript, plans every cut with a reason, shows the plan, renders the edit with punch-ins on the jump cuts and clean audio, writes captions and chapters, and posts after a yes. Everything it needs is in this folder.
Four commitments:
- The user's words stay. Only pauses, fillers, stutters, retakes and ranges the user approves go. Meaning is never edited.
- Plan before render. The cut list is shown and approved first.
- Nothing posts without a yes.
- Only footage the user may use. Their own recording, or with permission.
On Windows use py instead of python3 in every command.
Step 0: Setup and the source
Run python3 scripts/check_setup.py: it reports ffmpeg, Pillow, transcription routes and OpenCV
with the install command for the user's system. Required: ffmpeg and Pillow.
Ask, in one message, only what you can't see:
- Which file, and is it theirs?
- Where it's going: YouTube (16:9), social (vertical), or both.
- How tight: youtube (the default: pauses over 0.5 s cut, natural beats kept), tight (0.3 s, fast YouTube and social) or podcast (gentle, no punch-ins).
- Words they use as habits that are safe to cut ("like", "so", "you know", "basically"). These carry meaning in other sentences, so they're opt-in.
- Anything that must stay as it is (a demo, a joke with a pause, a sponsor read).
Step 1: Transcribe
python3 scripts/transcribe.py VIDEO --out work/ --terms "Product name, Jargon, Guest name"
--terms lists names and jargon so they're spelled right; fix whatever is still misheard with
"replace" in edit.json before rendering, because captions burned into a posted video can't be
corrected.
The same three routes as always, with the trade-off explained once:
| Route | How | Cost and speed |
|---|---|---|
| Existing transcript | --from captions.srt | Free, instant; word timing estimated and most "um"s missing, so filler cutting is weaker |
| Groq or OpenAI | GROQ_API_KEY or OPENAI_API_KEY | Groq about $0.04 per hour of audio, a minute or two per hour |
| Local | pip install faster-whisper | Free and private; roughly half to one times the video length with --model small |
The transcriber is prompted to write fillers down; Whisper drops them otherwise. Sounds it still misses (an "mm" nobody wrote down, a breath) are found in the audio itself by the editor.
Step 2: Plan the edit
Read work/transcript.txt once, all of it. Then write edit.json (format at the top of
scripts/edit_video.py):
- Style:
"style": "youtube","tight"or"podcast"(thresholds inreferences/editing-rules.md). Pauses over the limit shrink to a natural beat: shorter mid-sentence, longer after a sentence, longest at a topic change. - Fillers: the default list ("um", "uh", "er", "hmm", "mm") is safe. Add the user's habit
words to
extra_fillersonly when they asked. - Tangents and dead sections: a tangent, a "can you hear me?", a long set-up before the
point. Add them to
cutwith a reason, and tell the user. - Protect anything that must stay with
keep, including silent stretches. - Interviews with question cards or a visible interviewer: keep the questions (about 3
seconds of each card in
keep) unless the user says otherwise; without them every answer starts with "So..." and no context. - Misheard names:
"replace": {"Cyrus Rex": "OSIRIS-REx"}. - Chapters (for YouTube): 3 to 10 chapters from the topic changes, first at 0:00, each at least 10 seconds, named for what the viewer gets ("Why the camera failed", not "Part 2"). Times in the original video; the script moves them.
Then make the plan:
python3 scripts/edit_video.py edit.json --transcript work/transcript.json --out edited/ --plan
edited/edit-plan.md gives the new length, how much came from inside the talking versus long
gaps and cards, the pace in words per minute, and every removal over a second with its reason
and words. Read every retake and stutter line, and the "possible retakes" list: two finished
sentences that start the same way are never cut automatically; decide each one and add it to
cut if it's a real retake. Show the user the summary, the retakes, the tangents you chose and
the chapters, and get a yes.
Step 3: Render
python3 scripts/edit_video.py edit.json --transcript work/transcript.json --out edited/
What it does:
- Cuts pauses over the limit down to a natural beat, plus fillers, stutters, retakes and every
cutrange. Removals shorter than the style's minimum (0.4 s in youtube) are left alone: a jump cut costs more than it saves. - Places every cut by listening: word edges move to where the sound actually stops and starts, so word endings aren't clipped, and sounds the transcript missed (an unwritten "mm") are found.
- Looks at the picture too: title cards and shot changes are cut cleanly, never leaving a few frames of a card.
- Renders in groups of pieces in one pass each, so sound and picture stay in sync however many cuts there are.
- Punch-ins: switches between the full frame and a 1.1x punch-in where a jump cut needs
hiding: always at a cut that removed a second or more, otherwise only after 4 seconds on the
same framing, never at a cut onto a new camera shot.
"punch_in": 0turns it off. - Audio: gain to a working level, rumble filter, noise reduction set from the measured room noise (skipped when the room is already quiet), gentle compression, a peak limiter, and a two-pass loudness pass to -14 LUFS.
- Captions: always writes
captions.srt(2 lines of 42 characters at most, 1 to 7 seconds each, no line break after a small word or inside a name) for uploading to YouTube."captions": {"burn": true}draws them into the video for social, where many people watch muted; vertical versions burn them by default. Don't burn captions into a YouTube video that also gets the SRT: viewers with captions on would see both. - Vertical:
"format": "vertical"makes a 1080x1920 version cropped onfocus_x.
It writes edited/edited.mp4, captions.srt, chapters.txt, edit-report.md and
manifest.json.
Check before showing the user: open cuts.jpg (frames just before and after the biggest
cuts: look for flashes of a card, a jump in a different shot, a frozen expression) and read the
warnings in manifest.json (sync, pace over 190 words per minute, loudness). Fix and re-render
when a retake kept the wrong take, the pace feels breathless (a gentler style), or a cut lands
badly (keep that spot).
Step 4: Post with WoopSocial
How to connect, upload and post: references/woopsocial.md. Short version:
social_accounts_list; not connected: the one connect path for this agent (free plan: 2 social accounts), thenoauth_create_authorizationper platform.- Upload
edited.mp4with an upload session (media_uploads_create_sessionwith the byte size frommanifest.json,python3 scripts/upload_parts.py session.json edited/edited.mp4,media_uploads_complete_session). - YouTube:
title(main search words first, under 70 characters),privacy, and a description that starts with one line on what the viewer gets, then the chapters fromchapters.txt. Uploadcaptions.srtin YouTube Studio afterwards (WoopSocial doesn't send caption files). - Show the post (file, title, description, account, time with timezone) and get a clear yes.
Then
posts_createandposts_get.
Step 5: Read the results
After a week, social_account_posts_list: views, likes, comments where reported, with the
collection date; missing means "not reported". Retention and average view duration are in
YouTube Studio; ask the user for them. If viewers drop early, the next edit gets a tighter
opening; if they drop at a chapter, that section was too long.
Quality bar
Would a professional editor hand this over? Reject it if a word is clipped, a cut lands mid-breath with a pop, a punch-in changes every few seconds, the pace leaves no room to think, or meaning changed.
Edge cases
- Two people on camera: keep
formatat source; punch-ins still work on a wide shot. - Screen recording with a voice: set
"punch_in": 0. - Music under the voice: silence detection sees music as sound; set
"voiced_gaps": false. - Very long recordings (over an hour): works, but render time is about the video's length; plan first, render once.
- No speech for a stretch on purpose (a demo):
keepit.
References
references/editing-rules.md: thresholds, fillers, retake patterns, punch-ins, audio chain, captions and chapters, with sources.references/woopsocial.md: connect, upload, post and read results.