harnessgg-kdenlive
Published v0.5.0CLI harness for AI agents to automate Kdenlive video editing. Create projects, edit timelines, apply effects and colour grades, and render, all with structured JSON output via a local bridge.
pip install harnessgg-kdenlive Agents can file bugs or feature requests with curl -X POST https://harness.gg/api/submit using "package":"kdenlive" in the JSON payload.
Prerequisite
Kdenlive must be installed. The harness uses a local bridge process to communicate with it. Python 3.10+ required.
$ harnessgg-kdenlive bridge start Always call bridge status before editing commands. Retry only on BRIDGE_UNAVAILABLE, backoff 0.5s, 1s, 2s.
Quick flow
# 1. Start the bridge $ harnessgg-kdenlive bridge start # 2. Verify stability $ harnessgg-kdenlive bridge status $ harnessgg-kdenlive bridge verify --iterations 25 # 3. Create a project and import media $ harnessgg-kdenlive create-project edit.kdenlive --title "Agent Edit" --overwrite $ harnessgg-kdenlive import-asset edit.kdenlive clip.mp4 --producer-id clip1 {"ok":true,"protocolVersion":"1.0","command":"import-asset","data":{"producerId":"clip1"}} # 4. Build the timeline $ harnessgg-kdenlive add-text edit.kdenlive "Opening Title" --duration-frames 75 --track-id playlist0 --position 0 $ harnessgg-kdenlive stitch-clips edit.kdenlive playlist0 clip1 clip1 --position 75 --gap 10 # 5. Generate a reusable matte, then replace the background $ harnessgg-kdenlive segment-person edit.kdenlive clip1 --zone-in 0 --zone-out 50 --quality balanced $ harnessgg-kdenlive replace-background edit.kdenlive clip1 --background-media plate.mp4 --matte-asset-ref matte_person_abc123 --track-id playlist_bg # 6. Validate then render $ harnessgg-kdenlive validate edit.kdenlive $ harnessgg-kdenlive render-project edit.kdenlive output.mp4 {"ok":true,"protocolVersion":"1.0","command":"render-project","data":{"jobId":"job_abc"}} $ harnessgg-kdenlive render-status job_abc
Schema examples
Each command returns one JSON object. Use ok for flow control and check error.code on failure.
{"ok":true,"protocolVersion":"1.0","command":"import-asset","data":{"producerId":"clip1"}} {"ok":false,"protocolVersion":"1.0","command":"render-project","error":{"code":"BRIDGE_UNAVAILABLE","message":"Bridge is not reachable","retryable":true}} Bridge commands
The bridge must be running before any editing or render call. It binds to 127.0.0.1 only.
bridge start harnessgg-kdenlive bridge start [--host <ip>] [--port <n>]
Start the local bridge server. Must be running before any editing commands.
| Flag | Required | Description |
|---|---|---|
--host | no | Bind address (default: 127.0.0.1) |
--port | no | Port (default: auto) |
bridge status harnessgg-kdenlive bridge status
Check whether the bridge is reachable and healthy. Run before mutating commands.
bridge verify harnessgg-kdenlive bridge verify [--iterations <n>] [--max-failures <n>]
Run a stability check against the bridge. Recommended before long editing sessions.
| Flag | Required | Description |
|---|---|---|
--iterations | no | Number of health pings (default: 25) |
--max-failures | no | Allowed failures before abort |
bridge stop harnessgg-kdenlive bridge stop
Shut down the bridge server.
Project commands
create-project harnessgg-kdenlive create-project <output> [--title <s>] [--width <n>] [--height <n>] [--fps <f>] [--overwrite]
Create a new Kdenlive project file.
| Flag | Required | Description |
|---|---|---|
--title | no | Project title |
--width | no | Frame width px |
--height | no | Frame height px |
--fps | no | Frames per second |
--overwrite | no | Replace existing file |
import-asset harnessgg-kdenlive import-asset <project> <media> [--producer-id <id>] [--dry-run]
Import a media file into the project bin.
| Flag | Required | Description |
|---|---|---|
--producer-id | no | Stable ID to reference this clip in other commands |
--dry-run | no | Preview without writing |
inspect harnessgg-kdenlive inspect <project>
Return a structured summary of the project, tracks, clips, duration.
validate harnessgg-kdenlive validate <project> [--check-files]
Validate project structure. Run before renders and after destructive edits.
| Flag | Required | Description |
|---|---|---|
--check-files / --no-check-files | no | Verify referenced media files exist (default: on) |
snapshot harnessgg-kdenlive snapshot <project> <description>
Save a named checkpoint. Use before risky edits; restore with undo.
undo / redo harnessgg-kdenlive undo <project> [--snapshot-id <id>] harnessgg-kdenlive redo <project>
Undo the last edit or redo it. Pass --snapshot-id to jump to a specific checkpoint.
| Flag | Required | Description |
|---|---|---|
--snapshot-id | no | Target snapshot (undo only) |
Timeline & editing commands
add-clip harnessgg-kdenlive add-clip <project> <clip_id> <track_id> <position> [--in-point <n>] [--out-point <n>] [--dry-run]
Place a clip on a track at the given frame position.
| Flag | Required | Description |
|---|---|---|
--in-point / --out-point | no | Trim the clip source range |
--dry-run | no | Preview without writing |
move-clip harnessgg-kdenlive move-clip <project> <clip_ref> <track_id> <position> [--dry-run]
Move a clip to a new track or position.
| Flag | Required | Description |
|---|---|---|
--dry-run | no | Preview without writing |
trim-clip harnessgg-kdenlive trim-clip <project> <clip_ref> [--in-point <n>] [--out-point <n>]
Adjust a clip's in/out points.
| Flag | Required | Description |
|---|---|---|
--in-point | no | New in-point frame |
--out-point | no | New out-point frame |
split-clip harnessgg-kdenlive split-clip <project> <clip_ref> <position>
Split a clip at the given frame, producing two clips.
ripple-delete harnessgg-kdenlive ripple-delete <project> <clip_ref>
Remove a clip and close the gap by shifting downstream clips.
stitch-clips harnessgg-kdenlive stitch-clips <project> <track_id> <clip_id...> [--position <n>] [--gap <n>]
Place a sequence of clips end-to-end on a track.
| Flag | Required | Description |
|---|---|---|
--position | no | Start frame (default: 0) |
--gap | no | Frames between clips |
add-text harnessgg-kdenlive add-text <project> <text> [--duration-frames <n>] [--track-id <id>] [--position <n>] [--font <s>] [--size <n>] [--color <hex>]
Insert a text title clip.
| Flag | Required | Description |
|---|---|---|
--duration-frames | no | Length in frames |
--track-id | no | Target track |
--position | no | Start frame |
--font / --size / --color | no | Typography overrides |
add-track harnessgg-kdenlive add-track <project> [--track-type video|audio] [--name <s>] [--index <n>]
Add a new video or audio track.
| Flag | Required | Description |
|---|---|---|
--track-type | no | video | audio |
--name | no | Track label |
--index | no | Insert position |
apply-effect harnessgg-kdenlive apply-effect <project> <clip_ref> <service> [--properties-json <json>]
Apply an MLT effect service to a clip.
| Flag | Required | Description |
|---|---|---|
--effect-id | no | Explicit ID for later reference |
--properties-json | no | Initial effect properties as JSON |
segment-person harnessgg-kdenlive segment-person <project> <clip_ref> [--zone-in <n>] [--zone-out <n>] [--quality fast|balanced|quality] [--preview-only]
Generate a reusable matte asset for a clip or zone. v1 is temporally smoothed but explicitly non-tracking.
| Flag | Required | Description |
|---|---|---|
--zone-in / --zone-out | no | Restrict processing to a clip-local frame range |
--quality / --model | no | Segmentation preset or explicit model id |
--feather-px / --shrink-grow-px / --temporal-radius | no | Edge cleanup and temporal smoothing controls |
--preview-only | no | Process representative frames only for QC |
replace-background harnessgg-kdenlive replace-background <project> <clip_ref> [--background-media <path>] [--matte-asset-ref <id>]
Swap a clip background using a generated matte asset or a manual mask setup.
| Flag | Required | Description |
|---|---|---|
--background-media / --background-producer-id | no | Use a plate file or existing producer |
--matte-asset-ref / --matte-mask-id | no | Generated matte asset or manual cleanup mask |
--track-id / --effect-id | no | Control the background track and compositing filter id |
apply-transition harnessgg-kdenlive apply-transition <project> [--in-frame <n>] [--out-frame <n>] [--service <s>]
Add a transition between two clips.
| Flag | Required | Description |
|---|---|---|
--in-frame / --out-frame | no | Transition range |
--service | no | MLT transition service name |
grade-clip harnessgg-kdenlive grade-clip <project> <clip_ref> [--lift <f>] [--gamma <f>] [--gain <f>] [--saturation <f>] [--lut-path <path>]
Apply a colour grade to a clip.
| Flag | Required | Description |
|---|---|---|
--lift / --gamma / --gain / --saturation | no | Grade parameters (-1.0 to 1.0) |
--lut-path | no | Path to a .cube LUT file |
duck-audio harnessgg-kdenlive duck-audio <project> <track_id> [--duck-gain <f>]
Apply audio ducking to a track.
| Flag | Required | Description |
|---|---|---|
--duck-gain | no | Gain reduction factor (default: 0.2) |
Render commands
Render calls are long-running. Timeout is 600s. Poll render-status until the job completes.
render-project harnessgg-kdenlive render-project <project.kdenlive> <output.mp4> [--start-seconds <f>] [--duration-seconds <f>] [--preset-name h264|hevc|prores]
Render the full project or a zone to a video file. Returns a job ID, poll render-status for progress.
| Flag | Required | Description |
|---|---|---|
--start-seconds / --duration-seconds | no | Render a subrange |
--zone-in / --zone-out | no | Render zone in frames |
--preset-name | no | h264 | hevc | prores (default: h264) |
render-clip harnessgg-kdenlive render-clip <source.mp4> <output.mp4> <duration_seconds> [--start-seconds <f>] [--preset-name h264|hevc|prores]
Render a standalone clip segment without a project file.
| Flag | Required | Description |
|---|---|---|
--start-seconds | no | Clip start offset |
--preset-name | no | h264 | hevc | prores |
render-status harnessgg-kdenlive render-status <job_id>
Poll the status and progress of a render job.
Full command list
Complete CLI surface from the package docs. Use this list for long-form planning or tool coverage audits.
# Bridge lifecycle $ harnessgg-kdenlive bridge start [--host 127.0.0.1] [--port 41739] $ harnessgg-kdenlive bridge serve [--host 127.0.0.1] [--port 41739] $ harnessgg-kdenlive bridge status $ harnessgg-kdenlive bridge stop # Bridge verification $ harnessgg-kdenlive bridge verify [--iterations 25] [--max-failures 0] $ harnessgg-kdenlive bridge soak [--iterations 100] [--duration-seconds 5] [--action system.health] # Core commands $ harnessgg-kdenlive actions $ harnessgg-kdenlive capabilities $ harnessgg-kdenlive doctor [--report-on-failure/--no-report-on-failure] [--include-render/--no-include-render] [--report-url] $ harnessgg-kdenlive plan-edit [--params-json ] $ harnessgg-kdenlive undo [--snapshot-id ] $ harnessgg-kdenlive redo $ harnessgg-kdenlive autosave [--interval-seconds 60] [--enabled/--no-enabled] $ harnessgg-kdenlive pack-project [--media-dir-name media] $ harnessgg-kdenlive recalc-bounds [--output out.kdenlive] $ harnessgg-kdenlive create-project [--title ] [--width 1920] [--height 1080] [--fps 30] [--overwrite] $ harnessgg-kdenlive clone-project [--overwrite] $ harnessgg-kdenlive inspect $ harnessgg-kdenlive validate [--check-files/--no-check-files] $ harnessgg-kdenlive diff $ harnessgg-kdenlive import-asset [--producer-id ] [--output out.kdenlive] [--dry-run] $ harnessgg-kdenlive add-text [--duration-frames 90] [--track-id ] [--position 0] [--font "DejaVu Sans"] [--size 64] [--color "#ffffff"] [--output out.kdenlive] [--dry-run] $ harnessgg-kdenlive update-text [--text ] [--font ] [--size ] [--color ] [--duration-frames ] [--output out.kdenlive] $ harnessgg-kdenlive asset-metadata $ harnessgg-kdenlive replace-asset [--update-name/--no-update-name] [--output out.kdenlive] $ harnessgg-kdenlive list-bin $ harnessgg-kdenlive create-bin-folder [--parent-id ] [--output out.kdenlive] $ harnessgg-kdenlive move-asset-to-folder [--output out.kdenlive] $ harnessgg-kdenlive segment-person [--zone-in ] [--zone-out ] [--model ] [--quality fast|balanced|quality] [--feather-px ] [--shrink-grow-px ] [--despill ] [--temporal-radius ] [--preview-only] [--output out.kdenlive] $ harnessgg-kdenlive set-mask-keyframes [--mask-id ] [--feather ] [--invert] [--output out.kdenlive] $ harnessgg-kdenlive set-effect-keyframes [--output out.kdenlive] $ harnessgg-kdenlive add-clip [--in-point 0] [--out-point 49] [--output out.kdenlive] [--dry-run] $ harnessgg-kdenlive move-clip [--output out.kdenlive] [--dry-run] $ harnessgg-kdenlive trim-clip [--in-point 0] [--out-point 49] [--output out.kdenlive] [--dry-run] $ harnessgg-kdenlive remove-clip [--close-gap] [--output out.kdenlive] [--dry-run] $ harnessgg-kdenlive split-clip [--output out.kdenlive] [--dry-run] $ harnessgg-kdenlive ripple-delete [--output out.kdenlive] [--dry-run] $ harnessgg-kdenlive insert-gap [--output out.kdenlive] [--dry-run] $ harnessgg-kdenlive remove-all-gaps [--output out.kdenlive] [--dry-run] $ harnessgg-kdenlive stitch-clips [--position ] [--gap 0] [--duration-frames ] [--output out.kdenlive] [--dry-run] $ harnessgg-kdenlive list-clips [--track-id ] [--producer-id ] $ harnessgg-kdenlive resolve-clip [--track-id ] [--at-frame ] $ harnessgg-kdenlive select-zone [--zone-in 0] [--zone-out 0] [--output out.kdenlive] $ harnessgg-kdenlive detect-gaps [--track-id ] $ harnessgg-kdenlive time-remap [--output out.kdenlive] $ harnessgg-kdenlive transform-clip [--geometry ] [--rotate ] [--scale ] [--opacity ] [--keyframes-json ] [--output out.kdenlive] $ harnessgg-kdenlive nudge-clip [--output out.kdenlive] $ harnessgg-kdenlive slip-clip [--output out.kdenlive] $ harnessgg-kdenlive slide-clip [--output out.kdenlive] $ harnessgg-kdenlive ripple-insert [--length ] [--clip-id ] [--in-point ] [--out-point ] [--output out.kdenlive] $ harnessgg-kdenlive group-clips [--group-id ] [--output out.kdenlive] $ harnessgg-kdenlive ungroup-clips [--output out.kdenlive] $ harnessgg-kdenlive list-sequences $ harnessgg-kdenlive copy-sequence [--new-id ] [--output out.kdenlive] $ harnessgg-kdenlive set-active-sequence [--output out.kdenlive] $ harnessgg-kdenlive list-effects $ harnessgg-kdenlive apply-effect [--effect-id ] [--properties-json ] [--output out.kdenlive] $ harnessgg-kdenlive update-effect [--output out.kdenlive] $ harnessgg-kdenlive remove-effect [--output out.kdenlive] $ harnessgg-kdenlive list-transitions $ harnessgg-kdenlive apply-transition [--in-frame 0] [--out-frame 0] [--service mix] [--transition-id ] [--properties-json ] [--output out.kdenlive] $ harnessgg-kdenlive remove-transition [--output out.kdenlive] $ harnessgg-kdenlive apply-wipe [--in-frame 0] [--out-frame 0] [--preset circle|clock|barn|iris|linear] [--transition-id ] [--softness ] [--invert] [--output out.kdenlive] $ harnessgg-kdenlive replace-background [--background-media | --background-producer-id ] [--producer-id ] [--matte-mask-id ] [--matte-asset-ref ] [--track-id ] [--effect-id ] [--output out.kdenlive] $ harnessgg-kdenlive add-music-bed [--track-id playlist1] [--position 0] [--duration-frames ] [--producer-id ] [--output out.kdenlive] $ harnessgg-kdenlive duck-audio [--duck-gain 0.3] [--output out.kdenlive] $ harnessgg-kdenlive audio-fade [--fade-type in|out] [--frames 24] [--output out.kdenlive] $ harnessgg-kdenlive normalize-audio [--target-db -14] [--output out.kdenlive] $ harnessgg-kdenlive remove-silence [--threshold-db -35] [--min-duration-frames 6] [--output out.kdenlive] $ harnessgg-kdenlive audio-pan [--output out.kdenlive] $ harnessgg-kdenlive grade-clip [--lift ] [--gamma ] [--gain ] [--saturation ] [--temperature ] [--lut-path ] [--output out.kdenlive] $ harnessgg-kdenlive add-track [--track-type video|audio] [--name ] [--index ] [--track-id ] [--output out.kdenlive] $ harnessgg-kdenlive remove-track [--force] [--output out.kdenlive] $ harnessgg-kdenlive reorder-track [--output out.kdenlive] $ harnessgg-kdenlive resolve-track $ harnessgg-kdenlive track-mute [--output out.kdenlive] $ harnessgg-kdenlive track-unmute [--output out.kdenlive] $ harnessgg-kdenlive track-lock [--output out.kdenlive] $ harnessgg-kdenlive track-unlock [--output out.kdenlive] $ harnessgg-kdenlive track-show [--output out.kdenlive] $ harnessgg-kdenlive track-hide [--output out.kdenlive] $ harnessgg-kdenlive snapshot $ harnessgg-kdenlive render-clip [--start-seconds 0] [--preset-name h264|hevc|prores] $ harnessgg-kdenlive render-project [--start-seconds ] [--duration-seconds ] [--zone-in ] [--zone-out ] [--preset-name h264|hevc|prores] $ harnessgg-kdenlive render-status $ harnessgg-kdenlive render-latest [--type project|clip] [--status running|completed|failed|canceled] $ harnessgg-kdenlive render-retry [--output ] $ harnessgg-kdenlive render-cancel $ harnessgg-kdenlive render-list-jobs $ harnessgg-kdenlive render-wait [--timeout-seconds 120] [--poll-interval-seconds 0.2] $ harnessgg-kdenlive preview-frame [--frame ] [--seconds ] $ harnessgg-kdenlive preview-contact-sheet [--frames-json ] [--count 4] [--start-frame 0] [--end-frame ] [--columns 3] $ harnessgg-kdenlive export-edl $ harnessgg-kdenlive export-xml $ harnessgg-kdenlive export-otio $ harnessgg-kdenlive batch [--stop-on-error/--no-stop-on-error] $ harnessgg-kdenlive version
Response shape
Every command emits exactly one JSON object to stdout. Check ok first.
Success
{
"ok": true,
"protocolVersion": "1.0",
"command": "add-clip",
"data": { "clipRef": "c3" }
} Error
{
"ok": false,
"protocolVersion": "1.0",
"command": "add-clip",
"error": {
"code": "INVALID_INPUT",
"message": "Track 'playlist99' not found",
"retryable": false
}
} Error codes
| Code | Exit | Retryable | Action |
|---|---|---|---|
BRIDGE_UNAVAILABLE | 5 | yes | Bridge not reachable. Run bridge start; retry with backoff 0.5s, 1s, 2s (max 3 retries). |
INVALID_INPUT | 4 | no | Bad or missing arguments. Fix the command before retrying. |
VALIDATION_FAILED | 3 | no | Project structure is invalid. Run validate and fix issues first. |
FILE_NOT_FOUND | 2 | no | Referenced file does not exist. Check paths. |
INTERNAL_ERROR | 1 | yes | Unexpected error. Retry once; if it persists, file a bug. |
Submit feedback
Agents can file bug reports and feature requests via POST /api/submit.
Issues land on harnessgg/harness-kdenlive.
| Field | Required | Values |
|---|---|---|
type | yes | "bug" | "feature" | "question" |
package | yes | "kdenlive" |
title | yes | Short summary |
body | yes | Full description |
context | no | Bridge version, OS, project details… |
$ curl -X POST https://harness.gg/api/submit \
-H "Content-Type: application/json" \
-d '{"type":"bug","package":"kdenlive","title":"bridge fails on start","body":"Steps..."}'