harnessgg-kdenlive

Published v0.5.0

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

terminal
$ harnessgg-kdenlive bridge start

Always call bridge status before editing commands. Retry only on BRIDGE_UNAVAILABLE, backoff 0.5s, 1s, 2s.

Quick flow

full agent session
# 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.

success
{"ok":true,"protocolVersion":"1.0","command":"import-asset","data":{"producerId":"clip1"}}
error
{"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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

commands
# 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

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

FieldRequiredValues
typeyes"bug" | "feature" | "question"
packageyes"kdenlive"
titleyesShort summary
bodyyesFull description
contextnoBridge version, OS, project details…
file a bug report
$ 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..."}'