Reelwright
# Reelwright
**An MCP server that lets AI agents edit video through a structured timeline, with transcripts, scene detection, and preview renders for self-checking.**
AI agents can't drag clips on a timeline, and they can't watch or listen to footage in real time. Reelwright gives them what they need instead:
- **Eyes and ears.** Contact sheets, scene-cut detection, silence and loudness maps, waveforms, and word-timestamped transcripts.
- **A timeline as data.** A JSON edit list with ripple editing and undo/redo, driven by tool calls like `delete_range` and `add_text`.
- **A way to check its own work.** `check_frames` renders frames of the *edited* timeline, overlays and captions included, so the agent can verify each change before exporting.
Everything renders locally with ffmpeg, so footage never leaves your machine.
## Features
| Area | What it does |
|---|---|
| Perception | Contact sheets of any source range, scene-change detection, silence detection, EBU R128 loudness curves, waveform images, transcripts (faster-whisper or imported `.srt`/`.vtt`) |
| Editing | Add, trim, split, move and delete clips; ripple-delete any timeline range across clip boundaries; one-call silence removal with padding; per-clip volume |
| Layers | Text overlays (top, center, bottom, lower-third), background music with automatic ducking under speech, fades |
| Captions | Generated from transcripts and kept in sync with the edit; burned in or exported as `.srt` |
| Review | Notes pinned to timeline times, so a human can leave feedback like "cut this pause" for the agent |
| Output | Low-res range previews; exports for YouTube 1080p/4K, Shorts 9:16 and square, with -14 LUFS loudness normalisation; GPU encoders (NVENC, QSV, AMF, VideoToolbox) |
## Requirements
- Python 3.10+
- [ffmpeg](https://ffmpeg.org/) and ffprobe on your `PATH`, built with `libass` and `libfreetype` (standard full builds include both)
- Windows: `winget install Gyan.FFmpeg`
- macOS: `brew install ffmpeg`
- Linux: `sudo apt install ffmpeg`
## Install
```bash
git clone https://github.com/BitLess246/Reelwright.git
cd Reelwright
pip install -e . # core
pip install -e ".[transcribe]" # optional: local transcription with faster-whisper
reelwright doctor # check ffmpeg, filters, fonts and GPU encoders
```
## Connect it to an MCP client
**Claude Desktop.** Add this to `claude_desktop_config.json` (on Windows: `%APPDATA%\Claude\claude_desktop_config.json`), then restart Claude Desktop:
```json
{
"mcpServers": {
"reelwright": {
"command": "reelwright",
"env": { "REELWRIGHT_HOME": "C:/Users/YOU/Videos/Reelwright" }
}
}
}
```
If `reelwright` isn't on the `PATH` Claude Desktop sees, use the full path to your Python with `"args": ["-m", "reelwright"]`.
**Claude Code:**
```bash
claude mcp add reelwright -- reelwright
```
**Other clients.** Run `reelwright` for stdio or `reelwright serve --http` for streamable HTTP.
`REELWRIGHT_HOME` is where projects are stored (default: `~/Reelwright/projects`). `REELWRIGHT_FFMPEG` and `REELWRIGHT_FFPROBE` override the ffmpeg binaries.
## Example
Ask your agent something like:
> Make a project called "beam-lesson", import `D:/footage/lecture.mp4` and `D:/music/calm.mp3`. Remove the silences, add a title card that says "Simply Supported Beams" for the first 3 seconds, put the music under it at low volume, turn on captions, check a few frames, then export for YouTube and as a Short.
A typical run looks like this:
```
create_project → import_media → inspect_media / transcribe
remove_silences (dry_run=True, then for real)
add_text, add_music, set_captions
check_frames [0.5, 2.0, 45.0] → looks at the result, fixes anything off
render_preview (a range) → export preset=youtube → export preset=shorts
```
## Tools
| Tool | Purpose |
|---|---|
| `list_projects`, `create_project`, `get_timeline`, `update_settings` | Manage projects; `get_timeline` returns the whole edit with timeline and source times |
| `undo`, `redo`, `history` | Every edit is one undo step, persisted on disk |
| `import_media` | Probe and add video, audio and image files |
| `inspect_media` | Contact sheet of a source range with timestamps (image) |
| `detect_scenes`, `detect_silence` | Shot changes and silent ranges, in source time |
| `audio_loudness`, `audio_waveform` | Loudness curve and LUFS, or a waveform image, for an asset or a render |
| `transcribe`, `import_transcript`, `get_transcript` | Word-timestamped transcripts; read in source time or as the edited timeline |
| `add_clip`, `trim_clip`, `split_clip`, `delete_clip`, `delete_range`, `move_clip`, `set_clip_volume` | Main-track editing (ripple) |
| `remove_silences` | Detect and cut dead air across the timeline; supports `dry_run` |
| `add_text`, `update_text`, `remove_text` | Text overlays |
| `add_music`, `remove_music` | Background audio with ducking and fades |
| `set_captions` | Captions from transcripts, burned in or as `.srt` |
| `add_note`, `list_notes`, `resolve_note` | Review notes pinned to timeline times |
| `check_frames`, `timeline_contact_sheet` | Frames of the edited timeline for self-checking (image) |
| `render_preview`, `export` | Low-res range previews and final exports |
## How the timeline works
A project is one `project.json`:
- **`clips`** form the main track and play back-to-back. Each clip has `src_in`/`src_out` in source time; its position on the timeline is implied by the clips before it, so deleting anything ripples automatically.
- **`overlays`** and **`music`** sit at absolute timeline times. Ripple deletes shift them so they stay attached to the content around them.
- **Transcripts** are stored per asset in source time and mapped through the edit whenever captions or `get_transcript` need them, so captions stay correct after every cut.
```
<REELWRIGHT_HOME>/<project>/
project.json the edit
history.json undo/redo
cache/ transcripts, analysis, frames, contact sheets
renders/ previews and exports
```
## CLI
```bash
reelwright doctor # environment check
reelwright info beam-lesson # print the timeline
reelwright note beam-lesson 42.5 "cut this pause" # leave feedback for the agent
reelwright export beam-lesson --preset shorts --encoder h264_nvenc
```
## Development
```bash
pip install -e ".[dev]"
pytest
```
The tests generate small synthetic clips with ffmpeg, so no media files are needed.
## Roadmap
- [ ] Local review UI: scrub the timeline in a browser and leave notes
- [ ] Filler-word removal ("um", "uh") from word timestamps
- [ ] Transitions (crossfade, dip to black) and Ken Burns on images
- [ ] Picture-in-picture and B-roll overlay track
- [ ] Render progress reporting and background export jobs
- [ ] Speaker diarisation and face-aware auto-reframing for Shorts
## License
[Apache-2.0](LICENSE). Reelwright calls the ffmpeg you have installed and does not bundle it.
TDQS
Scored across 37 tools
Most tools map cleanly to one resource+action (clips, text, music, notes, transcripts), and the analysis tools (detect_scenes, detect_silence, audio_loudness, audio_waveform) are clearly separated. The only real blur is the preview trio — check_frames vs timeline_contact_sheet both render grids of the edited timeline, and inspect_media does the same for source assets — plus remove_silences overlaying detect_silence/delete_range. Descriptions do enough to steer an agent, but those pairs could be misselected.
Strong verb_noun snake_case pattern: add_clip, trim_clip, split_clip, delete_clip, move_clip, add_text/update_text/remove_text, add_music/remove_music, add_note/list_notes/resolve_note. The deviations are few and readable — noun-phrase analysis tools (audio_loudness, audio_waveform, timeline_contact_sheet) and bare commands (undo, redo, history, export, transcribe). Nothing chaotic, just minor convention drift.
37 tools is heavy for a single server, though the domain (ingest, analyze, edit, overlay, caption, render) genuinely demands breadth and almost every tool is doing distinct work. It still sits well past the comfortable 3-15 range and the preview/inspection cluster in particular feels padded. Borderline heavy rather than gratuitous.
Coverage is unusually deep: full clip lifecycle (add/trim/split/delete/move/volume/delete_range), overlays and music CRUD, transcripts, undo/redo/history, preview and final export with caption handling. Gaps are minor but real — no delete_project or asset/media removal, no read-side settings getter, and no transitions or fades between clips. Agents can work around these, but a few lifecycle ends are dead.