• English
  • CutZal for AI agents

    CutZal is a local desktop editor for talking-head videos. The cutzal command reads and edits one CutZal project at a time.

    • When CutZal has the project open and its external connection is on, your edits go through the open app. The person sees them right away and can undo them.
    • When CutZal is closed, the command edits the project files directly (headless).

    Desktop channels

    Each app installs its own command and Skill from Settings. CutZal Dev uses a separate command and does not import Stable or Beta personal settings. Use the command installed by the app you want to use. Project files and the ~/.cutzal/run/ registry remain shared: a command routes to the app that owns the project, regardless of channel. Do not edit the same project simultaneously with older apps that do not enforce GUI ownership.

    Before you start

    • Pass --project as the video file path or its cutzal.json path.
    • The video must have been opened in CutZal once. That creates <video folder>/edit/cutzal.json. If you get project_not_found, ask the person to open the video in CutZal first.
    • stdout is one JSON object: {"ok": true, "result": ...} or {"ok": false, "error": {"code", "message", "details"?}}. Pass --json to always get JSON. Exit code 0 is success, 2 is a refusal you can read and fix, 1 is an unexpected failure.
    • Progress and "waiting for the person" lines go to stderr. Do not parse them.
    • Sandboxes: cutzal talks to the open app through a local socket in ~/.cutzal/run/ and writes project files next to the video. If your commands run in a sandbox, cutzal must run outside it. In Claude Code, add "cutzal *" to sandbox.excludedCommands in settings. A blocked socket shows up as connection_disabled with details.reason: "socket_blocked".

    Workflow

    1. cutzal status --project <video>: project.route is app (CutZal has it open) or headless.
    2. cutzal context --project <video>: current revision, durations, tracks and clips, assets, output segments, and the person's current screen state (ui; null headless).
    3. cutzal transcript --project <video>: every word with its source time and output time.
    4. Write the edit as JSON (see references/edits.md) and check it without applying: cutzal preview --project <video> --revision <N> --edit edit.json.
    5. Apply it: cutzal apply --project <video> --revision <N> --id <new id> --label "<what and why>" --edit edit.json.
    6. Check the result: cutzal capture --project <video> --at <seconds> and look at the PNG it writes.

    --edit - reads the JSON from stdin.

    To change the layout (camera only, screen with the camera in a corner, camera size or position), send a placement edit. context.placement names the screen and camera tracks. See references/edits.md.

    To fast-forward a long process that should be seen but not heard in full (reading a prompt aloud, typing, waiting), or to slow a part down, send a speed edit instead of cutting it. The screen, camera and clips that follow the speech change speed together and the sound is muted above 2x unless you keep it. { "speed": { "global": 1.2 } } speeds up the whole video. See references/edits.md.

    To change the frame size of the whole video (for example a horizontal video from a screen recorded on a vertical monitor), send { "canvas": "1920x1080" } (or "1080x1920", "original"). Recordings that were shown whole stay whole; then pick layouts with placement.

    To fix the sync of a recording (for example the voice is heard after the mouth moves), send an offset edit with the new value for that source from context.sources. Do not ask the person to close CutZal and do not edit cutzal.json: the edit goes through the open app and can be undone there. See references/edits.md.

    A video inserted with cutzal insert starts with its volume matched to the main audio. To make it louder or quieter, send a gain edit with the new value in dB for that take (inserted: true in context.sources). See references/edits.md.

    To make a vertical short (1080x1920) from a long video, clone the project with a vertical canvas: cutzal project clone --project <video> --name <short name> --canvas 1080x1920. It returns the new projectKey; run every later command on that path. The original project does not change, and the copy appears at the top of Recent projects in CutZal, where the person opens it. In the clone, cut everything outside the parts you keep (range edit with action: "cut" on output time; add the motion tracks that use output anchors to rippleTrackIds), then place the screen and camera for a 9:16 frame with placement edits (pos as {x, y}, sizePct: 1). Assets on the screen follow the screen frame when their clip uses placement: "screen". Check every part with capture before asking the person to export. Put the header as a text clip (title) so the person can edit the words in CutZal, and fix product names in subtitles with captionTerms on the transcript track (see references/edits.md).

    To place an image, B-roll or sound file, register it first with cutzal asset add (a sound from the library: cutzal sfx use) and use the returned id as assetId. Add the destination track before registering: images are refused until the project has had a track edit, and sound files (asset add of audio, sfx use) are refused until it has an audio track (track.add with "kind": "audio"). references/edits.md has the track edits and a full example.

    Rules

    • “Here” and “this part”: read context.ui.selection before interpreting a pointing instruction. Selections preserve separate source ranges and their output ranges; do not replace them with their outer bounds. Ask the person to select a range when the selection is empty. ui: null means headless, not an empty screen selection. Source times are on the original master timeline, not a physical file's clock. A deleted playhead position has output: null; repeated footage can have several outputCandidates, so ask which occurrence when it is ambiguous. Reading context does not move the playhead, select, scroll or transfer control.

    • Resume after the person edits: read session status, changes --since <lastRevision> and fresh context before continuing. Preserve human changes and the current selection; do not reapply an old plan over them. ui.control: "human" with a work means wait for return to the agent. Prefer session status for the current control decision: ui describes the snapshot just after its initial save, not continuous live state. If context returns busy or stale_revision, discard the snapshot and reread. Reading it never consumes the returned handback.

    • Editing session: for a sequence of edits in an open app, start with cutzal session start --project <project> --label "<task>" --agent codex --json (or claude-code, other). Pass its session as --session on subsequent project commands. Only that session can write while it holds control. When locked has reason: "human_control", wait and poll session status every 15 seconds. Resume only at control: "agent"; preserve the returned handback cuts, restores and settings changes. A null handback or handbackIncomplete requires rereading context/transcript. End with session end. An ended or unknown session needs a new start, never a blind retry. mode: "headless" has no registered lock, expiry or status/end; use per-command revision checks. If the app opens later, start a fresh app session.

    • Revision: always pass the latest --revision. Every applied edit, asset add, sfx use and rewind increases it. On stale_revision, read error.details.changes before replanning. Rows with actor.kind of human or phone are the person’s intent: preserve those edits, especially restored ranges (action: "keep"). Never just replace the revision and replay the old plan. Use cutzal changes --project <video> --since <last revision> between editing turns. If incomplete is true, any row has rangesIncomplete: true, or the actor is unknown, read current context and transcript and check with the person when intent is unclear. Empty ranges are not evidence that nothing changed.

    • Request ID: use a new --id for each new edit. Sending the same id with the same edit again is safe and returns duplicate. The same id with a different edit is id_conflict.

    • Label: --label names the checkpoint the person sees in CutZal. Say what you did in a few words.

    • Do not write project files: never edit cutzal.json or anything under edit/ directly, especially while CutZal is open. Use the commands.

    • Time: all times are seconds. Output time is the edited video; source time is the original recording. See references/coordinates.md.

    • Human confirmation: export, and a rewind that would also undo the person's own edits, open a confirmation in CutZal and wait up to 10 minutes. Tell the person what you asked for, then wait. Do not retry in a loop. declined means they said no.

    • Costs: ElevenLabs transcription, the local model download, and sound effect generation cost money or gigabytes. The person starts them in CutZal. This command never starts them. Free local transcription (cutzal transcribe) runs on this Mac once the person has downloaded the model, so you may run it when transcript says the project is not transcribed yet.

    • Review is the person's: cutzal review only reads. Tell the person which places to listen to first, but never mark them as confirmed. Only the person confirms in CutZal, so there is no command for it.

    • Undo: every applied edit is a checkpoint. cutzal checkpoints lists them and cutzal rewind goes back to the state before one of them. An insert is not a checkpoint and rewind cannot go back across it: to take an inserted video out, cut its block with a range edit, or ask the person to undo it in CutZal.

    Commands

    CommandWhat it does
    cutzal session startDeclares an external editing task and returns its session ID
    cutzal session statusReads whether the agent or person has control and any returned human edits
    cutzal session endEnds the external session after its in-flight writes finish
    cutzal statusLists running CutZal apps and, with --project, which route the project uses
    cutzal contextProject summary plus playhead, selections and editing control in the open app; ui: null headless
    cutzal changesReads who changed what since a revision, including missing history
    cutzal transcriptWords with source and output times, in a time window
    cutzal previewChecks an edit without applying it
    cutzal applyApplies an edit and makes a checkpoint
    cutzal asset addRegisters video, image or audio files as project assets
    cutzal insertInserts a video with its own sound at a point in the edited video, matches its volume to the main audio and pushes the rest later
    cutzal checkpointsLists checkpoints (the undo history)
    cutzal rewindGoes back to the state before a checkpoint
    cutzal captureRenders frames of the edited video to PNG files
    cutzal exportAsks the person to export in CutZal and returns output files and delivery quality checks
    cutzal sfx listLists the person's sound effect library
    cutzal sfx addAdds audio files to the sound effect library
    cutzal sfx useCopies a library sound effect into the project as an audio asset
    cutzal transcribeTranscribes the project for free on this Mac (local model)
    cutzal reviewLists the places the person should listen to first after an AI cut, and which ones they already confirmed
    cutzal finish-rulesExperimental, off by default. Reads the person's versioned finishing rules and pending candidates without changing them
    cutzal finish-checkExperimental, off by default. Checks saved audible sound effect placements against confirmed limits; warnings do not block export
    cutzal project cloneCopies a project as another project of the same media, optionally with a vertical 1080x1920 canvas for a short

    Options and result fields: references/commands.md.

    When something fails

    Read error.code. The common ones:

    • stale_revision: the project changed. Use the new revision and retry.
    • connection_disabled: CutZal has the project open with the external connection off. Ask the person to turn it on in CutZal Settings > Agent, or to close the project. With details.reason: "socket_blocked" the connection is on but your sandbox blocks it (see Sandboxes above).
    • busy: CutZal is in the middle of something or the person is looking at a dialog. Wait, then run the same command again. For apply and rewind keep the same --id; the other commands take no --id.
    • app_required: this needs the open app. Ask the person to open the project in CutZal and turn on the external connection.
    • invalid_edit or invalid_argument: fix the input using the message.

    All codes and what to do: references/errors.md.