Skip to content
OrellBuehlerPublic

About

AI-assisted video & audio editor — Rust + Tauri, with an MCP server that lets Claude cut and assemble your footage.

Topics

Resources

Contributing

Stars

11 stars

Watchers

0 watching

Forks

Repository files navigation

Kerf

Kerf

The non-destructive video editor your AI can drive.

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

CI Release License Rust Tauri Stars

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.


Why Kerf is different

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) and skim_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 Project behind 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/ffprobe binaries, so probe, analysis, frames, waveforms, and export all work on a plain install — the in-process libav path is optional.

Features

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.

Quickstart

Download a build

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.

Or build from source

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.


Driving Kerf from an LLM

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.

Headless

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.

Hosting: media in and out

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.mp4

The 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.

Use as a stdio MCP server (Claude Code plugin, any client that launches its server)

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.

The tools (207)

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.


Building

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-dev
macOS
xcode-select --install            # Command Line Tools (provides clang)
brew install ffmpeg pkg-config    # FFmpeg dev libraries + pkg-config
Windows

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).

Without the FFmpeg dev libraries

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-features

Two 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).


Architecture

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.


Status

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.

License

PolyForm Noncommercial License 1.0.0 — free for noncommercial use.

About

AI-assisted video & audio editor — Rust + Tauri, with an MCP server that lets Claude cut and assemble your footage.

Topics

Resources

Contributing

Stars

11 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages