Kerf is a cross-platform desktop editor with an embedded MCP server, so an LLM (Claude, or any MCP client) can analyze your footage and assemble the cut through the same engine the GUI uses, on the same live project — and it can actually see the frames it's editing. Nothing is re-encoded until you export.
kerf website · download · FAQ
A kerf is the slit a saw leaves behind — the cut itself. Kerf edits non-destructively: your timeline is an edit list over the original media, and nothing is re-encoded until you hit export.
Plenty of tools bolt a chatbot onto a video editor. Kerf inverts that: the editor is an API, exposed twice over one shared project — as the GUI you click, and as Model Context Protocol tools an agent calls. So the agent isn't scripting a black box; it drives the identical engine — and its edits are staged for review, so they never move the cut you are looking at.
- 🎬 The agent has eyes.
get_frame,skim_asset(a contact-sheet montage for finding the good parts),preview_timeline(the composited cut at a given time) andskim_timeline(a contact sheet of the whole cut) return real images the model sees — so it can find the right moment and confirm the cut, not guess from metadata. - 🧠 Same engine, same project. The MCP server and the webview hold the same
Projectbehind one lock — no import/export round-trip, no second copy of the truth, and the agent previews its own work through the exact graph that renders your export. - 🤝 You stay in control. Agent edits stage — they build a proposal, not your cut. The review card shows a real diff (added / cut / moved / retrimmed), you can watch the proposed timeline play, and Apply lands it as one revertible revision. Work is handed back through a persisted task queue, so an agent is safe to leave running on someone's edit.
- ✂️ Truly non-destructive. Everything is an EDL over source ranges. Cuts, effects,
and keyframes are just data until you export a single
filter_complex. - 📦 Runs without FFmpeg dev libraries. The engine drives the
ffmpeg/ffprobebinaries, so probe, analysis, frames, waveforms, and export all work on a plain install — the in-process libav path is optional.
| Multi-track NLE | Bespoke timeline: video/audio/text tracks, free clip positioning with gaps, drag-to-move across tracks, edge-drag trim, razor split, roll / slip / slide trim tools, trim-to-playhead, ripple delete, markers, mute/solo/lock, snapping to edges / playhead / beats. |
| Real playback | Not a slideshow — one long-lived FFmpeg streams the composited cut (every track, effect, keyframe and overlay) paced against the audio clock, with J/K/L shuttle audible both ways and audible Web-Audio scrub. |
| Delivery frames | 16:9 / 9:16 / 1:1 / 4:5 is a property of the project, so preview, scrub and export all render the same frame — with platform safe-area guides and cover-crop instead of letterboxing. |
| Smart crop | Reshaping 16:9 to 9:16 throws away most of one axis. smart_crop samples where each shot's content actually is (edge detail + motion, no model to ship) and writes the crop that keeps it, per clip — an ordinary transform the sliders can still override. |
| Ready to publish? | platform_check judges the cut against Reels / Shorts / TikTok / Instagram / YouTube — length, shape, resolution, captions — and tells a hard limit (rejected) apart from a reach limit (accepted, then buried). Advisory only; nothing blocks an export. review_cut lints the editing itself — flash frames, cuts inside a word, sound cut into sound, jump cuts, captions a later edit left behind, black gaps — each with the tool that fixes it. Cover frames save at the full delivery resolution. |
| Analysis & speech | Silence and scene detection, an onset/tempo grid, EBU R128 loudness and speech-vs-music from one decode — plus transcription in every build, via FFmpeg's whisper filter or in-process whisper.cpp (models fetched on first use). |
| Cut to the beat | The tempo grid is drawn on the ruler and snapped to while dragging, and snap_to_beats ripples a whole track's cuts onto it, retrimming each clip at its outgoing edge. |
| Stabilization | Shaky hand-held footage made steady, per clip: vid.stab measures the camera once (a background analysis of the original, kept beside it), and the preview, every still, a proxy and the export move each source frame by the same correction — speed, reverse and ramps keep it. FFmpeg's deshake steps in where the FFmpeg has no vid.stab. |
| Effects, color & looks | Per-clip video (blur/sharpen/hue/negate/vignette/chromakey) and audio (highpass/lowpass/EQ/compressor/gate/denoise) chains, transform + color grade, and one-click Punchy / Warm / Cool / Faded / B&W looks. |
| Transitions & masks | Eleven transitions — crossfade, dip to black / white, slide and push in four directions — that borrow the outgoing clip's handle and degrade to a hard cut when there is none. Masks cut a clip to a feathered rectangle or ellipse so a lower track shows through: a blurred face is a duplicated shot above, blurred and masked. Blend modes — multiply, screen, overlay, hard light, add, darken, lighten, difference, exclusion — composite a clip onto the tracks below instead of over them: a light leak screened onto the shot, a texture multiplied into it. |
| Keyframe animation | Animated zoom, position, rotation and opacity via keyframes — linear, hold, ease in / out or a custom curve per key — the Transform panel auto-keyframes at the playhead. Any one number can carry keys of its own: a colour that warms over a shot, an opacity ramp that starts later than the zoom, the clip's volume swelling mid-clip. |
| 360 reframing | Cut a normal, flat shot out of equirect or Insta360 dual-fisheye footage: aim a virtual camera (yaw / pitch / roll / FOV) and keyframe the pan. An Insta360 lens pair imports as one 360 asset — Kerf stitches the two capture files into an equirect sphere once and caches it. Spherical sources are detected on import; anything unflagged can be marked by hand. |
| Titles & captions | Text overlays / lower-thirds with their own keyframes, Title / Lower-third / Caption style presets, the system font list, and SRT export. Captions follow the cut: the transcript is projected through the clips that actually show its footage (trim / speed / reverse honored), so words you cut out get no caption — in a subtitle Lines style or the social Word punch style, one large word on the beat of the speech, fitted to the delivery frame. |
| Edit by transcript | The transcript is an editing surface: lines resolve to the clip carrying them, a click seeks, and × cuts that sentence out of the timeline and ripples the gap closed. |
| Smart mixing | A mixer strip per audible track (fader + pan, mirrored exactly in preview), per-track ducking (music dips under dialogue via sidechain), a master bus (fader + safety limiter), single-pass loudnorm to −14 LUFS on export, and measured levels (LUFS / true peak, per track and master) an agent can check before it calls a cut finished. |
| GPU-accelerated export | NVENC / QSV / VideoToolbox / AMF are verified with a real test encode before being offered, hardware decode falls back to software on its own, and range export renders just the region between your in/out marks. |
| Agent workflow | The full MCP tool set (below), staged edits with a reviewable diff, a persisted task queue, and a fully revertible edit history attributed to user / agent / system. |
| Plays nicely with your machine | One heavy FFmpeg job at a time, at a CPU budget you set (Background / Balanced / Full speed in Settings, or KERF_CPU_PERCENT) and below-normal priority — an agent analyzing eight sources no longer takes the desktop down. Every toast lands in a notification center, so a failure is still readable after it fades. |
| Auto-update | The app updates itself from its own GitHub releases; a bundle only installs if its minisign signature verifies against the embedded public key. |
The Kerf site has a direct download
button for your platform, or grab the installer from the
latest release — .dmg
(macOS, Apple silicon + Intel), .AppImage/.deb/.rpm (Linux, x86_64 + arm64), or
.exe/.msi (Windows). macOS and Linux builds expect a system FFmpeg on PATH; the
Windows build bundles it. The macOS build is unsigned: on macOS 15 and later clear the
quarantine flag once with xattr -dr com.apple.quarantine /Applications/Kerf.app
(Windows SmartScreen asks once too — More info → Run anyway). Every installer
carries a build-provenance attestation: gh attestation verify <file> --repo OrellBuehler/kerf.
Once installed, Kerf updates itself from its own releases.
git clone https://github.com/OrellBuehler/kerf
cd kerf/frontend && bun install && cd ..
cargo run -p kerf-app # launches the app (runs the frontend dev server first)You need Rust ≥ 1.95, Bun ≥ 1.2, the platform WebView/GTK libraries for Tauri,
and (for the default ffmpeg feature) the FFmpeg development libraries + clang. See
Building for per-platform setup and the no-FFmpeg path.
The desktop app hosts the MCP server over streamable HTTP at 127.0.0.1:7777/mcp
(change it in Settings › Agent, or with KERF_MCP_ADDR). Every request must carry the
bearer token Kerf made on first start; Settings › Agent shows it with the exact commands
below filled in. Start the app, then point an MCP client at it — e.g. with Claude Code:
claude mcp add --transport http kerf http://127.0.0.1:7777/mcp \
--header "Authorization: Bearer <token>"…or in any MCP client config that supports HTTP servers:
{
"mcpServers": {
"kerf": {
"type": "http",
"url": "http://127.0.0.1:7777/mcp",
"headers": { "Authorization": "Bearer <token>" }
}
}
}Every tool is listed by default. A client that loads every tool's schema up front can ask for fewer by
adding tool sets to the URL — http://127.0.0.1:7777/mcp?tools=core,titles (sets: core, analysis,
clips, keyframes, titles, audio, music, delivery, tasks, project; Settings › Agent builds
the command for you). The server also offers workflow prompts — rough_cut_from_transcript,
podcast_cleanup, social_reel, music_bed, sound_design, deliver — which Claude Code shows as /mcp__kerf__<name>.
An agent's edits wait in a proposal for you to accept (all of it, or only some changes) unless you switch review off in the same place: then its edits, the work on the tasks you queue included, land on the cut as it makes them, each one an undoable step.
No display (CI, a server)? Run the MCP server without a window:
KERF_MCP_TOKEN=<32+ chars> kerf-app --headless --mcp-addr 127.0.0.1:7777 [--project cut.kerf]It prints one JSON line on stdout once it listens and stops on SIGINT / SIGTERM; edits land live
unless --review. kerf-app --headless --help lists the flags (--data-dir, --token-file, …).
On a server, --cache-dir DIR keeps the caches on a volume of your choosing and --cache-max-gb N keeps the
regenerable ones (proxies, waveforms, filmstrips, stems) under N GiB, least recently used first; what the open project
uses and the downloaded models are never removed. --cache-dir moves the model downloads too, and the cap protects only the
project this server has open: give each server its own cache directory, and do not share one with the desktop app.
To host it for remote agents (a Docker image, one container per tenant behind TLS), see
deploy/README.md.
A server that remote agents reach keeps them to one directory with --workspace DIR. Over HTTP, its files
are then served beside /mcp, behind the same token: PUT /files/<path> uploads (refused if the file is
there unless ?overwrite=1, never one the open project uses), GET /files/<path> downloads (with Range),
GET /files/<dir>/ lists, DELETE /files/<path> removes.
curl -H "Authorization: Bearer $TOKEN" -T clip.mp4 http://host:7777/files/media/clip.mp4 # then import_asset media/clip.mp4
curl -H "Authorization: Bearer $TOKEN" -o cut.mp4 http://host:7777/files/exports/cut.mp4The tools list_files and file_url tell an agent what is there and where to send it. Behind a TLS reverse
proxy, --public-url https://kerf.example.com/kerf is the base file_url builds on (the proxy strips the
prefix). --max-upload-gb N caps a file (default 20); at most four uploads run at once, one that sends nothing for
a minute is dropped, and nothing is written that would leave less than 1 GiB free. --allow-url-import adds import_url, which downloads an
http(s) URL into the workspace and imports it — only from public addresses, every redirect checked.
kerf-app --headless --stdio serves the same tools on stdin / stdout, for as long as the client keeps
stdin open — no port, no token. In Claude Code:
claude mcp add kerf -- kerf-app --headless --stdio --tools core,titles…or in a .mcp.json / mcpServers config:
{
"mcpServers": {
"kerf": { "command": "kerf-app", "args": ["--headless", "--stdio", "--project", "/path/to/cut.kerf"] }
}
}--tools picks tool sets as ?tools= does on the URL; --project, --new-project, --data-dir, --review,
--proxies and --cpu-percent work as above.
Now ask the agent to work on the project you have open — "skim the interview clip, cut the dead air, and drop in captions." It will claim a task, use the tools below, and hand back a reviewable result.
See / analyze
get_editing_guide (how the tools fit together) · list_assets (fields: "compact" for a big library, imported_after for what an import added, tags to filter by label) · list_tags (the labels in use) · import_asset · get_asset_metadata · analyze_asset · get_transcript (lines with
their speakers; the timed words on request) · get_cut_transcript (what the cut says, in timeline time) · speaker_ranges · find_filler_words ·
search_transcripts (where anything is said across the library, and whether the cut uses it) · refine_transcript ·
get_analysis_detail · get_timeline_state · timeline_summary · get_editor_context (what the user has
selected and where the playhead is) · get_scopes (waveform / parade / vectorscope / histogram numbers of a
frame) · get_waveform · get_energy ·
get_frame (drill-in frame) · skim_asset (contact-sheet montage) ·
preview_timeline (the composited cut) · skim_timeline (a contact sheet of the cut) · preview_svg_overlay (an animated title
as a contact sheet of moments) · preview_svg_preset · validate_svg — the bold ones return images the model
can see, and get_frame / preview_timeline take a region to zoom into a quarter of
the frame at full source detail. Also get_waveform_range · analysis_status · missing_assets ·
get_music_structure · get_band_balance (where music keeps its energy, in six bands per section) ·
list_sound_effects (the 21 sounds, what each is for and where its hit lands) · suggest_sound_effects (where the cut would take
one: cuts, titles, drops, markers) ·
get_ripple_mode · voiceover_status · stems_status · music_status.
Cut & arrange
cut_clip · add_clip_to_timeline · split_at · split_remove · split_remove_clips · trim · roll_edit ·
slip_clip · slide_clip · reorder · move_clip ·
remove · ripple_delete · cut_clip_range · duplicate_clips · set_clip_enabled ·
add_track · remove_track · set_track_duck · set_track_muted · set_track_solo ·
set_track_locked · add_marker · update_marker · remove_marker · remove_silence ·
snap_to_beats · sync_clips_by_audio · smart_crop · extract_audio · concatenate · edit_asset_tags (label assets, e.g. location: Cumbuco) · assemble_by_tag (a cut grouped by a label, one titled section per value) · move_clips · remove_clips ·
add_asset_audio · set_ripple_mode · plan_music_fit · fit_music · compose_music (original music from a
score, fitted to the cuts) · add_sound_effects (whooshes, impacts, risers and pops, synthesized and placed with their hit on
the picture) · update_sound_effect ·
detach_audio · detach_audio_clips · reattach_audio · reattach_audio_clips ·
link_clips · unlink_clips · apply_edits (several edits as one revision, all or nothing, with a dry run)
Style & animate
set_volume · set_fade · set_speed · set_speed_ramp (slow motion / speed-up that eases) · stabilize_clip (take a hand-held camera's shake out) · stabilization_status · set_transform · set_transform_at · set_color ·
set_grade (curves, colour wheels, a .cube LUT) · set_transition · set_mask · set_blend_mode (multiply, screen, overlay, …) · set_video_effects · set_audio_effects ·
set_keyframes · add_keyframe · set_keyframe_easing · set_property_keyframes · set_property_tracks · copy_keyframes · apply_motion_preset (an entrance, exit or emphasis such as pop_in, slide_out_to_left, pulse) · list_motion_presets · set_behaviors (live sway, breathe, spin, drift and shake riding on a clip's pose) · bake_behaviors (turn them into keys) · clear_keyframes · set_reframe · clear_reframe ·
set_reframe_keyframes · add_reframe_keyframe · set_track_volume · set_track_pan ·
set_master_volume · set_master_limiter · set_master_true_peak · set_master_duck ·
add_overlay · update_overlay · remove_overlay · set_overlay_keyframes ·
add_svg_overlay · update_svg_overlay · remove_svg_overlay · list_svg_presets · add_title_clip · update_title_clip ·
list_templates · save_template · apply_template · set_template_values · set_title_text_box · set_title_text_animation · list_text_animation_presets · list_text_animation_curves · convert_title_text · import_template · export_template · delete_template ·
generate_captions · import_captions · clear_captions · export_srt · export_captions · list_fonts ·
set_delivery_format · set_asset_projection
Render & hand-off
export · export_capabilities · export_cover · add_thumbnail · update_thumbnail · remove_thumbnail · preview_thumbnail · export_thumbnail · suggest_thumbnail_frames · export_interchange · export_markers · platform_check · review_cut (flash frames, cuts inside a word, clicks, jump cuts, stale captions, black gaps, stabilized clips not yet analysed) · get_levels · stage_edits ·
staged_diff · apply_staged_edits · discard_staged_edits · revision_diff ·
list_tasks · add_task · claim_next_task · complete_task · fail_task ·
resolve_task · remove_task · history · undo · redo · revert_to ·
transcription_status · set_speech_model · download_speech_model
Project, review & background jobs
project_info · save_project · save_project_as · open_project · new_project ·
get_settings · set_settings · undo_staged_edit · restore_discarded_edits ·
apply_staged_subset · proxy_status · rebuild_proxy · delete_proxy ·
job_status · cancel_job · list_jobs · list_files · file_url · import_url (the last three only on a
headless server with a workspace) — the long tools
(export, export_variants, analyze_asset, generate_voiceover, compose_music, separate_stems,
download_speech_model, import_asset, import_url, smart_crop, stabilize_clip, refine_transcript, sync_clips_by_audio) take
background: true and answer a
job_id at once. Instead of polling, an agent can subscribe to the resources kerf://jobs/{job_id},
kerf://jobs, kerf://tasks and kerf://project: the server pushes a resource-updated notification
when one changes (a job moving or ending, a task queued, you editing the cut). Applying a proposal is refused to an agent while you have review on;
undo, redo and revert_to are too, since they would rewrite your live cut.
Every mutating tool emits a project-changed event, so the agent's proposal appears in
the GUI for review as it is built — the live cut only moves when you apply it.
Linux (Debian / Ubuntu)
# Tauri system dependencies
sudo apt update
sudo apt install -y build-essential curl wget file pkg-config clang \
libwebkit2gtk-4.1-dev librsvg2-dev libxdo-dev libssl-dev \
libayatana-appindicator3-dev
# FFmpeg development libraries (for the default `ffmpeg` feature)
sudo apt install -y libavutil-dev libavcodec-dev libavformat-dev \
libavdevice-dev libavfilter-dev libswscale-dev libswresample-devmacOS
xcode-select --install # Command Line Tools (provides clang)
brew install ffmpeg pkg-config # FFmpeg dev libraries + pkg-configWindows
Install the WebView2 runtime (preinstalled on Windows 11) and the MSVC build tools, then provide FFmpeg via vcpkg:
vcpkg install ffmpeg:x64-windows
$env:VCPKG_ROOT = "C:\path\to\vcpkg"
# or point ffmpeg-sys-next at a shared build:
$env:FFMPEG_DIR = "C:\ffmpeg" # contains include/ lib/ bin/You also need LLVM/clang on PATH for bindgen (winget install LLVM.LLVM).
Every crate exposes an ffmpeg feature (on by default) that forwards to
kerf-core/ffmpeg. Disable it to build the model, persistence, and MCP tools with only
the ffmpeg/ffprobe binaries installed — probe, analysis, frames, waveforms and
export all still work:
cargo check --workspace --no-default-features
cargo test -p kerf-core --no-default-features
cargo run -p kerf-app --no-default-featuresTwo further optional features need a fuller toolchain and are off by default:
libav-render (experimental in-process libav export) and whisper (local whisper-rs
transcription; set KERF_WHISPER_MODEL). The downloadable release bundles are built
with whisper, so transcription there never depends on the local ffmpeg having been
built --enable-whisper; a build from source falls back to that filter unless you pass
--features whisper (cmake + a C++ compiler + libclang).
Kerf is a Cargo workspace of three Rust crates plus a Tauri-embedded SvelteKit frontend.
kerf-core is the UI-agnostic engine, kerf-gpu an opt-in wgpu preview compositor, and kerf-app a thin adapter that exposes that one
Project API twice — as Tauri commands to the webview and as MCP tools to a connected
LLM — over one shared, locked project.
kerf/
├── crates/
│ ├── kerf-core/ # engine: domain model, .kerf persistence, FFmpeg backends
│ │ ├── model.rs # Asset / Timeline (EDL) → Track → Clip, effects, keyframes
│ │ ├── project.rs # SQLite .kerf project + all timeline operations + task queue
│ │ ├── analysis.rs # pluggable Transcriber / SceneDetector / SilenceDetector
│ │ └── engine/ # cli.rs (binaries, always on) + ffmpeg.rs (in-process libav)
│ ├── kerf-gpu/ # wgpu compositor for the opt-in GPU preview
│ └── kerf-app/ # Tauri v2 shell
│ ├── lib.rs # one Arc<Mutex<Project>> shared by both surfaces
│ └── mcp.rs (+ mcp/) # embedded rmcp streamable-HTTP MCP server, auth, jobs
├── frontend/ # SvelteKit 3 / Svelte 5 (runes) / Tailwind 4 / shadcn-svelte
└── site/ # Hugo landing site (deployed to GitHub Pages)
| Layer | Choice |
|---|---|
| Shell | Rust + Tauri 2 |
| Frontend | SvelteKit 3 / Svelte 5 (runes), Bun |
| Styling | Tailwind CSS 4 (CSS config) + design tokens |
| Media | FFmpeg binaries (always) · ffmpeg-next 8.1 (optional libav) |
| Persistence | rusqlite (bundled SQLite) — one .kerf file |
| MCP | rmcp 3.1 (streamable-HTTP and stdio) |
The engine's export and timeline-still paths are pure and unit-tested — clip
positions, gaps, track layering, effects, keyframes, overlays, ducking and loudnorm all
render from data. See CLAUDE.md for a deep tour of the internals.
Kerf is a working editor under active development — not a scaffold. The timeline, preview, transcript, analysis, effects, keyframes, captions, playback and export are all wired to real backend state, and the MCP surface is exercised end-to-end.
Contributions welcome — see CONTRIBUTING.md.
PolyForm Noncommercial License 1.0.0 — free for noncommercial use.