Skip to main content
Glama
NOTE

WeftCut is still under active development, so some features and UI/UX may change before v1.0.0. Join us to improve the project: start with thecontributing guide.

An agent editing the timeline live over MCP

Most editors bolt AI on as a feature: a button that generates something, a sidebar that suggests a cut. WeftCut exposes the editor itself as a tool surface. A localhost MCP server publishes all editing tools — place, trim, split, restyle, keyframe, group, caption, mix, checkpoint — and whatever agent you already have open drives them. The intelligence lives outside the app: the installer bundles no model weights, and the local engines for speech and vision are an opt-in download when you want them.

None of that rides on a stripped-down editor. Everything an agent can reach, you can do by hand, in a full NLE: A/B-roll timeline, keyframes with a curve editor, effects, captions, a role-based audio mixer, and hardware-accelerated export.

Quick start

NOTE

We don't have a verified macOS installer yet, so allow it under System Settings → Privacy & Security → Open Anyway

  1. Download the installer for your platform from the releases page.

  2. Install the app, open the settings panel, and copy the prompt that teaches your agent how to connect to WeftCut.

  3. Enjoy your work.

Related MCP server: opencut-mcp

Hand your timeline to an agent

Copy the prompt in settings into your client, and your agent is holding the editor.

  • It edits the project you are watching. No import/export round trip, no separate headless copy.

  • Every batch is reversible. A work session begins with a checkpoint that is one click from being restored, and every edit the agent commits is a step of your undo history.

  • Multi-agent, with rules. Sessions are per-connection. A work session locks undo for everyone but its agent, so a stray Ctrl-Z doesn't land in the middle of its work — the lock and the reason it gave are shown to you, and Unlock is yours.

Watch and review in Agent view

For a longer run, the agent can call begin_agent_session to open Agent view: a preview, a compact review timeline, and an Agent panel with Activity, Tacks and Changes tabs. Follow its tool calls in Activity while you watch the edit play, discuss specific passages with Tacks, then audit the result with Timeline diff in Changes. You can return to the full editor at any time.

Agent view with added, removed and modified clips and titles in the Changes panel, plus change and Tack ranges across the review timeline

Agent view after an editing pass: Changes lists additions, removals and modifications. The timeline shows them in green, red and yellow, with Tack ranges in teal.

Tacks give the conversation a place. An agent leaves a note, issue or question on a time range; you locate and play it, then resolve, dismiss or convert the Tack into a marker to keep. Tacks follow the content they cover and become outdated when what plays there changes, including on other tracks. The agent can read their statuses and receives feedback when its edits affect its open Tacks.

Timeline diff shows the result of the work. Open Changes to compare the current project with the state when you opened it or last chose Approve all. Inspect additions, removals and modifications, with before/after details and timeline highlights. Approve all makes the result your new review baseline; Revert all restores that baseline in one undoable step. Both include your own edits since the baseline.

Try: “Find the pauses in this interview and leave Tacks on the ones worth cutting. Let me review them before you edit.” Review the passages, tell the agent which cuts to make, then use Timeline diff to approve or revert the result.

Tacks last only for the current project opening. They are not saved or exported, and managing them adds nothing to undo history.

Agent: create_tacks · read_project { view: "tacks" } · update_tack · delete_tacks

Code as video: Motifs

A Motif is an on-screen element written as code — a real web page (HTML, CSS, SVG, canvas, WebGL, whatever you reach for) dropped on the timeline as a layer. It isn't a fixed preset: the author declares the knobs, and the inspector builds the form from that declaration, so seconds, label and accent below are editable in the app.

The one rule that makes it an editor feature instead of a screen recording: a Motif renders as a pure function of time. It never advances itself. The harness owns the clock and drives the page to each composition frame, so the same t always yields the same pixels — when you scrub, when you re-export, and in preview and export alike.

// The built-in Countdown's whole script, near enough verbatim — the rest of the
// file is the SVG ring it animates. `props` is whatever the manifest declares;
// `frame` runs once per composition frame and keeps no state of its own.
motif.define({
  setup: async function (props, ctx) {
    _label = props.label != null ? String(props.label) : "GO";
    num.style.color = props.accent;
    ring.style.stroke = props.accent;
    ring.setAttribute("stroke-dasharray", C);
    ring.animate([{ strokeDashoffset: 0 }, { strokeDashoffset: C }],
      { duration: ctx.duration * 1000, easing: "linear", fill: "both" });
  },
  frame: function (t, ctx) {
    var n = Math.max(0, Math.ceil(ctx.duration - t));
    num.textContent = n > 0 ? String(n) : _label;
  },
});

A Motif on the timeline, with its props in the inspector

Writing a web page is the thing coding agents are already best at — so an agent can author a brand-new overlay for your edit instead of picking one from a catalog. The authoring spec ships inside the app as an agent skill, so the model gets the contract without you pasting documentation.

Lower thirds, countdowns, karaoke text and animated title cards are the obvious uses. Anything you can build on a page is the actual limit.

A complete editor underneath

WeftCut editor

Timeline — A/B-roll rows with filmstrips and waveforms, frame-accurate SMPTE editing, ripple delete that closes the gap behind it, linked A/V that trims as one clip, cross-track groups, and nested compositions. Agent: move_layers · trim_layer · split_layer · shift_layers · create_link · create_group · move_layers_to_composition

Keyframes — animate any parameter, with bézier easing, a curve editor, tangent control, motion paths and extrapolation. Agent: set_keyframe · update_keyframe · set_param_track · get_param_track

Speech and captions — transcribe a clip and get editable caption layers packed onto your caption tracks; import SRT/VTT/ASS into the media pool and drop it where it starts. Transcription runs against a cloud provider, or entirely on your machine once you let the app fetch a local engine (whisper.cpp, FunASR) — or an agent can pull the raw audio out and run its own model. Text-to-speech for scratch voiceover. Agent: transcribe_clip · extract_clip_audio · apply_transcripts · apply_subtitles · synthesize_speech

Audio — role-based mixing (dialogue / music / SFX / voiceover) with live per-role metering, gain, pan, fades and denoise. Pauses finds the dead air in a take and cuts it as one undoable edit, keeping a pad so speech still breathes. Agent: detect_pauses · remove_pauses · set_role_gain · set_role_flags

The Role Mixer console, metering during playback

Understanding the footage — shot-boundary detection with per-shot brightness, motion and sharpness, frame comparison, and vision-model descriptions of what a clip actually contains. An agent can cut on content, not just on timecode. Agent: analyze_clip · auto_split_by_shot · describe_clip · compare_frames

Titles, effects and transitions — styled text layers with outlines, per-layer effect chains including chroma key with an eyedropper that picks from the live frame, and transitions between clips. Agent: add_effect · update_effect · add_transition · update_transition

Export — H.264 / HEVC / AV1, hardware or software encoders, resolution / fps / quality controls, and streamed muxing.

Find anything — one Ctrl+K palette over commands, media, clips, captions and markers, search for whatever you want.

Search palette

Tech stack

Layer

Stack

Shell

Electron 44 · TypeScript 7 · electron-vite · Vite 8 · Node 24

UI

React 19 · Zustand · Immer · Tailwind CSS v4 · Base UI · shadcn/ui · Dockview · lucide · i18next (en-US / zh-CN) · fuzzysort

Preview

PixiJS v8 · WebGPU / WebGL · WebCodecs VideoDecoder pool · mediabunny · own YUV→RGB shaders · Web Audio clock

Export

Worker + OffscreenCanvas · GPU YUV pack pass · PBO readback · rawvideo over IPC · native ffmpeg sink · WebCodecs encoder (pin) · stream-copy mux

Native core

Rust · napi-rs 3 · Tokio · imbl · serde · schemars · blake3 · reqwest · ffmpeg-sidecar

Native decode

@weftcut/native-decode · ffmpeg-next · software + GPU lanes · sharedTexture (Windows)

Shared math

weftcut-eval crate · native + wasm32 · snap · keyframe eval · envelope · role gate

ffmpeg

GPL CLI sidecar (jobs, encode, mux) · LGPL shared libs (in-process decode)

Agent surface

MCP · streamable HTTP on localhost · @modelcontextprotocol/sdk · bearer token · TS + Rust tool catalog

Motifs

Offscreen BrowserWindow · Chrome DevTools Protocol · motif: scheme · CSP default-src 'none'

Speech & vision

Cloud providers over reqwest · whisper.cpp · FunASR · on-demand model download

Tests & CI

Vitest · cargo test · Playwright · node --test · Stryker · GitHub Actions (Windows / macOS / Linux)

Design decisions: ADRs.

Build from source

Prerequisites: Node 24+, Rust (version pinned by rust-toolchain.toml, installed via rustup), and your platform's C/C++ build tools and libclang — per-OS commands in docs/setup.md.

npm install       # JS dependencies
npm run bootstrap # one-time: fetch ffmpeg + build the Rust addons
npm run dev       # start the editor

Also useful: npm run typecheck, npm test, npm run e2e, npm run build, npm run package (installers).

Documentation

Start with architecture for the system map, or MCP server & agent UX for the tool surface, resources and multi-agent behavior. Motifs and motif authoring cover the overlay engine and its contract.

  • Data model — project state schema, history, persistence, validation.

  • Render — PixiJS + WebCodecs renderer architecture.

  • Preview — interactive preview surface and transport.

  • Export — export pipeline, settings and range, audio, finalization, export jobs and presets.

  • Captions · Audio — caption ingestion and the audio engine.

  • Conformance — E2E gates that export real media and check frame alignment, audio sync and colour.

  • Features — the concrete behavior of each editor capability: selection, links, groups, ripple delete, markers, shot review, pauses, search, gizmo, crop.

  • Status / log system — the bottom-of-editor log bus.

  • Setup — per-OS toolchain prerequisites and first-run flow.

  • Licensing — MIT app plus the two FFmpeg lanes and their build-time compliance gates.

  • v1 target — release scope and open work, tracked as an issue: docs/ describes what exists today.

Community

Join the WeftCut Discord community to share feedback, discuss feature ideas, and get help. Please use GitHub Issues for bug reports and feature requests so they can be tracked. Before opening a pull request, read the contributing guide.

Maintainer

WeftCut is built and maintained by UncleChair.

It exists to speed up my own video work. I wanted an editor an agent could actually drive, and a timeline I could keep watching while it did — so the MCP surface is the part I use daily, not a demo bolted onto the side. Motifs came from the other half of that: the overlays I wanted were easier to write than to find, and an agent that can write a web page can write one for the shot in front of it.

The project sits under the WeftCut organization so the name, domain and releases have a stable home, but it is a one-person project — issues and pull requests all reach me.

Star History

License

WeftCut is licensed under the MIT License. Packaged installers bundle FFmpeg binaries under their own licenses (LGPL shared libraries for in-process decode, GPL command-line tools run as a separate process) — see THIRD-PARTY-NOTICES.md and docs/licensing.md for the full model.

Available Tools

100 tools
add_effectA

Append an effect to a layer's chain (applied last), with params as plain numbers, and return its record (effect_id, kind, index, params). An unset param is its catalog default (effects://catalog: every kind's params, defaults and ranges), and can be keyframed at once as effects[<effect_id>].params[<key>]. Visual kinds ("blur", "chromakey", "brightness", "contrast", "saturation", "sharpen") go on visual layers; the colour trio and sharpen default to 0, no change; chromakey's key colour keyR/keyG/keyB is 0..1, not 0..255. audio.* kinds go on Audio layers ONLY, params STATIC ONLY (AudioEffectParamStatic); a kind on the wrong layer kind is EffectKindNotApplicable. "audio.denoise" (strength, margin dB) does nothing until profile_in_us/profile_out_us, SOURCE-time bounds of a noise-only span ≥ 250000 µs, are set.

NameRequiredDescriptionDefault
kindYesCatalog key: visual kinds on visual layers, audio.* on Audio layers.
paramsNoInitial values, param key → number, each within its catalog range, e.g. {"amount": -20}. Omitted keys take the catalog default.
layer_idYesLayer id.

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false and destructiveHint=false, so the description must supply the rest. It does add real behavioral context, such as catalog defaults, the audio params STATIC ONLY restriction, and the denoise profile_in_us/profile_out_us requirement with a 250000 µs minimum. It omits ordering or chaining side effects for the existing chain and does not say whether the append is atomic or reversible.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded with the action and the return shape, and nearly every clause carries operational information. The long parentheticals and backtick-heavy sentences make it dense to parse, but there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by naming the returned record fields and the failure mode EffectKindNotApplicable. Combined with the catalog reference for ranges and defaults, it is complete enough to call correctly, though it does not cover whether appended effects can be reordered afterwards.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, yet the description adds meaning the schema lacks: unset params fall back to catalog defaults, values are plain numbers, chromakey keyR/keyG/keyB are 0..1 rather than 0..255, and audio params cannot be keyframed. The keyframing path effects[<effect_id>].params[<key>] is described nowhere in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb, resource, and placement: "Append an effect to a layer's chain (applied last)", and then names the returned record fields. An agent can distinguish this from update_effect, move_effect, and delete_effect because the append/applied-last semantics are stated explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives strong applicability rules: visual kinds go on visual layers, audio.* kinds go on Audio layers ONLY, and a mismatch raises EffectKindNotApplicable. It does not explicitly route to update_effect or set_keyframe as alternatives for later changes, so it stops short of full when-to-use/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_group_membersA

Move selected clips into an existing Group while preserving external placement. Requires Group rate 1 and compatible selection. Refuses partial links, locked members and cycles. Returns the resulting Group.

NameRequiredDescriptionDefault
layer_idsYesThe layers to move in; at least one, all in one composition.
group_layer_idYesThe Group clip they move into — a `CompositionRef` layer in the SAME composition as the members.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the supplied annotations by disclosing preservation of external placement, refusal conditions, and the return value. These details materially help an agent predict behavior for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action, then preconditions, refusal cases, and return value in a compact sequence. Every sentence contributes useful information with no padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Complete enough for a two-parameter mutation tool: it explains the action, prerequisites, failure modes, and return value despite no output schema. The unexplained 'compatible selection' and 'Group rate 1' keep it just short of fully self-contained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents both parameters. The description still adds operational meaning with the Group rate 1 requirement and compatible-selection constraint, though those constraints remain somewhat vague.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: moving selected clips into an existing Group. It clearly distinguishes this from create_group and ungroup_layer by emphasizing an existing Group and preserved external placement.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operating conditions: Group rate 1, compatible selection, and refusal cases for partial links, locked members, and cycles. It does not explicitly name sibling alternatives such as create_group, but the when-to-use context is strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_layersA

Place 1–50 layers in ONE recorded edit, all or nothing: any refusal commits none. content.kind picks what each layer is. A layer without track_id gets a fresh track in the same edit; layers on one lane cannot overlap. A Video with an audio stream also lands its dialogue Audio on the same track's audio lane, linked (audio); an occupied audio lane refuses naming the blocker. Audio-only media is kind audio, a still kind image; a subtitle document is apply_subtitles. Returns { layers: [{ layer_id, track_id, t_start_us, t_end_us, adjusted, linked }] } in input order; adjusted lists grid snaps, linked is { audio_layer_id, link_id } or null.

NameRequiredDescriptionDefault
layersYesThe layers, placed in order.
composition_idNoComposition a layer without `track_id` opens its track in (a Group's id); omit for the root. A named track must belong to it.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false and destructiveHint=false, so the description carries the real burden and does: transactionality ('any refusal commits none'), lane-overlap refusal, auto-placement of a Video's dialogue audio as a linked layer, refusal of an occupied audio lane 'naming the blocker', and implicit track creation in the same edit. It also spells out the exact return shape including `adjusted` and `linked`, which no output schema supplies.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the atomicity guarantee and the batch limit, then walks through kind selection, track behavior, audio linking, and return shape in a logical order with zero filler. It is a single dense paragraph that leans on semicolons, and a few clauses echo the schema's enum descriptions, so it is tight but not maximally efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex batch-mutation tool with nested discriminated content, it covers atomicity, refusal semantics, track auto-creation, linking side effects, ordering of results, and the return payload — everything an agent needs to call it without follow-up. With no output schema present, the inline return description closes the last gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline would be 3; the description earns above that by adding cross-parameter constraints the schema does not encode — that layers on one lane cannot overlap, that a missing `track_id` creates a fresh track within the same edit, and that the audio lane is shared between linked picture-and-dialogue pairs. Some of it (kind → layer type) merely restates the discriminated union, keeping it below a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with a distinguishing property: 'Place 1–50 layers in ONE recorded edit, all or nothing'. The batching-plus-atomicity framing separates it from single-layer siblings like update_layer_params or paste_layers without the agent needing to inspect any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete routing rules: 'Audio-only media is kind `audio`, a still kind `image`; a subtitle document is `apply_subtitles`' — the last one explicitly hands the agent to a sibling tool. It does not, however, say when to prefer this over paste_layers or create_group for the same outcome, so the alternative-selection guidance is incomplete rather than absent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_markerA

Add a marker (point or region) to a composition's timeline — the root, or the Group named by composition_id. Returns the marker record (marker_id, t_us as snapped). Set t_end_us to make it a region marker. Set anchor_layer_id to have the mark FOLLOW a clip instead of standing at a fixed time; omit it for an ordinary marker. color defaults to the timeline's marker blue.

NameRequiredDescriptionDefault
noteNoLong text, shown only in the marker panel.
t_usYesMarker time, timeline, µs.
colorNoMarker colour; omit for the default.
labelYesShort name shown on the marker lane.
t_end_usNoRegion end, timeline; omit for a point marker, µs.
composition_idNoComposition to create in — a Group's id from `project://compositions`; omit for the root.
anchor_layer_idNoClip the marker should follow — a layer of the same composition with a source window (VideoClip, Audio, Group). Tied as `set_marker_anchor` would tie it, refused for the same reasons (no marker is created). Omit for a fixed marker.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false and destructiveHint=false, so the description carries the real behavioral load and does so: it discloses the return record (marker_id, t_us) and, importantly, that t_us is returned 'as snapped' — a non-obvious side effect an agent would otherwise miss. It also notes that an invalid anchor is refused with no marker created, though it says nothing about permissions or duplicate-marker behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and target, then each subsequent sentence handles exactly one decision (region, anchor, color). No filler, no repetition of the name, and the most consequential fact (the return record) appears early.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter mutation with a nested color object and no output schema, the description covers the return shape, the snapping behavior, and both optional modes, which is most of what an agent needs. Gaps are minor but real: nothing on permissions, on whether markers may overlap or duplicate, or on ordering relative to other timeline edits.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so 3 is the baseline, but the prose adds genuine framing: it recasts t_end_us and anchor_layer_id as selecting between point/region and fixed/following modes rather than merely documenting types. It also states the color default, which the schema only gestures at with 'omit for the default.'

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('Add a marker (point or region)') plus the exact target ('a composition's timeline — the root, or the Group named by composition_id'). It also enumerates the two marker variants, which lets an agent distinguish this from update_marker, delete_marker, and set_marker_anchor without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear conditional guidance for the optional modes: set t_end_us for a region, set anchor_layer_id to make the mark follow a clip, omit it for an ordinary marker, and color falls back to the timeline default. It stops short of stating when to use this versus modifying an existing marker with update_marker or tying an anchor later with set_marker_anchor.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_trackA

Add a track and return its record (track_id, index, composition_id). Tracks are kind-agnostic — any layer kind goes on any track. A track disappears when its last layer leaves it (deleted or moved away), so place a layer rather than reserving a track; a track created empty survives until it has been filled and emptied.

NameRequiredDescriptionDefault
labelNoOptional name. Omit it and the track is displayed by its position in the stack, which renumbers as tracks come and go.
composition_idNoComposition to create in — a Group's id from `project://compositions`; omit for the root.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare non-destructive and closed-world; the description adds the substantive lifecycle rule that a track vanishes when its last layer leaves it, and that a track created empty survives until filled and then emptied. That is genuine behavioral context an agent could not get from the annotations or schema. The final clause is a little dense but still discloses real state semantics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action and return fields, then follows with behavioral caveats, so an agent gets the essentials in the first clause. The final sentence ("survives until it has been filled and emptied") is somewhat convoluted and partially restates the prior sentence, costing a point.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully names the return fields, and with no required parameters and only two optional ones, little else is needed. The lifecycle note covers the main non-obvious risk (empty tracks disappearing), leaving only minor gaps like ordering or error behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and both `label` and `composition_id` are already documented in the schema with their defaults and lookup path. The description adds no additional meaning about these parameters, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Add a track") and even enumerates the returned record fields (`track_id`, `index`, `composition_id`), which makes the operation unambiguous. It does not explicitly distinguish itself from creation-adjacent siblings such as `create_tacks` or `add_layers`, so sibling differentiation is left implicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete guidance on the right workflow: "place a layer rather than reserving a track," which steers the agent away from pre-creating empty tracks. It stops short of naming an explicit alternative tool or stating when to use `create_tacks` instead, so no exclusions are spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_transitionA

Add a transition at the cut between two adjacent layers on the same track — from_layer_id (outgoing) ends exactly where to_layer_id (incoming) starts — and return its record. kind 'Crossfade' (default) | 'Wipe' | 'Slide'; direction is the MOTION direction ('left' = the boundary or the sliding content moves left), required for Wipe/Slide and rejected for Crossfade. placement 'overlap' (default) moves the INCOMING layer left by the frame-rounded duration so both still play exactly their trimmed ranges and the vacated span stays a gap — nothing ripples; link siblings follow, bouncing to a free lane. 'extend' instead borrows outgoing tail media past its out-point, positions untouched (extended_us = duration), refused with TransitionInsufficientHandle { available_us } when the tail is short. A pair already overlapped by exactly the duration attaches as-is. Refuses: participants sharing a link, a move crossing t = 0, a duration longer than either participant, an Audio participant (TransitionUnsupportedLayerKind). Recorded — one undo restores every moved layer.

NameRequiredDescriptionDefault
kindNoDefault Crossfade.
directionNoMotion direction. Required for Wipe / Slide, refused for Crossfade.
placementNo'overlap' (default): the incoming layer moves left, trimmed ranges preserved. 'extend': the outgoing layer borrows tail media, positions untouched.
duration_usYesTransition length, µs.
to_layer_idYesIncoming layer — the one that starts at the cut.
from_layer_idYesOutgoing layer — the one that ends at the cut.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false and destructiveHint=false, so the description carries the burden and does it well: 'overlap' moves the incoming layer with no ripple, linked siblings follow and bounce to a free lane; 'extend' borrows outgoing tail media and returns extended_us; failures surface as TransitionInsufficientHandle and TransitionUnsupportedLayerKind; one undo restores every moved layer.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and participants are front-loaded, and nearly every clause conveys a distinct constraint or side effect. It is still a dense wall of em-dashed, bolded fragments that takes effort to parse, and the placement explanation could be tightened without losing content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutating timeline tool with no output schema, the description covers return value ('its record'), both placement behaviors, the exact-overlap no-op case, four refusal classes, and undo granularity. An agent has everything needed to call it correctly on the first attempt.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all six parameters and the baseline is 3. The description does add genuine meaning beyond it — 'direction' is the MOTION direction with a concrete worked reading of 'left', and the placement modes describe what each does to positions and trimmed ranges — but much of this overlaps the enum descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource plus the exact precondition: a transition at the cut between two adjacent layers on the same track, with from_layer_id ending where to_layer_id starts. This distinguishes it cleanly from the sibling update_transition and delete_transition without needing to open any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear in-context routing for the three variants ('kind' default Crossfade, 'direction' required for Wipe/Slide and rejected for Crossfade) and enumerates refusal conditions. It does not explicitly name a sibling alternative (e.g. use update_transition to modify an existing one), so it stops short of full when-to-use/when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

analyze_audioA
Read-only

Analyze original source audio from cached waveform peaks; local, read-only, no model. Returns bounded peak/RMS waveform bins, onset candidates and signed energy changes (dB), all in source µs (src_*), plus resolution and event counts. Choose music edit/alignment points, including outside a clip's trim. These are amplitude measurements, not beats, bars or melody recognition. At most 60 s per call; max_points affects only the summary. Peaks are cache-limited, not true-peak or LUFS. To land src_us at timeline T on a layer: src_in_us = src_us - (T - t_start_us) * rate (rate from project://tracks, 1 when absent).

NameRequiredDescriptionDefault
media_idYesImported Audio or Video media id; analyzes its original audio before mix/effects.
max_pointsNoMaximum waveform summary bins, 1..1000 (default 200). Does not change event detection resolution.
src_end_usNoSource-absolute end, exclusive. Default start + 60 seconds, capped at media end. At most 60 seconds per call.
src_start_usNoSource-absolute start in microseconds, inclusive. Default 0.
onset_threshold_dbNoMinimum short-time energy rise for onset candidates, 1..30 dB (default 6). Candidates are not beats or melody labels.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond readOnlyHint/openWorldHint by disclosing that it is local, model-free, cache-derived, and explicitly not true-peak or LUFS, and that max_points affects only the summary. The formula for landing src_us at timeline T and the 60 s cap are real operational constraints an agent cannot infer elsewhere. No output schema exists, however, so the return-shape disclosure (peak/RMS bins, onset candidates, dB deltas, counts) is present but terse.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded: capability, scope, return shape, then caveats, then the coordinate note. Dense and largely waste-free, though the trailing parenthetical formula is telegraphic and harder to parse than the rest.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description does the work of naming the returned fields and units, and it flags the cache dependency and per-call duration ceiling. It omits what happens on a cache miss or for uncached media, a gap for an analysis tool an agent may call repeatedly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3; the description earns extra by clarifying that max_points changes only summary bins and not event detection resolution, and that src_* values are source-absolute microseconds. The rate/t_start_us mapping formula adds cross-tool meaning the schema does not carry.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Analyze original source audio from cached waveform peaks') plus scope ('original audio before mix/effects'), and explicitly rules out what it is not ('amplitude measurements, not beats, bars or melody recognition'), which separates it from siblings like detect_pauses and transcribe_clip. It never names a sibling directly, so differentiation is by category rather than by tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Choose music edit/alignment points, including outside a clip's trim' gives a concrete when-to-use context, and 'At most 60 s per call' plus the src_us mapping formula imply the chunking workflow. It stops short of explicit when-not guidance or naming the alternative tool for beat/key/tempo needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

analyze_clipA
Read-only

Shots and defect spans of a video's source, deterministic. media_id: a pooled item, placed or not, whole; layer_id: a VideoClip, clipped to the source it plays, plus its mapping (t = t_start_us + (src - src_in_us) / rate). Returns { media_id, mapping?, shots: [{ index, src_start_us, src_end_us, src_keyframe_us, brightness, motion, sharpness, flags }], cut_scores: [{ src_us, score }], spans? }, source µs; score 0..1. Stats from 3 frames/shot: brightness midpoint mean luma 0..1; motion 1 - SSIM of the end frames; sharpness Laplacian variance, relative per source. flags: "black" (all 3 < luma 0.02), "freeze" (SSIM >= 0.985), "fade" (monotonic luma ramp >= 0.15 touching < 0.10). Dark/blurry/frozen spots in shots: passes: ["spans"] samples every step_us into spans: [{ kind, src_start_us, src_end_us, value }]: "dark" luma < 0.08 >= 0.5 s (value: mean), "soft" sharpness < 35% of source median >= 1 s (value: ratio), "frozen" adjacent SSIM >= 0.985 >= 1 s (value: min). passes default shots, stats, events; ["shots"] = timing only. To split: auto_split_by_shot.

NameRequiredDescriptionDefault
passesNoWhich passes to run. Default shots, stats, events; `["shots"]` is timing only (no frame sampling). `"spans"` is opt-in: one sampled decode of the source for dark / soft / frozen spans.
step_usNoThe spans pass's sampling step (microseconds), 100000..=10000000. Default 500000. Needs `"spans"` in `passes`.
layer_idNoA VideoClip: the answer is clipped to the source it plays and carries its `mapping`.
media_idNoA pooled video, scanned whole (placed or not).
min_shot_usNoMinimum shot duration (microseconds); cuts closer than this are merged. Default 500000 (0.5 seconds).
sensitivityNoCut sensitivity in [0.0, 1.0]: a frame whose shot-change score exceeds this starts a new shot. Lower = more (finer) cuts. Default 0.4.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds genuine behavioral context: determinism, the 3-frames-per-shot sampling basis, that 'spans' requires 'one sampled decode of the source' (a cost signal), and exact numeric thresholds behind every flag and span kind. It omits error behavior and any runtime/performance expectation for the default passes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Everything present is substantive — return shape, stat formulas, flag and span thresholds — and the purpose is front-loaded. However, it is delivered as one dense semicolon-chained paragraph in heavy backtick notation, making it hard to scan for the one or two facts an agent needs at call time. No sentence is wasted, but structure is not doing the reader any favors.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description correctly carries the full return-value burden: it enumerates the response fields, defines every stat (brightness midpoint mean, motion as 1 - SSIM, sharpness as relative Laplacian variance), and specifies each flag and span kind with thresholds. An agent can interpret results without any external documentation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description exceeds it by supplying the mapping formula (t = t_start_us + (src - src_in_us) / rate) and by tying media_id/layer_id to their scoping difference (whole source vs clipped-to-played-range). It largely restates the schema's own parameter descriptions, so it is additive rather than transformative.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening states a specific resource and output: 'Shots and defect spans of a video's source, deterministic.' It is a noun phrase rather than a verb+resource statement, but it is unambiguous about what is produced and clearly distinct from siblings like describe_clip or analyze_audio. It also names auto_split_by_shot as the action counterpart, further anchoring its role.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit routing to an alternative ('To split: `auto_split_by_shot`') and, more importantly, precise guidance on the passes parameter: default shots/stats/events, `["shots"]` for timing only with no frame sampling, and `"spans"` as an opt-in cost-bearing pass. It does not state preconditions (must the media be imported? must the layer exist?) or contrast with compare_frames/describe_clip, so it stops short of full when/when-not coverage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

apply_subtitlesA

Lay an imported Subtitle item (a .srt/.vtt/.ass from import_media) onto the caption tracks as one editable Text layer per cue, one recorded edit. The whole document lands, its time 0 at t_start_us. Each cue packs onto the first unlocked caption track with room, opening a new one only where it collides with all of them. Advanced ASS styling is simplified. Returns { caption_track_id, cues, simplified }.

NameRequiredDescriptionDefault
media_idYesSubtitle media id.
t_start_usNoWhere the document's time 0 lands on the timeline; default 0, µs.
composition_idNoComposition to create in — a Group's id from `project://compositions`; omit for the root.

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false and destructiveHint=false; the description adds what those annotations cannot: the whole apply is a single recorded edit (undo unit), the packing policy (first unlocked caption track with room, new track only on collision with all), and that advanced ASS styling is simplified rather than preserved.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and one-write semantics, then placement, then side effects, then return shape — efficient. A few phrases ('opening a new one only where it collides with all of them') are dense but each sentence carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-parameter mutation with no output schema, the description covers prerequisites, undo granularity, track-allocation behavior, fidelity loss (ASS simplification), and the return payload `{ caption_track_id, cues, simplified }`. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both optional parameters and media_id are already documented; the description adds only the framing that the document's time 0 maps to `t_start_us`, and does not expand on `composition_id` beyond the schema's Group-id guidance. Baseline 3 for full-coverage schema is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('lay an imported Subtitle item onto the caption tracks as one editable Text layer per cue') and names the source producer (`import_media`), so it is distinguishable from import_media, apply_transcripts, and merge_captions without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Prerequisite is implied by tying the input to a `Subtitle` item from `import_media`, which tells the agent what must happen first. However, there is no explicit statement of when to prefer this over sibling tools like apply_transcripts, merge_captions, or export_captions, nor any exclusion.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

apply_transcriptsA

Lay transcripts on the caption tracks of composition_id (root by default), keeping per-word timing. Pass transcribe_clip's transcripts as is, or your own cues with word_timing: 'none', unsplit: cues are built to the style's caption limits (lines broken, long segments split). A transcript whose source clip changed since it was transcribed (trimmed, cut, moved) is refused: transcribe it again. Cues pack into the existing caption tracks, opening a lane only when all collide, and snap to frames. Returns { caption_track_id, cue_layer_ids }, cues in time order. At most 1000 transcripts. One recorded edit.

NameRequiredDescriptionDefault
transcriptsYes`transcribe_clip`'s `transcripts`, or your own in that shape.
composition_idNoComposition whose captions are meant — a Group's id from `project://compositions`; omit for the root.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false and destructiveHint=false, so the description carries most of the burden and does so well: it discloses that cues are rebuilt to the style's caption limits (lines broken, long segments split), that stale sources are refused, that cues pack into existing tracks and open a lane only on collision, that cues snap to frames, that at most 1000 transcripts are accepted, and that the call counts as 'one recorded edit'. It even states the return shape and ordering.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and front-loaded with the core action, and every sentence carries operational information. Some clauses are crammed together ('...`word_timing: 'none'`, unsplit: cues are built to the style's caption limits'), which slightly hurts scannability, but there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, yet the description states the return value (`{ caption_track_id, cue_layer_ids }`, cues in time order) and the cardinality limit, plus failure behavior for stale sources. For a two-parameter write tool with full schema coverage, nothing an agent needs in order to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description still adds value by clarifying that `composition_id` defaults to root and that supplied cues need not be pre-split — they are split to the style's limits. That meaning goes beyond the field-level schema text, though the `word_timing` enum values themselves are only restated from the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Lay transcripts on the caption tracks of `composition_id`', and immediately scopes it with 'keeping per-word timing'. This distinguishes it clearly from `transcribe_clip` (which produces transcripts) and from `merge_captions`/`apply_subtitles`, so an agent can route without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit input paths: pass `transcribe_clip`'s `transcripts` as is, or supply your own cues with `word_timing: 'none'`. It also states a concrete when-not condition — a transcript whose `source` clip changed is refused and must be re-transcribed. It stops short of naming sibling alternatives such as `apply_subtitles` or `merge_captions`, leaving that comparison implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

auto_split_by_shotA
Destructive

Split a VideoClip at cached analyze_clip shot cuts as one edit. min_shot_us defaults to 500000. drop_short deletes shorter shots and overlapping link members. Returns layer_ids in timeline order (the original id alone when no interior cut exists) and siblings: [{ layer_id, segments }], each link partner cut with it.

NameRequiredDescriptionDefault
layer_idYesThe VideoClip to split.
drop_shortNoAlso delete segments shorter than min_shot_us, with the overlapping members of their link. Default false.
min_shot_usNoShortest shot to keep; default 500000, µs.

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare destructiveHint=true; the description goes well beyond by specifying exactly what is destroyed (short shots and the overlapping members of their link), that link partners are cut alongside the target, and that a no-cut clip returns the original id unchanged. That is precisely the mutation and side-effect detail an agent needs before calling a destructive tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense sentences, front-loaded with the action, then parameter behavior, then return shape. Nothing is padded and no sentence is redundant with the others.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return contract and does so well: layer_ids in timeline order, the single-id no-cut case, and the siblings structure with segments. The remaining gap is failure/prerequisite behavior when shot analysis is not cached, which is left unstated for a destructively annotated tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so all three parameters are already documented, and the description largely restates the schema's defaults (min_shot_us 500000, drop_short false, link-member deletion). It adds no formats, ranges, or constraints beyond what the schema provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb (split), a specific resource (VideoClip), and the exact mechanism (cached analyze_clip shot cuts) applied 'as one edit'. That mechanism implicitly distinguishes it from the generic split_layer sibling, which cuts at a caller-supplied point rather than at detected shot boundaries.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'cached analyze_clip shot cuts' implies the prerequisite that analyze_clip must have run first, and the drop_short sentence explains a conditional mode. However, there is no explicit statement of when to prefer this over split_layer, nor any exclusion such as what happens if no cached shot data exists.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

begin_agent_sessionA
Idempotent

Begin a work session for a batch: one Pre-agent checkpoint, the review baseline pinned to it, and the lightweight agent view. lock (default true) locks the user's undo until the session ends, reason shown in its place; your own undo, redo, jump_to and restore_checkpoint still work. Repeating on the same connection returns the session, changing the lock only when lock is passed. Another connection's session refuses (AgentSessionBusy names the holder) unless force: true ends it and begins yours. end_agent_session, the user or your connection closing ends it. Answers the session with locked, and taken_over after a force. Unrecorded.

NameRequiredDescriptionDefault
lockNoLock the user's undo for the session. Default true; false leaves it free.
forceNoEnd another connection's session (its owner gone) and begin yours. Default false.
reasonYesWhat this work session is for; shown to the user beside the busy badge and in place of undo.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite annotations already covering idempotency and non-destructiveness, the description adds substantial behavior: the user's undo is locked and `reason` is displayed instead of it, while the agent's own undo/redo/jump_to/restore_checkpoint keep working. It also discloses the repeat-call semantics (lock only changes when explicitly passed), the cross-connection conflict and the `AgentSessionBusy` error name, and that the call is unrecorded. That is far beyond what the annotations convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Roughly six sentences, each carrying distinct information (what is created, lock semantics, repeat behavior, conflict/force behavior, termination, return fields), with the core purpose front-loaded. Backticked identifiers keep it scannable and there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, but the description still names the returned fields (`locked`, and `taken_over` after a force). Combined with the lifecycle and conflict behavior, an agent has everything needed to call this correctly in a multi-connection setting.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline would be a 3, but the prose genuinely extends meaning: `lock` is tied to a concrete consequence (the user's undo is frozen, and passing it on a repeat call is what changes the lock), `reason` is tied to where it is rendered, and `force` is tied to ending another connection's session. Only `force`'s destructive nuance versus `destructiveHint: false` is left implicit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ("Begin a work session for a batch") and immediately enumerates what the session creates: a Pre-agent checkpoint, a review baseline pinned to it, and a lightweight agent view. It also names its counterpart (`end_agent_session`), so the agent can separate the begin/end pair from the many other project-mutation siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage context is clear: call it to open a batch's work session, it is idempotent on the same connection, and an occupied session refuses with `AgentSessionBusy` unless `force: true` is supplied. It also states the lifecycle exits (`end_agent_session`, user action, connection close). It stops short of an explicit "use this before/after X" rule relative to siblings like `create_checkpoint`, but the when-to-use picture is essentially complete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cancel_exportA
DestructiveIdempotent

Cancel or discard an export from either entry point. Cancellation drains active work before releasing the project edit lock; wait on get_export_status until terminal.

NameRequiredDescriptionDefault
job_idYesApplication-session export job id.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, so the safety profile is covered. The description adds genuinely non-obvious behavior beyond that: cancellation drains active work before releasing the project edit lock, and the caller must poll get_export_status until a terminal state. It does not say whether partial output is deleted, which is the remaining gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with the action front-loaded and zero filler; the second sentence carries the behavioral payload. 'From either entry point' is the only phrase that costs clarity without adding actionable meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter mutation with no output schema and annotations covering destructiveness and idempotency, the description supplies the key lifecycle facts: in-flight work is drained, the project edit lock is released, and the caller must wait for a terminal status. Only the fate of already-produced output is unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single job_id parameter is documented in the schema as an application-session export job id. The description adds nothing about job_id format or where to obtain it, so the schema carries the full burden and baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb plus resource (cancel/discard an export) and names the follow-up tool, get_export_status, so it is distinguishable from start_export, retry_export and get_export_status. The phrase 'from either entry point' is vague about which entry points, slightly blurring the scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: it tells the agent what to do after cancelling (poll get_export_status until terminal), but never says when to cancel versus retry_export or leave the export running. The alternative tool is named, but the selection condition between them is not.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_compositionA
Read-only

Check a composition against the craft rules (skill craft/rules.md) and the project's taste: { composition_id, revision, findings: [{ severity, rule, range, layers, message, fix }], counts }. hard: fix before handoff; warning: fix, or leave a tack saying why not; review: a departure from the style to confirm. Project data only — text extents are estimated. The whole composition is checked and remembered; t_start_us/t_end_us only narrow the findings returned. Run it after your edits and after fixing.

NameRequiredDescriptionDefault
t_end_usNo…to here; give both or neither, µs.
t_start_usNoOnly findings overlapping from here, timeline, µs.
composition_idNoA Group's composition; omit for the root.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say readOnly/openWorld=false; the description goes well beyond that by disclosing that 'the whole composition is checked and remembered' and that the time range only narrows returned findings. It also scopes what is validated ('Project data only — text extents are estimated'), which is exactly the kind of caveat an agent could otherwise misread as a bug.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action and rule source, then severity semantics, then caveats, then timing advice — a sensible order. The inline return-shape snippet is dense but earns its place since there is no output schema; a slightly lighter rendering would read better.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description supplies the return shape, severity taxonomy with required agent behavior, scope limitations, and invocation timing. Nothing an agent needs to call and act on this tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: t_start_us/t_end_us do not scope the check itself, only which findings are returned. That stateful nuance is not in the schema wording ('Only findings overlapping from here').

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — checking a composition against craft rules and project taste — and names the concrete source of truth (skill craft/rules.md). No sibling tool does validation, so the role is unambiguous against the surrounding edit/restyle/motif tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit timing: 'Run it after your edits and after fixing,' and the severity definitions tell the agent what to do with each outcome (hard = fix before handoff, warning = fix or leave a tack, review = confirm). No explicit when-not-to-use or named alternative, which keeps it short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

compare_framesA
Read-only

Compare two video frames for perceptual similarity — dedup shots, match a cutaway. Each side is { media_id | layer_id, src_us }: a pooled video (placed or not) or a VideoClip, and a source µs time (the space of analyze_clip's src_keyframe_us and media://{id}/frame/{src_us}); the two may be one source or two. Returns { phash_hamming, ssim, similar }: phash_hamming is the 0..64 distance between the frames' perceptual hashes (0 = identical, 20+ = a different scene), ssim is structural similarity 0..1, and similar is phash_hamming <= 10 && ssim >= 0.5. Read-only; video only, errors naming the offending side.

NameRequiredDescriptionDefault
aYesFirst frame to compare.
bYesSecond frame to compare.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and closed-world, so "Read-only" is redundant; the description earns credit instead by disclosing scope limits (video only), error behavior (errors naming the offending side), and precise interpretation thresholds (0..64 hamming, 20+ = different scene, similar = hamming<=10 && ssim>=0.5).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One dense but well-ordered sentence: purpose first, then input shape, then return values, then caveats — no filler, and each clause carries distinct information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and a nested two-object input, the description fully specifies the return triple and how to interpret it, the accepted side shapes, and failure behavior — nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline would be 3, but the description adds real meaning beyond the schema: it clarifies the `{ media_id | layer_id, src_us }` shape is an XOR of one media reference plus a source-absolute time, and anchors src_us to analyze_clip's src_keyframe_us and the media://{id}/frame/{src_us} space.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Compare two video frames for perceptual similarity") and immediately names two concrete jobs — dedup shots and match a cutaway — which sets it apart from analyze_clip/describe_clip siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear usage context via the dedup/match-a-cutaway examples and notes the two sides may come from one source or two, but never states when not to use it or names an explicit alternative tool for a different need.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

correct_caption_textA

Correct caption TEXT against script, the full verbatim transcript of what is said (not notes or a glossary): each cue's words are aligned to it and misheard words, names and terms replaced. Cue segmentation and timing never change. Refuses (InvalidArgument, field script) when under half of the caption words align to it. Every caption in composition_id (root by default); layer_ids narrows it (a non-caption id refuses). Returns { changed, match_ratio, changes: [{ layer_id, before, after }] }, at most 20 listed (changed counts all). Refuses whole, before any write, if a target or its track is locked. One recorded edit; nothing to change records nothing.

NameRequiredDescriptionDefault
scriptYesThe full verbatim transcript of the speech these captions show, correctly spelled.
layer_idsNoThe captions to correct. Omit for every caption in the composition.
composition_idNoComposition whose captions are meant — a Group's id from `project://compositions`; omit for the root.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it discloses the refusal threshold (under half of caption words aligning), atomicity ('refuses whole, before any write, if a target or its track is locked'), that exactly one recorded edit results, and that a no-op records nothing. This tells the agent the failure modes and side effects that openWorldHint/destructiveHint do not.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and constraint, and every clause carries a distinct fact (scope, refusals, return shape, listing cap, locking). It is dense to the point of being terse—several backticked clauses are jammed into one paragraph—but almost nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description still defines the return payload including the 20-item listing cap and the meaning of `changed` versus `changes`. Combined with the refusal and atomicity notes, an agent has everything needed to call it correctly and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, but the description still adds real meaning: `script` is clarified as verbatim speech spelling rather than a glossary, `layer_ids` is clarified as caption-only (non-caption refuses), and `composition_id` defaults to root. Only the returned-field list duplicates what a schema would otherwise carry.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Correct caption TEXT against `script`') and immediately bounds the operation ('Cue segmentation and timing never change'), which separates it from caption-merging or transcript-application siblings. An agent knows exactly what is mutated and what is preserved.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the essential precondition for use (script must be the full verbatim transcript, not notes or a glossary) and the fallback targets (root composition by default, `layer_ids` to narrow, non-caption ids refused). It does not name sibling alternatives such as merge_captions or apply_transcripts to route between them, which keeps it short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_checkpointA

Create a named checkpoint of the current state and return { checkpoint_id, label }. It lasts for this project opening only: opening another project or quitting drops it. It survives later commits (unlike the redo tail); project://history lists checkpoints and the agent panel shows each with a Restore button. begin_agent_session already makes one. Unrecorded.

NameRequiredDescriptionDefault
labelYesCheckpoint name.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare non-destructive and closed-world; the description adds the crucial lifetime rule (dropped on opening another project or quitting) and that it survives later commits unlike the redo tail. "Unrecorded" signals it is not part of undo history, though the term is left unexplained.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and return value, then lifetime, then interactions, with no filler. A few clauses are terse to the point of ambiguity ("the redo tail", "Unrecorded"), costing a little clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by stating the returned object's shape. Lifetime, discoverability via `project://history`, and overlap with begin_agent_session are all covered; only the meaning of "Unrecorded" is left for the agent to infer.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With a single parameter at 100% schema coverage, the schema already defines `label`. The description adds only the modifier "named", which restates rather than enriches the parameter's meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Create a named checkpoint of the current state" gives a specific verb plus resource, and the return shape `{ checkpoint_id, label }` is stated inline. It is clearly distinguishable from restore_checkpoint and begin_agent_session by what it produces.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It tells the agent when a checkpoint is not needed ("begin_agent_session already makes one") and implies the restore path via the agent panel's Restore button. It never names restore_checkpoint as the explicit alternative, so routing is only implied rather than spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_export_presetA

Create a reusable personal export preset. Copies base_preset_id (default builtin:match) and applies optional settings. Built-in base bitrate is copied as a fixed standard-frame-rate value; use get_export_options with preset_id to inspect project-adapted values. Does not change the default or project settings.

NameRequiredDescriptionDefault
nameYesUnique personal preset name, trimmed, at most 40 characters.
settingsNoPartial portable output settings in snake_case. Omitted fields retain base values.
base_preset_idNoExact preset ID from list_export_presets. Built-in IDs start with builtin:.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare non-read-only, non-destructive, non-idempotent, local-only behavior. The description adds genuinely non-obvious context beyond that: the copy-from-base semantics, the default base of builtin:match, the quirk that built-in base bitrate is copied as a fixed standard-frame-rate value, and the explicit scope limit that default/project settings are untouched. It omits what happens on a duplicate name, which the schema handles only indirectly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the core action and default, then the bitrate caveat and the scope limit. No sentence is redundant and the ordering matches the order an agent needs the information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a create tool with a deep nested settings object but no output schema, the description covers origin of values, defaults, and side-effect scope well. The one gap is interaction with existing presets and the fact that the uniqueness constraint on name implies a possible failure mode that is never mentioned.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema coverage the baseline is 3, but the description adds real meaning the schema does not carry: base_preset_id defaults to builtin:match, settings are layered over a copied base, and inspecting the source preset requires get_export_options rather than assuming parity. That directly improves how an agent populates the two optional parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence gives a specific verb and resource ("Create a reusable personal export preset") and the qualifier "personal" distinguishes it from the built-in presets handled by list_export_presets. It stops short of explicitly naming update_export_preset as the tool for modifying existing presets, leaving that inference to the agent.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides a clear exclusion ("Does not change the default or project settings") and routes the agent to get_export_options with preset_id when project-adapted values are needed. What's missing is explicit guidance on create-vs-update, i.e. pointing at update_export_preset when a preset already exists.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_groupA

Pre-compose selected clips into a new Group, preserving their placement and links. Refuses partial links, locked members and incompatible selections. Returns the Group clip and composition. Group members retain their own timing and effects.

NameRequiredDescriptionDefault
labelNoOptional name for the new composition. Omit and the UI derives one.
layer_idsYesThe layers to pre-compose; at least one, all in one composition.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false and destructiveHint=false, so the description carries most of the load and does add real context: three explicit refusal conditions and the fact that members keep their own timing and effects. It also discloses the return payload ('the Group clip and composition') despite having no output schema. What is missing is whether the operation is undoable or what state the source layers are left in after pre-composition.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the action and scope, then refusals, then return value. Every clause carries distinct information: placement/links preservation, failure modes, and member timing behavior. Nothing is repeated from the schema or annotations.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter mutation with no output schema, the description covers purpose, failure conditions, and return shape, which is most of what an agent needs. The remaining gap is post-state: whether the group replaces the source layers in the timeline and whether the call can be reverted.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already documented, including the UI-derivation behavior when label is omitted. The description adds only a loose restatement ('selected clips', 'preserving their placement and links') rather than new meaning for layer_ids ordering or composition-scope constraints. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Pre-compose selected clips into a new Group, preserving their placement and links.' An agent can distinguish it from the inverse sibling ungroup_layer without opening the schema. It stops short of naming adjacent siblings such as add_group_members or create_link, so it is clear but not maximally differentiated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied through preconditions rather than stated routing: 'Refuses partial links, locked members and incompatible selections' tells the agent when the call will fail, but never says when to choose this over add_group_members or move_layers_to_composition. The reader must infer the workflow position of grouping from context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_projectA
Destructive

Create <parent_folder>/<name> and open it, as New Project does; only when the user asked. The project open before is saved. Defaults: the session view's default_parent_folder; 1920x1080 at 60 fps (the rate locks once a layer is placed). Returns { name, dir, replaced }.

NameRequiredDescriptionDefault
fpsNo24, 25, 30, 50, 60, or 24000/30000/60000 over 1001.
nameYesFolder and project name.
widthNoEven px, 16..7680; with `height`.
heightNoEven px, 16..7680; with `width`.
parent_folderNoAbsolute folder to create in.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The destructiveHint=true annotation is meaningfully qualified: the description states the previously open project is saved, and that the frame rate locks once a layer is placed — traits an agent could not infer from annotations. It also names the return shape `{ name, dir, replaced }`, though what `replaced` means (existing target folder/file overwritten?) is left unexplained, which is the main gap for a destructive tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense sentences, front-loaded with what is created and conditioned by the user-intent gate, with defaults and return value packed efficiently. The telegraphic style and the 'as New Project does' UI reference cost a little immediate clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter, nested-schema creation tool with no output schema, the definition covers creation target, defaults, destructive side effect, fps lock, and the returned fields. Missing only failure behavior, e.g. what happens if the folder or project name already exists.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns above that by supplying defaults not in the schema — parent folder taken from the session view's `default_parent_folder`, and 1920x1080 at 60 fps — plus the constraint that fps is fixed after the first layer is placed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a concrete verb and resource plus the exact path semantics (`<parent_folder>/<name>`) and the UI analogue ('as New Project does'), which differentiates it cleanly from the sibling open_project.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'only when the user asked' gives an explicit gating condition for invoking the tool, which is stronger than most definitions. It stops short of naming open_project/read_project as the alternatives when no creation is wanted, so routing is partly implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_tacksA

Point the user at time ranges to review — a pause to check, a shot to judge, a cut to decide. Not a marker: it lives in the agent panel for this project opening only; the user resolves, dismisses or clears it; use it unless the user asked for markers. Create after your edits; all or none. It comments on what plays in its range on every track: it moves with that content and is outdated once the range plays anything else. Describe content, never times: the panel shows the live place. One place, one tack. Returns { tacks, hints? } as project://tacks reads them; later edits report your moved or outdated ones as affected_tacks. TackLimit past 1000. Unrecorded; works while history is locked.

NameRequiredDescriptionDefault
tacksYesThe tacks to create, validated together: one refusal creates none.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the annotations: it discloses scoping (agent panel, this project opening only), lifecycle (user resolves/dismisses/clears; tacks go outdated when the range plays different content), transactional validation (one refusal creates none), the 1000 limit with the `TackLimit` error, and that it is unrecorded and works while history is locked. That is exactly the mutation-behavior context destructiveHint=false alone cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and dense with information — nearly every clause carries a rule or a constraint, and nothing reads as filler. The trade-off is telegraphic syntax such as "`TackLimit` past 1000" and em-dash chaining that costs a re-read in places.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description still names the return shape (`{ tacks, hints? }`) and the follow-up signal (`affected_tacks`), and covers limits, persistence, validation, and lifecycle. Minor gaps remain, e.g. what a returned tack object contains and how `hints` is populated, but nothing essential to calling it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, and the description adds real guidance beyond it: "Describe content, never times: the panel shows the live place" tells the agent how to write `label`, and "One place, one tack" constrains the array contents. It does not add anything about `kind` or `composition_id`, which remain schema-only.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a concrete action and resource — pointing the user at time ranges to review — and defines what a tack functionally is (a comment anchored to a range that travels with the content). It explicitly separates itself from markers ("Not a marker"), so an agent can distinguish it from add_marker without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit routing rule: "use it unless the user asked for markers," plus timing guidance ("Create after your edits") and a boundary that the user, not the agent, resolves or clears tacks. It does not name the close siblings update_tack or delete_tacks as follow-up paths, which leaves a small inference gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_compositionA
Destructive

Delete a composition nothing references — an orphan left when its Group layers were deleted. Refuses while any Group layer points at it (CompositionInUse { ref_count }; project://compositions shows the count) and refuses the root (RootComposition). Recorded.

NameRequiredDescriptionDefault
composition_idYesComposition id.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and openWorldHint=false, so the risk profile is known; the description goes further by documenting the exact refusal conditions and error identifiers (CompositionInUse with ref_count, RootComposition), which the agent can handle programmatically. 'Recorded' hints the operation is journaled, but it does not say whether an undo or checkpoint restore is available, leaving that ambiguity.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the core constraint, then the refusal contract, then the audit note. No filler, and the error tokens are inlined rather than buried at the end.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter destructive tool with no output schema, the definition covers the precondition, the failure modes, and how to check eligibility beforehand. Nothing an agent needs in order to avoid a failed or wrong deletion is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is a single parameter with 100% schema description coverage, so the schema already carries the burden. The description adds no format or sourcing detail for composition_id beyond implying it must be an orphaned, non-root composition; per the baseline rule for full schema coverage this is a 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (delete) and resource (composition) and immediately narrows the scope: only an orphan left behind when its Group layers were deleted. That scoping distinguishes it from delete_layers and the other deletion siblings without the agent needing to open any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It spells out the precondition (nothing references it) and both failure cases — CompositionInUse while a Group layer points at it, and RootComposition for the root — and points at project://compositions to inspect the reference count first. It stops short of naming the sibling to use for the other cases (e.g. delete_layers for the group layers themselves), so it is context-rich but not fully comparative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_effectC
Destructive

Remove an effect from a layer by id.

NameRequiredDescriptionDefault
layer_idYesLayer id.
effect_idYesEffect id.

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and openWorldHint=false, so the agent knows this is a destructive local mutation. The description adds nothing beyond that — it does not say whether the removal is undoable, whether it cascades to keyframes or links, or whether confirmation/permissions are needed, which is the main thing left for a destructive tool to disclose.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with zero filler. It is efficient, though on the terse side given the destructive nature of the operation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple (2 required params, no output schema), but it is a destructive mutation and the description leaves reversibility, validation behavior, and error conditions unspecified. An agent can call it, but cannot predict the consequences of doing so.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% (both effect_id and layer_id are documented in the schema), so the baseline of 3 applies. "By id" only restates that the parameters identify the effect and layer; no additional format or constraint detail is added.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Remove an effect from a layer by id" names a specific verb (remove) and resource (effect scoped to a layer), which is unambiguous. It does not differentiate from siblings such as add_effect, update_effect, or delete_transition, but the core action is clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use guidance is given. There is no mention of when to prefer update_effect (modify parameters) over delete_effect, nor any prerequisite such as needing the effect to exist or requiring the layer to be otherwise unlocked.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_export_presetA
DestructiveIdempotent

Delete a personal export preset. Deleting the default restores builtin:match. Existing projects are unchanged. Built-ins are read-only.

NameRequiredDescriptionDefault
preset_idYesExact preset ID from list_export_presets. Built-in IDs start with builtin:.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, so the description's job is to say what damage occurs — and it does: deleting the default restores builtin:match, and existing projects are left unchanged. That consequence disclosure is genuinely useful context beyond the annotations. It stops short of stating irreversibility or recovery options for a non-default preset.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the action, then consequences, then the read-only guard. No filler and nothing restated from the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter destructive tool with no output schema, the description covers the scope, the fallback behavior, and the built-in restriction — enough to call it correctly. The remaining gap is what happens to a non-default preset's settings (recoverable or not).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the preset_id description already points at list_export_presets and explains the builtin: prefix. The description reinforces the built-in constraint but adds no format or source detail beyond what the schema provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ("Delete a personal export preset") and implicitly scopes it against the create/update/list_export_presets siblings by qualifying the preset as personal. No sibling is named explicitly, so it lands at 4 rather than 5, but an agent can still tell what this does and what it does not touch.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Built-ins are read-only" is an explicit when-not-to-use condition, which is exactly the kind of exclusion most delete tools omit. It does not name an alternative for modifying rather than removing a preset (update_export_preset), so it misses the top tier.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_keyframeA
Destructive

Remove a keyframe by id from a layer param (keyframe_ids in get_param_track). When it was the last key, the track collapses to Static holding that key's value. Returns the track's mode and keyframe_ids, or the static value.

NameRequiredDescriptionDefault
layer_idYesLayer id.
param_keyYesVisual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>].
keyframe_idYesKeyframe id.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and openWorldHint=false, so the description gets a lower bar, and it clears that bar by disclosing a non-obvious side effect: deleting the last key collapses the track to Static holding that key's value. It also states the shape of the response ('the track's mode and keyframe_ids, or the static value'), which annotations cannot convey. It does not mention whether the deletion is recoverable or undoable via the 'undo' sibling, so it stops short of 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: the action comes first, the side effect second, and the return value last. No restated name or filler, and every sentence carries distinct information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-required-parameter destructive mutation with no output schema, the description covers the action, the resulting state transition, and the return shape, which is enough to call it correctly. It omits error behavior (e.g., unknown keyframe id) and recoverability, which keeps it one step from complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description adds cross-tool meaning by tying keyframe_id to the keyframe_ids field returned by get_param_track. That sourcing hint is genuine information beyond the schema; layer_id and param_key semantics are left entirely to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource ('Remove a keyframe by id from a layer param'), and it points at the sibling that supplies the id ('keyframe_ids' in get_param_track). It never explicitly contrasts itself with set_keyframe/update_keyframe, so an agent must infer the difference from the verb alone, which holds it below a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: the reference to get_param_track tells the agent where to obtain keyframe ids before calling, which is genuinely useful context. But there is no explicit when-to-use vs. when-not guidance, and no routing away from set_keyframe/update_keyframe for modification cases.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_layersA
Destructive

Delete a set of layers as one recorded edit. Nothing is expanded: pass link partners (link_id in project://tracks), or a lifted video leaves its dialogue playing. ripple decides what happens to the vacated span: false (default) is the lift — it stays empty and nothing moves; true closes each hole so the film gets shorter — every remaining layer starting at or after a hole shifts left by its length on EVERY track of the composition (anchored markers riding along), touching holes merge, and layers starting before a hole, free markers and the playhead stay put. The set is one composition's (CrossCompositionSet); any locked layer or track refuses the whole batch; tracks the batch emptied are pruned. A ripple refuses whole, before any write, naming the blocker: RippleInsideHole (a remaining layer starts inside a hole — add it to layer_ids, or lift), RippleCollision (a mover would land on a layer that is not moving), RippleLinkStraddles (a link spans the hole), RippleLockedLayer (only a layer that shifts blocks). An empty set is refused as a ripple.

NameRequiredDescriptionDefault
rippleNoClose each vacated span and shift everything downstream left (default false — leave the spans empty).
layer_idsYesThe layers to delete, all in one composition.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the destructiveHint annotation, the description discloses atomicity (whole-batch refusal before any write), ripple mechanics, hole merging, track pruning, and named ripple refusal errors. This is unusually rich behavioral context for a destructive tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but front-loaded with the core action and the ripple default. It is long for two parameters, yet most sentences carry distinct behavioral information; a few clauses could be simplified without losing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the destructive batch operation, no output schema, and the need to understand ripple side effects and refusals, the description is complete enough for an agent to call the tool correctly or anticipate failure conditions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although the schema already documents both parameters at 100% coverage, the description adds substantial meaning: it explains what 'ripple' does to every track, anchored markers, the playhead, and free markers, and it explains why link partners may need to be added to layer_ids.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Delete a set of layers as one recorded edit.' It also distinguishes the operation's scope (one composition) and batch nature, making it clearly different from sibling tools like delete_track or delete_transition.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear contextual guidance: link partners must be included explicitly, ripple defaults to false, and locked layers/tracks block the whole batch. It lacks explicit comparison to alternative tools, but the operational conditions are sufficiently clear for correct use.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_markerC
Destructive

Remove a marker.

NameRequiredDescriptionDefault
marker_idYesMarker id.

TDQS

C2.5/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and openWorldHint=false, so the safety profile is covered structurally and the description is not required to restate it. However, the description adds no behavioral context beyond the annotations: it does not say whether deletion is reversible, whether attached keyframes or anchors are also removed, or what happens if marker_id is invalid. For a destructive operation this leaves meaningful gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The single sentence is front-loaded and free of waste, but its brevity reflects under-specification rather than disciplined editing. There is no structure to speak of because there is only one short clause.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive single-target tool with no output schema, the description should at minimum cover reversibility and side effects, and it covers neither. The annotations and 100% schema coverage carry the structural burden, but an agent still cannot tell what it loses by calling this.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single marker_id parameter, so the schema already carries parameter meaning and the baseline of 3 applies. The description contributes only the indefinite "a marker", adding no format, id-namespace, or lookup guidance beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a verb plus resource ("Remove a marker"), which is marginally more than the name delete_marker already conveys and does not tell the agent anything about scope or which marker domain (timeline markers vs. other markers) is affected. It is clear enough to avoid confusion with update_marker or add_marker, but it borders on restating the name rather than adding distinguishing detail.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance at all: nothing says when deleting is preferable to update_marker or set_marker_anchor, and no prerequisites or confirmation conditions are given. The only implied usage comes from the verb itself, which the sibling name already exposes.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_mediaA
Destructive

Remove a media item. Rejects if any layer references it unless force=true. With force=true, also deletes the referencing layers in one atomic commit, exactly as delete_layers would: their links dissolve below two members, a transient lane they empty is pruned, a locked lane refuses as TrackLocked. Unrecorded when nothing used it; the forced cascade records.

NameRequiredDescriptionDefault
forceNoAlso delete the layers that use it (their links and emptied lanes go too). Default false: media in use refuses.
media_idYesMedia id.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past destructiveHint=true: it discloses atomic commit semantics, that links dissolve below two members, that emptied transient lanes are pruned, that a locked lane raises TrackLocked, and how undo recording differs between the no-op and forced paths. These are exactly the failure and side-effect details an agent must anticipate; only the return payload is unaddressed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then escalating detail on refusal, cascade, and recording. Dense but nearly every clause adds a distinct behavioral fact; the final 'Unrecorded when nothing used it; the forced cascade records' is terse to the point of being cryptic.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter destructive tool with no output schema, the description covers the refusal path, the destructive path, error conditions, and undo recording — enough to call it safely. What is missing is any indication of what the call returns on success or on the cascade.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, and the description earns above it by spelling out what force actually triggers (cascade plus the same rules as delete_layers) rather than just restating 'default false'. media_id gets no extra meaning, but it needs none.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource ('Remove a media item'), which is unambiguous. It also implicitly separates itself from delete_layers by explaining that removing media may cascade into layer deletion, though it never states the reverse case (deleting layers without touching media).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clearly states the default refusal condition and the alternative (force=true), plus the consequence of taking that alternative. It stops short of an explicit 'use delete_layers instead when you only want layers gone', but the cascade paragraph makes the boundary between the two siblings legible.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_motifA
Destructive

Delete a user Motif or draft (and its pending proposal); linked source directories are never deleted. Built-ins are refused. Referencing layers become missing-content placeholders.

NameRequiredDescriptionDefault
motif_idYesMotif id (list_motifs).

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the `destructiveHint`, the description provides critical behavioral context, such as stating that referencing layers become 'missing-content placeholders' and that source directories are never deleted, defining the exact mutation consequences.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition is highly concise and perfectly structured, layering the core purpose first, followed by necessary behavioral constraints and side effects without any wasted language.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given its destructive nature and specific resource types, the description is extremely complete. It covers the object being deleted, what stays, what is refused, and the resulting placeholder status of dependent layers.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 100%, providing maximum baseline information. The description does not add semantic value beyond confirming that the ID targets the Motif or draft being deleted.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the action (Delete) and the resource type (user Motif or draft). It distinguishes this tool from creation or listing tools available in the sibling set.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides important contextual guidelines regarding safety and scope by stating which linked resources (directories) are safe from deletion and which types (built-ins) are refused.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_tacksA
Destructive

Remove tacks: the listed tack_ids (every one must exist, or none is removed), or every tack created in work session session_id. Exactly one of the two. Returns { deleted_tack_ids }. Unrecorded.

NameRequiredDescriptionDefault
tack_idsNoThe tacks to remove.
session_idNoA work session id (project://session); removes every tack created in it.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag `destructiveHint: true` and `openWorldHint: false`, and the description adds real value beyond them: all-or-nothing semantics ("every one must exist, or none is removed"), the return shape `{ deleted_tack_ids }`, and the terse flag "Unrecorded." The last item is important but cryptic — it presumably means the deletion is not captured in undo/checkpoint history, but the description never says so plainly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Extremely compact and front-loaded: verb, modes, constraint, return, caveat. No filler sentences. The telegraphic fragments ("Exactly one of the two.", "Unrecorded.") trade a little readability for density, and the final fragment borders on ambiguous note-taking.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 2-parameter destructive tool with no output schema, the description covers everything needed to call it correctly: which argument selects which mode, that exactly one is used, atomicity on failure, and what comes back. Nothing essential is missing, though expanding "Unrecorded" would remove the only interpretive burden.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns above that by adding semantics the schema does not express — mutual exclusivity of `tack_ids` and `session_id`, and that a session deletion expands to every tack created in that session. The `tack_ids` and `session_id` schema descriptions corroborate but do not duplicate this.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ("Remove tacks") and immediately distinguishes the two supported scopes: an explicit `tack_ids` list versus all tacks from a work session. An agent can tell exactly what this does and how it differs from `create_tacks` or `update_tack` without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Exactly one of the two" is an explicit, unambiguous selection rule between the two deletion modes, which is the key usage decision here. It stops short of naming alternatives (e.g., using `update_tack` for less destructive edits) or prerequisites, so it is clear context but not a full when-to-use/when-not map.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_trackA
Destructive

Remove a track. Refuses a track with layers unless force=true (TrackNotEmpty); with force the layers go with it and their links are cleaned up in the same undo entry. A Group layer among them leaves its composition in place with ref_count 0 (project://compositions) — delete_composition removes that. Only A roll / B roll tracks are protected (TrackNotRemovable); audio and caption tracks can be deleted.

NameRequiredDescriptionDefault
forceNoAlso delete the layers still on it. Default false, which refuses a non-empty track (TrackNotEmpty).
track_idYesTrack id.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare destructiveHint=true and openWorldHint=false; the description supplies the specifics those hints cannot: the exact refusal error, the cascade behavior under force, that layer links are cleaned up, and that the whole cascade lands in a single undo entry. It also discloses the subtle side effect that a Group layer's composition survives with ref_count 0 rather than being deleted.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action, then the refusal condition, then the cascade and edge case. It is dense and every clause carries information, though the em-dash aside about project://compositions is slightly awkward to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive two-parameter tool with no output schema, it covers the failure modes, the cascade semantics, the undo grouping, and the follow-up tool for leftover compositions. An agent has everything needed to call it safely and handle the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both parameters are already documented, and the description largely restates force's semantics (cascade delete of layers) rather than adding syntax or format detail. It does add the consequence of force beyond the schema's wording, but the baseline of 3 for a fully-covered two-parameter schema is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Remove a track" is a specific verb+resource, and the description immediately scopes it against siblings: delete_composition handles orphaned compositions, delete_layers is implied for individual layers. It also names which track types are deletable, so an agent can tell this apart from layer- or composition-level deletion tools without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states the precondition for force (non-empty track raises TrackNotEmpty), the protected track types (A roll / B roll raise TrackNotRemovable), and routes orphaned compositions to delete_composition. What it does not say is when to prefer deleting individual layers via delete_layers instead of force-deleting the whole track, which is the one remaining routing decision left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_transitionA
Destructive

Remove a transition and restore the hard cut, routed by provenance: the outgoing layer's end shrinks back by extended_us (only borrowed tail is returned, never real content) and the incoming layer moves RIGHT by duration_us − extended_us, link siblings following. TransitionRestoreCollision when that destination has since been filled — move or delete the blocker first; the system never makes room. Recorded. TransitionNotFound for an unknown id.

NameRequiredDescriptionDefault
transition_idYesTransition id.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare destructiveHint=true; the description goes far beyond by explaining exactly what mutates (outgoing layer end shrinks by `extended_us`, incoming layer shifts right by `duration_us − extended_us`, link siblings follow), that only borrowed tail is discarded and never real content, that the operation is "Recorded" (undoable), and the two named error conditions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action and its restoral semantics are front-loaded and every clause carries information, but the middle sentence is dense jargon with several backticked field names used without definition, which slows comprehension for an agent that has never seen `extended_us`.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter destructive mutation with no output schema, this covers the important ground: mutation mechanics, error names, remediation, and recording/undo. It stops short of stating permission or checkpoint prerequisites and does not say what is returned on success.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% for the single `transition_id` parameter, so the baseline is 3. The description adds only indirect meaning — `TransitionNotFound` for an unknown id implies the id must reference an existing transition — while `extended_us`/`duration_us` are recorded transition properties, not inputs, and are left unexplained.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource ("Remove a transition") and immediately clarifies the resulting state ("restore the hard cut"), so an agent can distinguish it from add_transition/update_transition without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete when-it-fails guidance — on `TransitionRestoreCollision` the agent must "move or delete the blocker first" because "the system never makes room" — but it never names the sibling tools (e.g. move_effect, delete_effect) that would perform that remediation, leaving the routing one inference away.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

describe_clipA
Read-only

Describe a video's visual content as timestamped segments with a video-understanding model (local Qwen3-VL / MiniCPM-V, or an OpenAI-compatible endpoint). Name a pooled item by media_id (placed or not; the whole source by default) or a VideoClip by layer_id (the source it plays, plus its mapping, as analyze_clip's). Samples the window at fps (default 1.0), ≤3600 frames per call. Returns { backend, model, summary?, media_id, mapping?, segments: [{ src_start_us, src_end_us, text, tags }] }, source µs; text is prose, tags short visual keywords; long windows add a summary. Cached per source range, so a retry after a client timeout or an interruption resumes; refresh re-describes. src_start_us/src_end_us (e.g. a shot's) narrow the window; focus steers tags; language is BCP-47 (default: UI language). qwen3_vl and minicpm_v run on this machine; byo_endpoint UPLOADS frames — name it only with the user's consent. backend REQUIRES that engine, never substituting; omitted: the selected engine, then availability (local first).

NameRequiredDescriptionDefault
fpsNoFrames sampled per second (higher = finer, more requests). Default: the app's setting, else 1.0. Cache key.
focusNo`shot-type` biases `tags` toward shot type / camera. Default: the app's setting, else `general`. Cache key.
backendNoStrict engine override; that engine serves or the call errors. `byo_endpoint` uploads frames.
refreshNoDescribe again even when cached, replacing the earlier run (default false).
languageNoBCP-47 tag the `text` and `tags` come back in (`"en-US"`, `"zh-CN"`, `"ja"`). Default: the app's UI language. Cache key.
layer_idNoOr a VideoClip: the default window is the source it plays, and the answer carries its `mapping`.
media_idNoA pooled video, described whole by default (placed or not).
src_end_usNoOptional exclusive window end, source-absolute microseconds. Defaults to the end of the source the layer plays. Must lie within it.
src_start_usNoOptional window start, source-absolute microseconds (the space the answer's segments and `analyze_clip`'s shots use). Defaults to the start of the source the layer plays. Must lie within it.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the `readOnlyHint`/`openWorldHint` annotations: caching per source range means a retry after a client timeout resumes, `refresh` replaces the earlier run, sampling is capped at ≤3600 frames per call, local engines run on this machine while `byo_endpoint` uploads frames, and `backend` never silently substitutes. These are exactly the operational facts an agent needs before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the verb and target, then window, return shape, caching, and engine policy in descending order of importance; nearly every clause carries information. It is a dense wall of backticked tokens in one paragraph, which costs it a point on readability rather than on waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 9 optional parameters, no output schema, and a non-trivial engine/caching model, the description supplies the return shape (`backend, model, summary?, media_id, mapping?, segments[...]`), the source-microsecond convention, cache/resume behavior, and consent requirements. Nothing essential to a correct call is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3; the description still adds cross-cutting meaning the schema cannot express — which parameters are cache keys, that `focus` steers only `tags`, that `language` defaults to the UI language, and the backend resolution order (selected engine, then availability, local first).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Describe a video's visual content as timestamped segments with a video-understanding model'. It also names the concrete alternatives (media_id pooled item vs. layer_id VideoClip) and ties itself to the sibling `analyze_clip` by sharing its `mapping` semantics, so an agent can place it precisely.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear selection rules: pooled item by `media_id` (placed or not), VideoClip by `layer_id`, window narrowed by `src_start_us`/`src_end_us`, `refresh` to re-describe, and a consent condition for `byo_endpoint`. It lacks an explicit when-not (e.g. use `analyze_clip` for shot structure vs. this for visual prose), so 4 rather than 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

detect_pausesA
Read-only

Find the pauses in the audio a clip plays — the stretches nobody is speaking — from the pre-computed waveform. Read-only: the writes are remove_pauses (cut them, or a reviewed subset via its pauses) and create_tacks (point the user at them). A pause is a run where every channel's peak stays below threshold_db (dBFS, default -34) for at least min_pause_us (default 500000); a louder run under 80 ms inside it (a click, a cough) does not end it. layer_id is an Audio layer, or a VideoClip, read through the linked Audio member that plays (refused when it plays no sound). Returns { pauses: [{ t_start_us, t_end_us }], noise_floor_db, peaks_source }, timeline µs, sorted; noise_floor_db is the 10th-percentile peak (null in silence; a threshold reads well 6 dB above it); peaks_source is "raw" or "fx" (baked effect chain). Refused (DerivativeNotReady with the waveform's state) until ready: retry after retry_after_s; failed names its reason.

NameRequiredDescriptionDefault
layer_idYesTarget Audio layer id. A VideoClip id is accepted by the host, which resolves it to the Audio layer of its link before the call.
min_pause_usNoShortest pause to surface, in microseconds. Default 500000 (0.5s).
threshold_dbNoPeak threshold, dBFS (≤ 0). Anything strictly below it counts as quiet. Default -34.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint/openWorldHint annotations, the description discloses the internal detection semantics (peak below threshold for min_pause_us; a sub-80 ms louder run like a click does not end a pause), the layer_id resolution rule and refusal when a linked Audio member plays no sound, and the DerivativeNotReady refusal with state/retry_after_s/failed reason. This is unusually rich behavioral context that annotations alone would never supply.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core purpose and the read/write split before the technical detail. It is dense and somewhat crammed with parentheticals (dBFS defaults, click exception, refusal states), but nearly every clause earns its place and the ordering is logical.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description fully specifies the return shape (pauses[{t_start_us,t_end_us}], noise_floor_db, peaks_source with 'raw'/'fx'), timeline units, sort order, and the DerivativeNotReady failure path. For a read-only detection tool with three params, nothing an agent needs to call and interpret it is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all three parameters; the description nonetheless adds meaning by explaining how threshold_db and min_pause_us interact to define a pause, and by noting the 6 dB-above-noise-floor heuristic. It adds real value beyond the schema, though it largely restates the defaults already present in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Find the pauses in the audio a clip plays... from the pre-computed waveform') and immediately disambiguates from the write-side siblings (remove_pauses, create_tacks). An agent can tell exactly what this does versus the mutation tools without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames the tool as read-only and names the alternatives for the write path: 'the writes are remove_pauses (cut them, or a reviewed subset via its pauses) and create_tacks (point the user at them).' It also states the prerequisite (waveform must be ready) and the refusal/retry behavior, so when-to-use and when-it-fails are both covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

end_agent_sessionA

End your work session and release its history lock; the view, activity, running tasks and connection stay. Only the owning connection may end it (begin_agent_session { force: true } takes over a stale one). Unless your last check_composition is current, the app audits first; hard or warning findings keep the session open (ended: false, held: "audit"): settle them and end again. Answers { ended, audit } (ended: the closed session, null with none), plus tacks_to_review when open tacks are outdated. Unrecorded.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say openWorldHint=false and destructiveHint=false; the description goes well beyond by disclosing the ownership rule, the audit gate, and exactly what is retained versus released. The failure mode is given concretely (`ended: false, held: "audit"`). Minor gap: 'Unrecorded' is asserted without clarifying which history/undo log it refers to.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the primary effect, then preconditions, failure semantics, and return shape in a logical order with no filler sentences. It is densely packed with shorthand ('Unrecorded.', `tacks_to_review`) that assumes domain familiarity and slightly compresses readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, but the description hand-specifies the response (`{ ended, audit }`, null `ended`, optional `tacks_to_review`). Combined with the ownership and audit-gate behavior, an agent has everything needed to call and interpret this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the schema baseline is 4 and there is nothing parameter-specific for the description to add. It does correctly avoid inventing inputs, though the caller has no handle to force or skip the audit here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (end the agent session) plus the precise effect: releases the history lock while the view, activity, running tasks and connection persist. It is immediately distinguishable from the sibling begin_agent_session, which is named as the takeover alternative.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says who may call it (only the owning connection) and names the alternative for the stale case (`begin_agent_session { force: true }`). It also states the precondition (a current `check_composition`) and what to do when the call is refused (settle findings and end again).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

export_captionsA
Read-only

The captions of a composition as a subtitle document — format srt or vtt — read from every caption lane (or one track_id) in time order, with the cue text as it stands. range (start_export's) clips cues to it and shifts them to 0, in step with a range export. Returns { format, cues, body }, plus the snapped range; write body to a file yourself. Records nothing.

NameRequiredDescriptionDefault
rangeNoSnapped to the frame grid as start_export snaps it; omit for all cues.
formatYesSubRip or WebVTT.
track_idNoOne caption lane only; omit for every caption lane of the composition.
composition_idNoComposition whose captions are meant — a Group's id from `project://compositions`; omit for the root.

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already establish readOnlyHint=true and openWorldHint=false, so safety is covered. The description adds useful behavior beyond that: it discloses the return shape `{ format, cues, body }` plus the snapped `range`, states that the range is snapped to the frame grid like start_export, and notes 'Records nothing' and that no file is written. It does not cover error behavior or lane-ordering edge cases, so it sits at a solid but not exceptional level given annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action, then the range semantics, return shape, and the 'write body yourself' caveat. It is dense and telegraphic (heavy em-dash use), but essentially every clause carries information; minor tightening is possible but nothing is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by specifying the returned object keys and the snapped range, and it covers all four parameters at 100% schema coverage. For a read-only export tool with nested range parameters, an agent has everything needed to call it and handle the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema baseline is 3; the description nonetheless adds real meaning by explaining that `range` clips cues and shifts them to 0 in step with a range export, and that `track_id` restricts to one lane while omission means all lanes. That is more than restating field names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('The captions of a composition as a subtitle document'), states the supported formats, and defines scope ('every caption lane (or one track_id) in time order'). That level of specificity clearly separates it from siblings such as merge_captions, apply_subtitles, and correct_caption_text.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear context for when to use it: when you want cue text as it stands, aligned with a range export ('range (start_export's) ... in step with a range export'), and it tells the agent to write `body` to a file itself. It stops short of explicitly naming alternatives or stating exclusion conditions (for example, that this does not merge, apply, or correct captions).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

export_motifA
Destructive

Write a complete ZIP snapshot to path: an absolute app-machine .zip in an existing folder; an existing file is refused, never overwritten. Refuses invalid linked content.

NameRequiredDescriptionDefault
pathYesAbsolute path on the app machine.
motif_idYesMotif id (list_motifs).
expected_revisionNoRevision returned by open, read or preview.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds real behavior beyond the annotations: no-overwrite semantics ('an existing file is refused, never overwritten') and validation failure on invalid linked content. This is meaningful for a tool flagged destructiveHint=true, since it tells the agent the blast radius is limited to a new file. It stops short of covering revision-mismatch behavior or whether the write is synchronous.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the core action and the path contract, with every clause carrying a constraint an agent needs. No filler or restatement of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The write path contract is well covered, and with no output schema there is no obligation to describe return values. However, for a three-parameter export with a revision guard, the description leaves the caller without any model of what success looks like or how expected_revision participates in the write.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description adds genuine constraint on 'path' (must be absolute, on the app machine, inside an existing folder, and must not already exist) that the schema text does not, but says nothing about expected_revision, which is the parameter most likely to cause a failed call.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and artifact: writes a complete ZIP snapshot to a given path. It is clear what the tool produces, but never says the word 'motif' and never contrasts itself with nearby export siblings (start_export, render_frames, export_captions), so the agent must infer the boundary from the name alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives preconditions rather than use guidance: path must be absolute on the app machine, the folder must already exist, and an existing file causes a refusal. There is no statement of when this is the right export tool versus the other export-related siblings, so usage is only implied by the constraints.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

extract_clip_audioA
Read-only

Extract the ORIGINAL source audio that plays on a VideoClip or Audio layer (a VideoClip through its linked Audio member) — before gain, mute, effects or mixing — for an agent running its own speech model; no engine or API key is involved and nothing is uploaded. Returns a JSON metadata block (layer_id, media_id, t_start_us, t_end_us, src_in_us, src_out_us, duration_us, rate {num, den}, sample_rate_hz, channels, bits_per_sample, byte_length, mime_type) plus an MCP audio block: base64 WAV, mono 16 kHz 16-bit, starting at zero — about 2.6 MB of base64 per 60 s. Optional t_start_us/t_end_us are timeline µs, defaulting to the layer endpoints; at most 60 s of source audio per call (timeline windows ≤ 60 s / rate), so a long clip is several calls. Map a WAV offset w to the timeline as t_start_us + w / rate, then apply_transcripts. Refuses a layer that plays no sound and a window outside the layer.

NameRequiredDescriptionDefault
layer_idYesTarget VideoClip or Audio layer id.
t_end_usNoExclusive window end in the owning composition's absolute microseconds. Defaults to the layer end. Maximum window duration: 60000000 us (60 s).
t_start_usNoWindow start in the owning composition's absolute microseconds. Defaults to the layer start. Must lie inside the layer.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint and openWorldHint; the description adds substantially more: nothing is uploaded, no API key is needed, output is normalized to mono 16 kHz 16-bit WAV starting at zero, ~2.6 MB base64 per 60 s, and it refuses layers that play no sound or windows outside the layer. That is exactly the behavioral context the annotations cannot carry, and it is consistent with readOnlyHint=true.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose before the mechanics, and nearly every clause carries information (format, size, limits, refusal cases, offset mapping). It is a single dense block with embedded field lists and formulas, which is efficient but slightly harder to scan than a broken-out structure would be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, yet the description fully enumerates the returned metadata keys and the MCP audio block format, so an agent knows exactly what comes back. Combined with limits, defaults, and failure modes, nothing needed to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: it clarifies the 60 s cap is on SOURCE audio (timeline windows ≤ 60 s / rate), whereas the schema only mentions a 60 s window, and it supplies the offset mapping formula 't_start_us + w / rate'. That rate-dependent nuance is not derivable from the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — 'Extract the ORIGINAL source audio that plays on a VideoClip or Audio layer' — and pins down the exact point in the signal chain ('before gain, mute, effects or mixing'). The parenthetical 'a VideoClip through its linked Audio member' disambiguates the linked-audio case, which no sibling tool covers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear usage context ('for an agent running its own speech model; no engine or API key is involved') and a concrete follow-up path ('then apply_transcripts'), plus chunking guidance ('at most 60 s ... so a long clip is several calls') and refusal conditions. It stops short of explicitly naming the alternative tool to use when the agent does NOT have its own speech model (e.g. transcribe_clip), so the routing is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_export_optionsA
Read-only

Read effective export settings and composition limits. Optional preset_id previews that preset without changing project settings; otherwise uses saved project settings, then the global default.

NameRequiredDescriptionDefault
preset_idNoExact preset ID from list_export_presets. Built-in IDs start with builtin:.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the non-mutating nature is known. The description still earns credit for adding the precedence chain (preset preview → project settings → global default) and for explicitly stating the preview does not change project settings, which is the behavior an agent would otherwise worry about. It does not clarify what 'composition limits' actually contain or whether results can be stale.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core action and followed immediately by the branching behavior. No filler, no restatement of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-required-parameter read tool with a fully documented schema and safety annotations, this covers what an agent needs to call it correctly. The only gap is the absence of an output schema combined with no description of the returned shape beyond the phrase 'effective export settings and composition limits'.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the preset_id format (including the 'builtin:' prefix and the reference to list_export_presets) is already fully documented. The description adds the meaningful semantic that supplying it is a non-persistent preview rather than a mode switch, but that is the only increment over structured data. Baseline 3 fits.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: reads 'effective export settings and composition limits'. This is clearly distinct from the sibling create/update/delete_export_preset tools and from list_export_presets, though it never names the closest alternative explicitly. The purpose is unambiguous without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives real situational guidance: pass preset_id to preview a preset without touching project settings, omit it to read saved project settings falling back to the global default. That answers the main 'when do I pass the parameter' question. It stops short of naming an alternative tool or stating exclusions (e.g. when to use list_export_presets instead).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_export_statusA
Read-only

Read an export job as { job }. Omit job_id for the active job, else the most recent one; job is null only when none has run. wait_s blocks until its state changes. queued waits for resources; job.queued names the holders. Records survive MCP reconnects until the app exits.

NameRequiredDescriptionDefault
job_idNoApplication-session export job id.
wait_sNoBlock up to this many seconds for a state change.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so safety profile is covered; the description adds real behavior beyond that: blocking semantics of wait_s, the meaning of the queued state and that job.queued names the resource holders, and the persistence caveat that records survive MCP reconnects only until the app exits. It stops short of enumerating the possible state values or the full return structure, so it is strong but not exhaustive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, each carrying a distinct fact, with the return shape and default resolution front-loaded. A few phrases are compressed to the edge of cryptic ('as { job }', 'job is null only when none has run'), which costs a little readability but no sentence is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description carries the return-value burden and does address the key parts an agent needs: the job object, its null case, and job.queued. What is missing is the set of possible export states and which ones are terminal, which matters for deciding whether to call again with wait_s.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, and the description earns above that by explaining the two behaviors the schema cannot: what omitting job_id resolves to (active job, else most recent, else null) and that wait_s blocks until a state change rather than simply sleeping for the duration. The 0-60 cap and id format are left to the schema, which is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Read an export job') and immediately defines the returned shape as { job }, with the default-resolution rule (active job, else most recent, null when none has run). No sibling tool in the list reads export job state, so the boundary against start_export/cancel_export/retry_export/get_export_options is unambiguous without naming them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete selection guidance: omit job_id to get the active job or the most recent one, and use wait_s to block for a state change. It does not state when *not* to use it (e.g., poll repeatedly instead of using wait_s, or use cancel_export/retry_export once a state warrants action), so no explicit exclusion or alternative routing is provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_param_trackA
Read-only

Read a layer param's animation. track is exactly set_param_track's shape, to edit and send back as is: {"mode":"Static","value":v} or {"mode":"Keyframed","value":[{t_us, value, time_fraction?, in, out, continuity, segment}],"extrapolate"}, t_us timeline-absolute. Beside it, parallel to the keys: keyframe_ids (for update_keyframe / delete_keyframe), local_t_us (layer-local) and preset_ids (the easing preset the segment leaving each key matches, else null). in/out are tangents {x, y, mode} ("Auto" solved on write, "Free" authored); segment is {kind, …}, the class of the segment leaving the key — only Spline reads the tangents. An unset effect param reads as its catalog default. Position params are mode-specific: x/y in XY mode, path_progress in Path mode (a fraction).

NameRequiredDescriptionDefault
layer_idYesLayer id.
param_keyYesVisual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>].

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, and the description goes well beyond that: it discloses that unset effect params read as their catalog default, that position params are mode-specific, and that tangents are only meaningful for Spline segments. These are non-obvious semantics an agent could not infer from the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action is front-loaded and every clause carries real information, but the middle is a dense run of parallel-field explanations (keyframe_ids, local_t_us, preset_ids, in/out, segment) packed into one paragraph. Splitting the return-shape discussion from the mode-specific notes would make it easier to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description takes on the burden of describing the return shape and does so thoroughly, including the parallel key arrays and tangent/segment objects. For a two-parameter read tool, nothing an agent needs to interpret the response is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already enumerates `param_key` values, so the baseline is 3. The description earns above that by adding meaning the schema cannot express: position params differ by mode (x/y in XY, path_progress as a fraction in Path), which clarifies how to interpret the returned value for a given key.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb and resource: 'Read a layer param's animation.' It immediately distinguishes itself from the write-side sibling by noting that `track` is exactly `set_param_track`'s shape, so an agent knows this is the read counterpart without inspecting either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the round-trip workflow explicit ('to edit and send back as is') and names the downstream tools that consume the returned `keyframe_ids` (update_keyframe / delete_keyframe), which tells the agent why it would call this. It lacks an explicit 'do not use this to write' exclusion, but the read/edit pairing is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

import_mediaA
Idempotent

Import media files: every path is checked first (a directory, missing or unreadable file refuses the call, nothing imported), then each is hashed, probed and copied into the project's Media/ folder. Returns { media: [record] } in path order, each the pooled record with derivatives; path / path_rel name the Media/ copy (copying: true while it lands). A pooled file answers existing: true (a repeat is harmless), a missing one now read from here relinked: true; same_content_as names copies of its bytes. .srt/.vtt/.ass pool for apply_subtitles; .svg rasterises to PNG. Unrecorded.

NameRequiredDescriptionDefault
pathsYes1–50 video / audio / image / subtitle files the host can read: absolute, or relative to the open project's folder.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the annotations by disclosing pre-flight validation and atomic refusal ('nothing imported'), hashing and probing, copy location, return shape, the meaning of existing/relinked/copying flags, and pooling behavior. This matches the idempotent and non-destructive hints while adding substantial operational detail.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded, but the body is one dense run-on sentence packed with semicolons and parentheticals, making it harder to scan. The trailing fragment 'Unrecorded.' is cryptic and would benefit from explicit phrasing about undo behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, but the description supplies the return envelope `{ media: [record] }` with field-level explanations for path, path_rel, derivatives, existing, relinked, and same_content_as. It also covers failure modes, making the definition complete enough to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter is already fully documented in the schema (absolute or project-relative paths, 1-50 files). The description adds behavioral context about paths being checked first but does not extend parameter semantics beyond what the schema covers, so the baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Import media files', then immediately states the full pipeline (check, hash, probe, copy into Media/). This clearly distinguishes import_media from siblings like delete_media, apply_subtitles, and extract_clip_audio.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear workflow context: subtitle extensions pool for apply_subtitles and .svg rasterises to PNG, which tells the agent how this tool relates to downstream operations. It does not explicitly state when not to use it, but the context is strong for a tool with no direct import alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

install_motifA

Propose publishing a draft's expected_revision; the library is untouched until the user approves it in WeftCut's Motif panel. Answers {state: awaiting_approval, proposal_id, target: {id, version} | {new_id}}: tell the user to review it, do not poll. list_motifs shows the outcome. A new proposal from the draft supersedes the old. A new id is the name's; a taken one is refused (MotifIdTaken). To replace an installed Motif pass target_id and expected_version.

NameRequiredDescriptionDefault
motif_idYesMotif id (list_motifs).
target_idNoInstalled Motif to replace.
expected_versionNoCurrent version of the publication target.
expected_revisionYesRevision returned by open, read or preview.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false and destructiveHint=false; the description supplies the real behavior: nothing is committed until user approval, the call returns {state: awaiting_approval, proposal_id, target}, a later proposal from the same draft supersedes the earlier one, and a taken name fails with MotifIdTaken. That is meaningful context an agent cannot infer from the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The commit-safety caveat and the return shape are front-loaded, and nearly every sentence carries a distinct fact (return contract, no-poll instruction, supersession, name collision, replacement path). The telegraphic phrasing ('A new id is the name's') is slightly compressed at the cost of a quick first read.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description takes on the return contract and does so well, including the state field, proposal_id, both target shapes, and the error case. What is left implicit is broad (e.g. what invalidates a proposal or how approval surfaces), but nothing needed to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description still adds real meaning by tying target_id and expected_version together as the replacement path and explaining that a new id comes from the name while a collision is refused. It does not restate the expected_revision format beyond the schema's own wording.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a precise verb+resource+manner: 'Propose publishing a draft's expected_revision', and immediately distinguishes the actual effect ('the library is untouched until the user approves it'). This separates it cleanly from open_motif_draft, preview_motif and list_motifs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit about the approval flow and the correct follow-up ('tell the user to review it, do not poll', 'list_motifs shows the outcome'), and gives the exact rule for the replace case ('To replace an installed Motif pass target_id and expected_version'). It names the sibling that reports the outcome, which is the alternative an agent would otherwise guess at.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

jump_toA
Destructive

Move the history cursor to the state right after op op_id (an ops[].op_id of project://history): the way to a state that is neither one undo away nor a checkpoint. An op the stack no longer holds is refused. A revert path like undo, so another session's history lock blocks it. Records nothing; a later edit drops whatever sat ahead, as after an undo. Answers at: the op the cursor now sits on.

NameRequiredDescriptionDefault
op_idYesThe op to land on: an `ops[].op_id` of `project://history`.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the destructiveHint annotation, the description discloses key behavior: it records nothing, a later edit drops the history ahead, it is refused if the op is no longer on the stack, and another session's history lock blocks it. It also describes the return value as the op the cursor now sits on.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the core action. Every clause adds relevant behavior or context, with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter history-navigation tool with no output schema, the description covers purpose, failure conditions, locking, side effects, and the response value. No essential invocation detail appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the single parameter is already documented. The description adds some nuance by clarifying that the cursor moves to the state right after the op, but it does not add substantial new parameter-level meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: moving the history cursor to the state right after a given op. It distinguishes this from undo and checkpoint restoration by explaining that it reaches a state that is neither one undo away nor a checkpoint.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains when to use this tool: to land after an op that is still held by the history stack. It also states failure conditions, names undo and checkpoints as related alternatives, and notes that a session history lock can block the operation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

launch_weftcutA
Idempotent

Launch the WeftCut desktop app (opens its GUI window on the user’s machine) and wait until its MCP endpoint is reachable. On success the full WeftCut tool catalog becomes available in this session automatically (tools/list_changed). Safe to call when already running — reports that instead of launching twice. Use after weftcut_status says the app is not running.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (idempotentHint=true, destructiveHint=false, openWorldHint=false) it discloses real side effects: a GUI window is opened on the user's machine, the call blocks until the endpoint is reachable, and the tool list changes for the session. It does not say what happens on launch failure or how long it waits before giving up, which is the main remaining behavioral gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the primary action and effect, then the idempotent-behavior caveat, then the prerequisite. No filler or restated field names.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter lifecycle tool with no output schema and annotations already declaring safety, the description covers purpose, blocking behavior, side effects, idempotency, and prerequisite. An agent has everything needed to decide to call it and to interpret a "already running" response.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate; schema coverage is 100% and additionalProperties=false is self-documenting. Baseline for a no-parameter tool applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Launch the WeftCut desktop app") plus the concrete effect (GUI window opens, MCP endpoint becomes reachable, tool catalog appears via tools/list_changed). Among siblings it is clearly the process-lifecycle tool, distinguishable from weftcut_status and from the project/motif loading tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives both the when-to-use condition ("Use after weftcut_status says the app is not running") and the when-it-is-unnecessary case ("Safe to call when already running — reports that instead of launching twice"). It names the sibling that gates it explicitly, so no inference is required.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_export_presetsA
Read-only

List built-in and personal export presets, complete portable settings, default ID and name limit. Available without a project.

NameRequiredDescriptionDefault

No parameters

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds the useful constraint that no project context is required, but the phrase 'complete portable settings, default ID and name limit' is too compressed to convey clearly what each preset entry contains.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with the verb first and no filler. The trailing clause about 'default ID and name limit' is dense to the point of ambiguity, which slightly hurts comprehension even though brevity is good.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of explaining what is returned, and while it gestures at preset contents and a name limit, it does not make the return shape or ordering clear. For a trivial parameterless list tool this is close to adequate, but an agent cannot predict the response structure from it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters and the schema is an empty object, so there is nothing for the description to disambiguate. Baseline for a parameterless tool applies and nothing misleads.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb ('List') and resource ('export presets') with a scope qualifier ('built-in and personal'), which distinguishes it from the sibling write tools create_export_preset, update_export_preset and delete_export_preset. It stops short of distinguishing it from get_export_options, which an agent might reasonably confuse it with.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Available without a project' gives one concrete precondition, implying it can be called before a project is opened. There is no explicit guidance on when to pick this over get_export_options or how it pairs with start_export, so alternatives are only weakly implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_motifsA
Read-only

List built-in, installed and draft Motifs with props schemas, revisions and diagnostics. A draft with a proposal carries publication {state: awaiting_approval|approved|rejected, note?, version?, rebound?}.

NameRequiredDescriptionDefault
statusNoFilter by lifecycle status.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds genuinely new behavioral context by stating that returned entries carry props schemas, revisions and diagnostics, and by sketching the publication object on draft proposals with its state enum. It stops short of describing pagination or ordering.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact sentences with the enumeration scope front-loaded and no filler. The second sentence is dense, using shorthand like 'rebound?' without explanation, but it is information-bearing rather than wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of characterizing return values and partially does so via props schemas, revisions, diagnostics and the publication shape. For a single-optional-parameter read-only list tool this is close to sufficient, missing only ordering or volume expectations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single status parameter has an enum with its own description, so the schema does the work. The description's phrase 'built-in, installed and draft' loosely mirrors the enum values but adds no format or filtering semantics beyond them. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb plus resource with explicit scope: 'List built-in, installed and draft Motifs'. The scope wording distinguishes it from the singular siblings such as read_motif and open_motif_draft, though those siblings are not named directly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the enumeration scope suggests 'use this to see all motifs', which contrasts implicitly with read_motif for one motif. There is no explicit when-to-use versus alternatives, no mention of when to prefer read_motif or open_motif_draft instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

merge_captionsA
Destructive

Merge two or more captions of ONE caption lane into the earliest, as one recorded edit: its span becomes the union, its text the texts joined by a line break in time order, its style stays; the others are deleted. A gap between them is spanned. Refuses a layer that is not a caption, captions on different lanes, and a union that would overlap another cue of the lane (LayerOverlap). Returns the merged caption's record with removed.

NameRequiredDescriptionDefault
layer_idsYesTwo or more captions on one caption track.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructiveHint=true, and the description genuinely earns its keep on top of that: it discloses exactly what is destroyed (the other captions are deleted), what is preserved (style stays, span becomes the union), that a gap is spanned, and the `LayerOverlap` failure mode. It's one step short of a 5 because it doesn't say whether the merge is a single undoable edit beyond implying 'one recorded edit'.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and scope, then effects, then refusal conditions. Dense but every clause carries information; nothing is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by stating the return value (the merged caption's record plus `removed`) and the error case. For a destructive one-parameter tool this is nearly complete; only undo/reversibility is left unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter is already described as 'Two or more captions on one caption track,' so the baseline would be 3. The description adds real meaning: the array is ordered by time, the earliest becomes the merge target, and all entries must share one lane — semantics an agent could not infer from the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (merge captions) and pins the scope precisely: two or more captions of ONE caption lane, collapsed into the earliest as a single recorded edit. That level of specificity separates it cleanly from siblings like split_layer, correct_caption_text, and trim_layer without needing to name them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-not conditions: refuses non-caption layers, captions on different lanes, and unions that would overlap another cue. It stops short of naming the sibling tools to use instead (e.g., correct_caption_text for text-only edits or split_layer for the inverse), so the alternative routing is left implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

move_effectA
Idempotent

Reorder an effect within its layer's chain. new_index is 0-based; 0 = first applied. Must be < effect count.

NameRequiredDescriptionDefault
layer_idYesLayer id.
effect_idYesEffect id.
new_indexYesTarget position in the chain; 0 is applied first.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotentHint=true and destructiveHint=false, so safety is covered. The description adds real behavioral context beyond that: the index is 0-based, 0 means first applied, and the value must be strictly less than the effect count, which tells the agent the valid range and implicitly that other effects shift rather than being removed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short clauses, front-loaded with the action, then the indexing convention and its bound. No filler or redundant restatement of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple three-parameter reorder with full schema coverage and annotations that cover safety, nothing essential is missing. It stops just short of describing what happens to the displaced effects' indices or how an out-of-range index is reported.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description does add one piece of meaning the schema lacks — the upper bound 'Must be < effect count' — but it largely restates the schema's 'new_index' wording about 0 being applied first.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Reorder an effect within its layer's chain.' This cleanly separates it from add_effect, update_effect, and delete_effect, all of which operate on the same entity without changing position.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the usage context clear (repositioning an existing effect within its chain) but never names alternatives or exclusions, e.g. that it is not for adding effects or for moving effects between layers. The distinction from update_effect is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

move_layersA

Move a set of layers as one recorded edit. layer_ids[0] is the seed: land it with one of t_start_us (absolute) or delta_us, or with neither for a lane change alone. Every member keeps its offset on its own track, link partners included unless escape_link; track_id moves only the seed — a track of the same composition, or "spawn" for a fresh top track. insert: true is the ripple move: the set's span closes behind it and opens at its landing on every track, so a later landing is read with that span already closed; it refuses like delete_layers { ripple: true }. Each layer snaps on its own grid. A start before 0, an occupied landing (LayerOverlap) or a lock refuses whole. Returns { layers, rippled, track?, pruned_tracks }.

NameRequiredDescriptionDefault
insertNoClose the span behind and open room at the landing, on every track. Default false: an occupied landing refuses.
delta_usNoSigned shift of the seed, µs; positive moves later. Exclusive with `t_start_us`.
track_idNoThe seed's destination track, or "spawn" for a fresh top track. Omit to keep its track.
layer_idsYesThe layers to move, all in one composition; the first is the seed.
t_start_usNoWhere the seed starts afterwards, timeline. Exclusive with `delta_us`, µs.
escape_linkNoMove only the named layers, leaving link partners in place. Default false.

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only assert openWorldHint=false and destructiveHint=false; the description goes well beyond that by disclosing ripple semantics ("the set's span closes behind it and opens at its landing on every track"), atomic refusal ("a start before 0, an occupied landing (LayerOverlap) or a lock refuses whole"), and the ripple-with-gap refusal analogous to delete_layers { ripple: true }. It even names the return shape, which is valuable since no output schema exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action and seed concept are front-loaded and no sentence is filler — grid snapping, atomicity, and return shape each add distinct information. The dense semicolon-and-em-dash packing makes it slower to parse than it needs to be for a caller skimming before invocation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter mutation with no output schema, the description covers the essentials: what moves, what anchors the move, how links and tracks behave, error/refusal conditions, and the return tuple. Nothing an agent needs in order to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds genuine semantics the schema lacks: layer_ids[0] being the seed, every member keeping its offset on its own track including link partners, escaped via escape_link, and track_id relocating only the seed rather than the whole set. That relationship-level meaning is not derivable from the per-field schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a specific verb and resource ("Move a set of layers") plus the transactional framing ("as one recorded edit"). It is far from tautological, but it never names or contrasts the closely related siblings (shift_layers, retime_layers, move_layers_to_composition, restack_layer), so an agent must infer the boundary itself.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage conditions within the tool are stated precisely: the seed lands via t_start_us OR delta_us OR neither for a lane change alone, and insert:true selects the ripple behavior. However, there is no guidance on when to prefer this over shift_layers or retime_layers, which occupy adjacent semantic space in the sibling list, so the when-to-use-vs-alternative question is left implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

move_layers_to_compositionA

Move selected layers into another composition. The anchor starts at t_start_us; other members retain offsets. Lane assignment is per source track: omit to_track_id to find space, use spawn for fresh lanes, or name a free unlocked lane. Refuses mixed source compositions, locks, cycles, negative starts and membership changes involving retimed Groups. Internal links/transitions move; straddling ones are cut. Markers stay; compositions autofit; Group windows stay fixed.

NameRequiredDescriptionDefault
layer_idsYesThe layers to move; at least one, all in one composition.
t_start_usYesThe anchor's start time on the DESTINATION's clock — absolute, not a delta.
to_track_idNoA lane id (locked or occupied REFUSES), "spawn" for a fresh top lane, or omit to bounce to the nearest free lane.
anchor_layer_idYesWhich member `t_start_us` positions; every other member keeps its offset from it.
to_composition_idYesThe destination composition (`project://compositions`). The root is allowed — that is the move back out of a Group.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Rich disclosure beyond the annotations: offsets are preserved relative to the anchor, internal links/transitions travel with the layers, straddling ones are cut, markers stay, and Group windows stay fixed. Annotations only say non-destructive and closed-world, so this adds real value; note the mild tension with destructiveHint=false, since cutting straddling transitions is a lossy side effect, though it is transparently disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then behaviours, then refusals in roughly priority order, with no filler sentences. The telegraphic phrasing ('compositions autofit; Group windows stay fixed') is dense but each clause carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers refusal cases, link/transition handling, marker and Group behaviour for a complex multi-parameter mutation, which is what an agent needs before committing. Without an output schema, it could still say what a successful call returns or how partial failures are reported.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, yet the description still adds relational meaning the schema alone doesn't: the anchor is positioned at t_start_us while other members keep their offsets, and lane assignment is scoped per source track. It also clarifies that omitting to_track_id is a valid bounce-to-free-lane strategy rather than an error.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with scope: 'Move selected layers into another composition,' which implies the cross-composition variant versus in-composition moves. It never names the neighbouring move_layers or paste_layers siblings, so the agent must infer the boundary itself.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-not conditions ('refuses mixed source compositions, locks, cycles, negative starts and membership changes involving retimed Groups') and lays out the three lane strategies for to_track_id. What's missing is a direct statement of when to pick this over move_layers or paste_layers.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

move_trackA
Idempotent

Move a track to a different z-order position, one recorded edit; 0 is the bottom of the stack, and the position must be below the track count (TrackPositionOutOfRange). Refuses a reserved A roll / B roll track (TrackReserved; they keep their place), a locked track (TrackLocked) and a track holding a locked layer (LayerLocked).

NameRequiredDescriptionDefault
track_idYesTrack id.
new_positionYesTarget index in the stack; 0 is the bottom.

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotentHint=true and destructiveHint=false, so the safety profile is largely covered. The description still adds real value by naming the domain error codes (TrackPositionOutOfRange, TrackReserved, TrackLocked, LayerLocked) and calling the operation "one recorded edit," which hints at undo/checkpoint integration. It stops short of describing how intervening tracks shift or what the response contains.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense sentence that front-loads the action and scope before the error conditions. Every clause (index origin, range limit, three refusal cases) carries needed information, though the semicolon-chained error list makes it harder to scan than a short bulleted structure would.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return/error burden and does so by enumerating the exact failure modes and the position validity rule. For a two-parameter mutation with reassuring annotations, this is nearly complete; only the effect on tracks between source and destination is left unstated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description adds genuine meaning: the position is a z-order index with 0 at the bottom of the stack, and the valid range must be strictly below the current track count. That range constraint is not captured in the schema's integer type.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource ("Move a track to a different z-order position") and scopes it as "one recorded edit." The resource (track) distinguishes it from layer-level siblings like move_layers and restack_layer, but it never explicitly names an alternative or contrasts behavior with them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage context is clear through the enumerated refusal conditions: reserved A/B roll tracks, locked tracks, and tracks holding a locked layer cannot be moved, which implicitly tells the agent to unlock first. There is no explicit when-to-use-vs-sibling routing, such as preferring move_layers for layer restacking.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

open_motif_draftA

Open a draft; returns {motif_id, revision}. directory: a live linked folder (reopening returns its draft). motif: a draft id resumes that draft, any other id copies it. copy: an independent copy of any Motif, drafts included. Copies answer source {id, version}. empty: 960×540, 5 s, no props.

NameRequiredDescriptionDefault
sourceYesExactly one source variant.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false and destructiveHint=false, so the description carries real weight here and delivers: the return shape {motif_id, revision}, idempotent reopening of a directory draft, resume-vs-copy behavior for motif ids, and the fact that copies report their source {id, version}. It stops short of stating persistence/locking behavior (e.g., what happens if a draft is already open elsewhere).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and return shape, then one compact line per source variant with no filler. The telegraphic register ("Copies answer source {id, version}") is dense enough that an agent may need a second read, but nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single nested oneOf parameter with no output schema, the description covers four of five variants plus the returned {motif_id, revision}, which is a lot of the needed surface. The omission of the 'zip' source kind is the notable gap, since that path format and its consequences are documented nowhere else.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description genuinely adds meaning the schema lacks: the schema labels both 'motif' and 'copy' entries identically as "Motif id (list_motifs)", and only the description distinguishes resume from duplicate. The 'empty' defaults (960×540, 5 s, no props) are also absent from the schema. The 'zip' variant is left entirely unexplained, which keeps this from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Open a draft" gives a specific verb plus resource, and the per-variant lines make clear this tool materializes a draft from one of several sources. It never names a sibling (read_motif, preview_motif, install_motif, open_project), so the agent must infer the boundary with those tools from names alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description effectively routes the agent across variants: directory = live linked folder, motif = resume if draft id else copy, copy = independent duplicate, empty = blank 960×540 5 s project. It gives clear usage context for each mode but no explicit exclusions relative to sibling motif tools or guidance on which tool to pick when a Motif merely needs inspection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

open_projectA
Destructive

Open a project folder (the one holding project.json) in the editor, as the start screen's Open does; only one the user asked for. The project open before is saved; its undo history is dropped. The folder already open is not reloaded and answers already_open: true. Recent projects: read_project { view: "session" }. Returns { name, dir, replaced, already_open }.

NameRequiredDescriptionDefault
pathYesAbsolute path of the project folder.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say destructiveHint=true; the description turns that into concrete consequences (the currently open project is saved, its undo history is dropped) and discloses the no-op case (the already-open folder is not reloaded and answers already_open: true). That is exactly the extra context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action, then the safety consequences, then the edge case and return shape, with no filler sentences. It is telegraphic in places ("only one the user asked for", the inline read_project snippet), which is efficient but slightly terse to parse on first read.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by listing the return fields (`name, dir, replaced, already_open`). Combined with the destructive side effects, the already-open no-op, and the parameter constraint, an agent has everything it needs to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the path param is already documented as an absolute path, so the baseline is met by the schema. The description still adds meaning by telling the agent what the path must point at – a folder containing project.json – which prevents pointing it at an arbitrary directory.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Open a project folder ... in the editor") and pins down exactly which folder qualifies ("the one holding project.json") plus an anchoring reference to the start screen's Open. That is enough to separate it from siblings like create_project and read_project without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"only one the user asked for" gives an explicit usage constraint against speculative opening, and it routes the agent to `read_project { view: "session" }` for recent projects. It stops short of naming the boundaries against create_project or explicitly saying when NOT to call it, so it lands just under full marks.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

paste_layersA

Duplicate a set of layers as one recorded edit — the only copy tool. layer_ids[0] is the seed; land its clone with exactly one of t_start_us or delta_us (from the seed's start). Every other clone shifts by the same delta on its source's track; track_id moves only the seed's clone. Nothing is expanded: pass link partners to copy them. All-or-nothing: a locked or occupied destination refuses the batch (TrackLocked, or LayerOverlap naming the source). Two or more clones link to each other. A Group clone shares its composition unless unique. Returns { clones: [{ source, clone }], layers, groups? }; groups names each unique copy's composition_id.

NameRequiredDescriptionDefault
uniqueNoGive each Group clone its own deep copy of the Group's composition, so editing inside it leaves the source alone. Default false: another instance of the same composition.
delta_usNoStart of the seed's clone relative to the seed's own start, so every clone shifts by that much. Exclusive with `t_start_us`.
track_idNoTrack for the seed's clone. Omit to keep it on the seed's track.
layer_idsYesThe layers to clone; the first is the seed the start time refers to.
t_start_usNoAbsolute start time of the seed's clone; the other clones keep their offsets from it. Exclusive with `delta_us`.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations (which only say destructiveHint=false, openWorldHint=false) by disclosing atomicity — a locked or occupied destination rejects the whole batch — and naming the failure modes TrackLocked and LayerOverlap. It also reveals non-obvious side effects such as automatic linking among two or more clones and Group clones sharing composition by default.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the one-line purpose, then rules, then return shape; almost nothing is redundant. A few clauses are compressed to near-telegraphic terseness ('Two or more clones link to each other', 'Nothing is expanded'), which costs a little readability for an already dense description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter mutation tool with no output schema, the description still supplies the return shape ({ clones, layers, groups? }) and explains the optional groups field. Combined with atomicity, error names, and linking semantics, an agent has enough to call it correctly and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3, but the description adds cross-parameter meaning the schema does not: how delta_us propagates to every clone while track_id affects only the seed's clone, and that t_start_us/delta_us are mutually exclusive. This resolves the ambiguity an agent would otherwise hit when reading the parameters in isolation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Duplicate a set of layers') and immediately differentiates itself from siblings with 'the only copy tool', so an agent scanning the list knows this is the copy primitive rather than move/shift/retime. The recorded-edit framing tells the agent the whole call is one undoable unit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete invocation rules: layer_ids[0] is the seed, exactly one of t_start_us or delta_us must be supplied, and links are not implicitly expanded so partners must be passed explicitly. It does not name a competing sibling or spell out a when-not case, largely because it claims to be the only copy tool, so there is little to exclude.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

preview_motifA
Read-only

Render a Motif at each local_t_s as one labelled PNG contact sheet (frames keep their alpha), plus the exact revision and the canvas and frame sizes. Each frame is the whole canvas scaled to fit, never cropped. Refreshes this draft's linked files first; refuses an invalid directory or a stale expected_revision.

NameRequiredDescriptionDefault
propsNoInstance values; missing keys use defaults.
widthNoMaximum frame width in pixels (default 640); the whole canvas is scaled to fit.
heightNoMaximum frame height in pixels; the whole canvas is scaled to fit.
motif_idYesMotif id (list_motifs).
local_t_sYes1–24 times, in seconds from the Motif's start (its frame(t) time), not timeline time.
expected_revisionNoRevision returned by open, read or preview.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses framing behavior ('Each frame is the whole canvas scaled to fit, never cropped'), alpha preservation, a files-refresh step, and two refusal conditions. The only tension is that 'refreshes this draft's linked files first' hints at a side effect on linked assets while readOnlyHint=true; read as a re-sync/reload this is consistent, but it is worth clarifying. Returned metadata (revision, canvas and frame sizes) is also stated, which annotations alone would not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the artifact and its key property (alpha-preserving contact sheet), then constraints, then preconditions. No filler or restated title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description does the necessary work by describing the return payload (contact sheet, exact revision, canvas and frame sizes). Two gaps remain: where the PNG sheet is delivered (path, attachment, or artifact reference) is unstated, and 'invalid directory' refers to a directory the input schema does not expose.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already explains motif_id, local_t_s (motif time, not timeline time), width/height scaling, props defaults, and expected_revision provenance. The description reinforces the fit-not-crop semantics of width/height and the staleness rule for expected_revision but adds no syntax or format detail the schema lacks. Baseline 3 applies when the schema carries the parameter burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource ('Render a Motif') and pins down the output artifact precisely: 'one labelled PNG contact sheet (frames keep their alpha)'. That makes it clearly distinguishable from siblings like render_frames or read_motif, since it is a contact-sheet visual preview rather than a read or a timeline render.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage context is concrete: render at each local_t_s to preview a motif, with preconditions spelled out ('Refreshes this draft's linked files first; refuses an invalid directory or a stale expected_revision'). It stops short of explicitly naming an alternative sibling (e.g. render_frames or read_motif) or saying when not to preview, so it is strong but not complete routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_motifA
Read-only

Read manifest, revision and file inventory. With path: a UTF-8 file returns its text (max 256 KiB); a binary file returns only {size, sha256}. Includes working-directory diagnostics.

NameRequiredDescriptionDefault
pathNoPath relative to the Motif root.
motif_idYesMotif id (list_motifs).

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so safety is covered; the description nonetheless adds substantive behavior: the 256 KiB text cap, the fact that binary files return only {size, sha256} instead of content, and inclusion of working-directory diagnostics. It stops short of saying what happens at truncation or when the path is missing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short, front-loaded statements: inventory first, the path-mode branch second, the ancillary diagnostics last. Every clause carries information; nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of describing returns, and it does so well for the file case (text vs. {size, sha256}). It is a read-only tool with annotations covering the safety profile, so the remaining gap — the shape of the manifest/revision/inventory payload — is modest.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both parameters are already documented and the baseline is 3. The description adds genuine meaning for path by describing the divergent outcomes (UTF-8 text vs. binary metadata), which lifts it slightly, but motif_id semantics (listing via list_motifs) are left entirely to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and concrete resources: reads the motif's manifest, revision, and file inventory. The 'With path' clause extends this precisely to single-file reads. It does not, however, distinguish itself from nearby siblings such as preview_motif, open_motif_draft, or read_project, so an agent must infer the boundary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The conditional 'With path:' sentence clearly explains the two invocation modes — omit path for the inventory, supply path for a file read — which is exactly the decision an agent must make. There is no guidance on when to prefer this over preview_motif or open_motif_draft, and no stated exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_projectA
Read-only

The project://* views as a tool result, for clients without resources. view: composition, compositions, media (with id, one item's card), tracks (layer envelopes), layer (needs id), markers, links, transitions, settings (preferences, role mix, metadata), history, session (who holds the session), effects (effects catalog), tacks (review tacks; composition_id narrows), taste (style tokens + provenance), media_thumbnail / media_frame (an IMAGE; id is the media id, media_frame takes src_us). composition, tracks, markers, links, transitions take composition_id for a Group's (root if omitted); others refuse it. JSON views answer as text.

NameRequiredDescriptionDefault
idNoThe layer id for view `layer`; the media id for `media` (optional) / `media_thumbnail` / `media_frame`.
pathNoFor `skill`: a file beside SKILL.md, as SKILL.md names it (`craft/rules.md`); omit for SKILL.md.
viewYesWhich view to read.
src_usNoFor `media_frame`: the frame time in the source, µs.
composition_idNoFor the per-composition views: a Group's composition; omit for the root.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so safety is covered, and the description adds genuinely non-obvious behavior: JSON views are returned as text, while `media_thumbnail` and `media_frame` return an IMAGE. It also discloses that most views reject `composition_id` rather than silently ignoring it, which matters for correct invocation. It stops short of describing size/volume or error behavior for invalid ids.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first clause and the rest is a dense but purposeful enumeration with no filler sentences. The long semicolon-chained paragraph is hard to scan for 17 views, and the omission of `skill` while listing every other view is a structural inconsistency, but no sentence is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a multi-view reader with no output schema, the description supplies what an agent actually needs: the full view catalog with per-view meaning, which parameters each view honors or refuses, and the distinction between text JSON responses and IMAGE responses. The only omission, the `skill`/`path` combination, is fully documented in the schema itself, so nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description goes further by explaining what each `view` value actually returns (e.g. `settings` = preferences, role mix, metadata; `taste` = style tokens + provenance; `session` = who holds the session) and by mapping `id` and `composition_id` to the specific views that honor them. The one gap is that the `skill` view — referenced only by the schema's `path` parameter — is never explained in the description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens by stating exactly what the tool returns: the `project://*` views surfaced as a tool result, explicitly for clients without resource support. It then enumerates all readable views (composition, tracks, markers, media, session, etc.), so an agent knows this is a read-only project introspection tool rather than a mutation. It does not explicitly contrast itself with other read-oriented siblings such as `get_param_track` or `check_composition`, which keeps it below a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is a clear eligibility condition ('for clients without resources') and per-view rules: `layer` needs `id`, `media_frame` takes `src_us`, `tacks` accepts `composition_id` to narrow. It also states which views take `composition_id` and that 'others refuse it', which is real routing guidance. However, it gives no guidance on choosing `read_project` over other read tools in the sibling list, so the when-to-use story is only partially covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

redoA
Destructive

Redo the next edit. Errors with NothingToRedo if no redo is available. A new commit truncates the redo tail. Answers redone: the op reapplied.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations declaring destructiveHint=true and openWorldHint=false, the description still adds real value: it discloses the NothingToRedo error condition, the history rule that a new commit truncates the redo tail, and the response key 'redone'. What it does not explain is whether the redo entry is consumed or how the stack shrinks after a successful redo, leaving a small gap around the destructive behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, each carrying distinct information (action, error, history rule, return field), with the core action front-loaded. Nothing is repetitive or padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter tool with no output schema, the description covers the action, the failure mode, the history-truncation rule, and the return key — enough to call it correctly. The only shortfall is that it never states the relationship to 'undo', which an agent needs to decide between the two.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate and the baseline applies. No schema-level semantics are needed or missing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource ('Redo the next edit') and makes the scope explicit — it reapplies exactly one edit, the next one on the redo stack. An agent can distinguish this from the sibling 'undo' without opening the schema, since a redo is the direction of history traversal being moved forward.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage context is implied rather than stated: the NothingToRedo error tells the agent a redo is only valid after an undo, but there is no explicit when-to-use/when-not-to-use guidance and no naming of the 'undo' sibling as the counterpart. The agent must infer the undo/redo pairing from general knowledge.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_pausesA
Destructive

Cut pauses out of the audio a clip plays and ripple downstream, as one edit. layer_id is an Audio layer, or a VideoClip read through its linked Audio member; link members are cut together, on the frame grid when picture is linked. pauses cuts exactly those ranges (detect_pauses output, e.g. the subset the user kept); without it the clip is detected at threshold_db / min_pause_us (detect_pauses' defaults). pad_us keeps 100000 µs of each pause on each side; a pause at a clip edge trims whole. Returns { surviving_layer_ids, removed, removed_us }. To review first: detect_pauses, then one create_tacks batch. Refuses whole, before any write: RippleInsideHole (a layer on another track starts inside a pause), RippleCollision, RippleLinkStraddles, RippleLockedLayer / TrackLocked, InvalidArgument (pad too large, a pause outside the clip or overlapping another, a clip silent end to end).

NameRequiredDescriptionDefault
pad_usNoMicroseconds of each pause KEPT on each side. Default 100000; 0 erases each pause whole. Must satisfy 2 * pad_us < min_pause_us.
pausesNoTimeline ranges to cut, as `detect_pauses` returned them; replaces detection, so not with `threshold_db` / `min_pause_us`.
layer_idYesTarget Audio layer id, or a VideoClip id that delegates to its linked Audio layer.
min_pause_usNoShortest pause worth removing, µs, as `detect_pauses` takes it. Omit for its default.
threshold_dbNoPeak threshold, dBFS (≤ 0), as `detect_pauses` takes it. Omit for its default.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and openWorldHint=false, but the description adds substantial context beyond them: the edit is atomic and ripples downstream, link members are cut together, edge pauses trim whole, and every refusal (`RippleInsideHole`, `RippleCollision`, `RippleLinkStraddles`, `RippleLockedLayer`/`TrackLocked`, `InvalidArgument`) happens before any write. This is rich disclosure of the destructive semantics and atomicity guarantees.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and efficient throughout — no filler sentences, every clause carries operational detail. It is densely packed with semicolon-chained clauses and a long error enumeration, which makes it harder to scan than a shorter, segmented version would be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, link-aware tool with no output schema, the description covers return shape (`{ surviving_layer_ids, removed, removed_us }`), mode selection, defaults, atomicity, and the full pre-write failure set. Nothing an agent needs in order to call it safely is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3; the description still adds meaning, notably that `layer_id` may be a VideoClip delegating to its linked Audio layer, that `pauses` cuts exactly those ranges rather than re-detecting, and that `pad_us` keeps 100000 µs per side while an edge pause trims whole. It also clarifies that `threshold_db`/`min_pause_us` fall back to `detect_pauses` defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource plus scope: 'Cut pauses out of the audio a clip plays and ripple downstream, as one edit.' It implicitly distinguishes itself from the sibling `detect_pauses`, which only detects, by making clear this one mutates and ripples.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states the two modes of operation — supply `pauses` from `detect_pauses` output (e.g. the subset the user kept) versus letting the clip be detected at `threshold_db` / `min_pause_us` — and names the review-first alternative path: `detect_pauses`, then one `create_tacks` batch.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rename_compositionA
Idempotent

Name a Group's composition (label: null or blank clears it back to the derived name). Recorded, so undo reverts it. The root composition refuses (RootComposition): it has no name — it is the timeline. Composition ids: project://compositions.

NameRequiredDescriptionDefault
labelNoThe new name; null or blank clears it.
composition_idYesComposition id.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (idempotent, non-destructive, closed-world), the description discloses three things an agent could not infer: the change is recorded so undo reverts it, the root composition rejects the call with a named error, and blank/null is the reset path. That is meaningful behavioral context for a mutation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the action, then the reset semantics, then the undo/refusal caveats. No filler and no restatement of the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter tool with no output schema, the definition covers action, reset behavior, undo consequences, and the one failure case with its error identifier. It stops short of describing what the response returns or how a derived name is computed, which are minor omissions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, and the description adds a hint about composition id form (`project://compositions`), which the schema does not supply. The clear-semantics for label duplicate the schema slightly, but the id format guidance is genuine added value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource, 'Name a Group's composition', which is clearly distinct from rename_track or rename_layer. It does not explicitly contrast itself with the sibling update_composition, so an agent must infer that this tool is the label-only path, but the core purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a concrete when-not condition: the root composition refuses with `RootComposition` because it is the timeline itself. It also states how to clear a name via null/blank. What is missing is explicit routing against update_composition, but the exclusion guidance present is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rename_layerA
Idempotent

Rename a layer: label, or null to clear it. One recorded edit. Times are move_layers (start) and trim_layer (one edge); enabled / locked are set_layer_flags; kind-specific params are update_layer_params.

NameRequiredDescriptionDefault
labelYesDisplay name; null clears it.
layer_idYesLayer id.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover idempotence, lack of destructiveness, and closed-world behavior. The description adds useful context beyond that by stating that the operation produces one recorded edit and that a null label clears the value. It does not contradict the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The main action and null behavior are front-loaded in the first sentence, and the routing information is compact. The second sentence is slightly compressed but still useful, and there is no unnecessary filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter mutation tool with full schema coverage and annotations, the description covers purpose, behavior, and alternative routing sufficiently. No output schema exists, so the absence of return-value explanation is not a material gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the schema already documents both layer_id and label, including that null clears the display name. The description repeats the null-clearing behavior but adds no parameter semantics beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: rename a layer via its label, with null clearing it. It also explicitly separates related operations that belong to sibling tools such as set_layer_flags, update_layer_params, move_layers, and trim_layer, making the tool distinguishable without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly assigns label changes to this tool and routes times, enabled/locked flags, and kind-specific parameters to named sibling tools. This gives explicit when-to-use and when-to-use-alternatives guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rename_trackB
Idempotent

Name a track, reserved A roll / B roll / audio / caption tracks included. Recorded. label: null (or blank) clears it back to the derived name — its role, or its position in the stack.

NameRequiredDescriptionDefault
labelNoThe new name. null or blank clears it back to the displayed-by-default name.
track_idYesTrack id.

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotentHint=true and destructiveHint=false, so the safety profile is covered. The description adds one genuinely useful behavior — that renaming applies even to reserved A roll / B roll / audio / caption tracks — but 'Recorded.' is ambiguous (undo history? export metadata?) and nothing is said about error cases or whether reserved tracks can be restored. This is useful added context without being rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The clearing behavior is front-loaded reasonably and the sentence about role tracks earns its place, but 'Recorded.' is a dangling fragment with no clear referent, and the first sentence's grammar ('Name a track, reserved ... included') is awkward enough to slow parsing. Some tightening is needed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a simple two-parameter mutation with full schema coverage and annotations, and no output schema to explain, so the description covers most of what is needed. However, with no sibling differentiation against rename_layer and an unexplained 'Recorded.' clause, an agent still has open questions before invoking it confidently.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already states that null or blank clears the name back to the displayed-by-default name. The description largely restates that, though it does add a small amount of meaning by explaining what the derived name is — the track's role, or its position in the stack. That is a marginal gain over the schema, so the baseline 3 fits.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource, 'Name a track', which is clearly distinct from the sibling rename_layer (layers) and rename_composition. It also tells the agent that reserved role-bearing tracks (A roll / B roll / audio / caption) are in scope, which sharpens the purpose beyond the bare name. The trailing fragment 'Recorded.' is opaque and does not help distinguish the tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit when-to-use, when-not-to-use, or pointer to an alternative such as rename_layer versus rename_track. The only implicit guidance is that reserved role tracks may also be renamed, which tells the agent about scope but not about selection between tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

render_framesA
Read-only

See the root composition as export renders it (footage, Motifs, text, captions and Groups composited) as JPEGs. Pass t_us, or layer_ids to judge beats over their whole span: each is sampled settled, in the middle, in its exit, and just after every cut or shot change under it. Returns one labelled contact sheet (default) or one image per frame, plus each time and why it was taken. Read-only; refused while an export runs, or (RendererCannotDraw) for frames with effects, crops or transitions the host cannot draw; without: ["effects"] skips effects. Seconds per frame.

NameRequiredDescriptionDefault
t_usNoTimeline times in µs.
sheetNoOne contact sheet (default true) or one image per frame.
widthNoFrame width in px; default 640.
withoutNoSkip clip effects; the answer lists them in omitted. Crops and transitions still refuse.
layer_idsNoRoot layers to sample over their spans (at most 24 frames in all).

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint/openWorldHint annotations, the description discloses failure modes (refused while an export runs, RendererCannotDraw for effects, crops or transitions the host cannot draw), the without:["effects"] escape hatch, and exactly what is sampled around cuts and shot changes. That is rich operational context an agent could not infer from structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The key scope and sampling behavior are front-loaded and almost every clause carries signal. It is dense and telegraphic, and the dangling final phrase 'Seconds per frame.' is unclear enough to slightly hurt the structure.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description still covers the return shape (one labelled contact sheet by default or one image per frame, plus each time and why it was taken), the error conditions, and read-only semantics. Nothing an agent needs in order to call this correctly appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: the t_us vs layer_ids choice, the four-point sampling strategy per beat, and that sheet defaults to a labelled contact sheet. The trailing fragment 'Seconds per frame.' is ambiguous and adds little.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: render the root composition exactly as an export would, compositing footage, Motifs, text, captions and Groups, as JPEGs. It is clearly distinct from siblings like compare_frames or start_export, though it never names those alternatives explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete usage context: pass t_us, or layer_ids to judge beats over their whole span, and it explains the sampling policy (settled, middle, exit, after each cut). It does not say when to prefer compare_frames or preview_motif instead, so it falls short of explicit when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

restack_layerA
Idempotent

Restack a visual layer above/below a stable layer or track anchor. Supply exactly one anchor; track anchors work through gaps. A sole occupant carries its track; shared or reserved sources split onto a fresh track. Reserved tracks stay put. Audio, cross-composition and self-anchors reject. Already in place records nothing. One undo step.

NameRequiredDescriptionDefault
layer_idYesThe visual layer to restack.
positionYesPlace the layer directly above or directly below the anchor layer's track.
anchor_layer_idNoThe visual layer to place it against; supply exactly one of anchor_layer_id / anchor_track_id.
anchor_track_idNoA visual track to place it against, including an empty reserved lane. Supply instead of anchor_layer_id.

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the idempotent and non-destructive annotations, it discloses important side effects: a sole occupant carries its track, shared or reserved sources split onto a fresh track, and reserved tracks remain stationary. It also documents rejection cases, the absence of a history record when already positioned, and single-step undo granularity.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and anchor requirement are front-loaded, and every short sentence conveys substantive behavior without filler. However, the compressed terminology in 'sole occupant carries its track' and 'shared or reserved sources' makes the description denser and less immediately interpretable than it could be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a comparatively complex mutation with no output schema, it covers the main invocation requirements, side effects, failures, no-op behavior, and undo behavior well. The remaining gap is that domain terms such as 'stable', 'sole occupant', and 'reserved' are undefined, leaving some uncertainty about when each track behavior applies.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, including the anchor exclusivity constraint and position enum, so the schema already provides the basics. The description adds operational meaning through gap-spanning track anchors, anchor validity restrictions, and source-track behavior, although some wording merely repeats the schema's exactly-one-anchor rule.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence clearly identifies the resource, action, and relative placement: restacking a visual layer above or below a layer or track anchor. The track-moving and splitting details further clarify its scope, but it does not explicitly distinguish itself from siblings such as move_layers or move_track.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete invocation guidance: supply exactly one anchor, use track anchors across gaps, and expect audio, cross-composition, and self-anchors to be rejected. It lacks explicit routing to an alternative tool when the agent wants ordinary layer movement or whole-track reordering.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

restore_checkpointA
Destructive

Restore a named checkpoint. Records a new history entry — undo will return to the pre-restore state. Errors with CheckpointNotFound if the id doesn't exist. The agent panel preserves activity and inserts a restore boundary; only edits with known history provenance are marked reverted.

NameRequiredDescriptionDefault
checkpoint_idYesCheckpoint id.

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true and openWorldHint=false, but the description adds substantial context beyond them: a new history entry is recorded, the operation is therefore reversible via undo, and the specific error name CheckpointNotFound is given. The final sentence characterizes partial-effect behavior (a restore boundary is inserted; only edits with known provenance are marked reverted), which is exactly the kind of nuance the annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the action and its reversibility, then the error case, then the side effects. Dense but efficient; the clause about "edits with known history provenance" is jargon-heavy and slightly opaque, costing the top score.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter mutation with no output schema, the description covers reversibility, the failure mode, and side effects on the agent panel. It does not say what state is returned or whether the checkpoint must belong to the current project, but nothing essential for invoking it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter has 100% schema description coverage, so the baseline is 3. The description adds only that the id must refer to an existing checkpoint (CheckpointNotFound otherwise), with no format or provenance details beyond that.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource: "Restore a named checkpoint." An agent can immediately distinguish this from create_checkpoint or undo. It stops short of naming a sibling as the alternative path, which keeps it out of the top band.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: the note that "undo will return to the pre-restore state" hints at how this relates to undo, and the CheckpointNotFound error implies the id must already exist. There is no explicit when-to-use/when-not guidance versus create_checkpoint or undo/redo.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

restyle_to_tasteA
Idempotent

Reset Text and style Motif layers to the project's style tokens (project://taste), one edit: text takes its role's tokens (untagged: none), captions the caption tokens, a Motif its token-backed props. Select by exactly one of layer_ids, graphic_role, captions: true (the last two within composition_id). groups: look (face, size, colour, outline, shadow, box), position, motion (intro/outro); default look + motion (placement kept); position moves Text only. Returns { restyled, unchanged }.

NameRequiredDescriptionDefault
groupsNoDefault look, motion.
captionsNoEvery caption.
layer_idsNoText or Motif layers to restyle.
graphic_roleNoEvery Text or Motif layer with this role; null selects the untagged ones.
composition_idNoA Group's composition; omit for the root.

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (idempotentHint true, destructiveHint false, closed-world), so the description adds real value on top: mutual exclusivity of selectors, the default (look + motion, placement kept), the fact that `position` only moves Text layers, and the return shape { restyled, unchanged }. It does not disclose whether prior manual styling is lost or recoverable, which matters for a 'reset' operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is short and front-loads the core action, but the middle section is compressed into near-fragments ('text takes its role's tokens (untagged: `none`), captions the caption tokens, a Motif its token-backed props'), forcing the reader to reconstruct the grammar. The information is worthwhile; the packaging is not.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter, no-required-args tool with no output schema, the description covers selection semantics, defaults, per-group behavior, and the return keys. The only meaningful gap is the absence of any statement about reversibility of the restyle, which is relevant given the 'reset' framing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description does go beyond the schema by decoding group contents (look = face, size, colour, outline, shadow, box; motion = intro/outro), noting the look+motion default, and clarifying that graphic_role null selects untagged layers, but these partly duplicate the schema hints ('Default look, motion.', 'null selects the untagged ones').

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: reset Text and style Motif layers to the project's style tokens (project://taste). It also explains what each layer type receives (role tokens, caption tokens, token-backed props), which distinguishes it from siblings like update_layer_params or update_motif_files. The telegraphic phrasing ('a Motif its token-backed props') costs a little clarity but the intent is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives strong selection rules (exactly one of layer_ids, graphic_role, captions:true, with the latter two scoped to composition_id) and states the default groups. However, it never says when to prefer this over adjacent tools such as update_layer_params or set_position, nor does it state any preconditions or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

retime_layersA
Idempotent

Retime exactly these clips in one recorded edit, keeping their starts and source windows. target is an absolute Rate — source µs per timeline µs, so 2/1 plays twice as fast at half the length — or a Duration (µs). preserve_pitch sets the pitch policy of the Audio and Group clips among them (default true), with or without a target. Nothing is expanded: pass link partners too, or their A/V sync drifts; the answer's unretimed_partners names any left out. Atomic; refuses collisions, transitions, locks and nested targets. Returns { layers: [{ layer_id, t_end_us, duration_us, actual_rate, … }], unretimed_partners } after grid snapping.

NameRequiredDescriptionDefault
targetNoAbsolute rate or duration.
layer_idsYesExplicit target clips
preserve_pitchNoKeep the pitch of the Audio and Group clips when the rate changes. Omit to leave the policy alone.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover idempotency, non-destructiveness and closed-world; the description adds the real behavioral payload: atomic execution, specific refusal classes, grid snapping of the result, and the `unretimed_partners` safety net for link partners left out. No contradiction with destructiveHint=false, since it modifies timing rather than removing content.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then target semantics, then constraints, then return shape — a logical order with no filler sentences. The prose is extremely dense (backticked identifiers, em-dashes, parentheticals), which costs some readability for a definition this packed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by sketching the return object (`layers` with layer_id, t_end_us, duration_us, actual_rate, plus `unretimed_partners`). Combined with failure modes, atomicity, and grid snapping, an agent has everything needed to call this correctly for a nested-object, mutation-style tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description genuinely adds meaning: the Rate target is "source µs per timeline µs, so 2/1 plays twice as fast at half the length," and preserve_pitch is scoped to Audio and Group clips among the targets. Minor flaw: it says preserve_pitch is "default true," while the schema says "Omit to leave the policy alone" — a small inconsistency an agent may trip on.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Retime exactly these clips in one recorded edit") and pins down scope with "keeping their starts and source windows," which distinguishes it from trim_layer/move_layers without naming them. It never explicitly names a sibling, so the differentiation is implicit rather than declared.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives actionable invocation guidance: "pass link partners too, or their A/V sync drifts" and "Nothing is expanded," plus the refusal conditions (collisions, transitions, locks, nested targets). It stops short of explicitly saying when to choose retime_layers over trim_layer or shift_layers.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

retry_exportA

Retry only finalization of an awaiting_retry job. Optional filename changes the basename in the same directory; keep its extension.

NameRequiredDescriptionDefault
job_idYesApplication-session export job id.
filenameNoNew basename including matching extension. Directory and encoded settings cannot change.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly=false, idempotent=false, and destructive=false; the description adds real behavioral detail beyond that – it operates on the finalization stage only, and the optional filename must stay in the same directory with a matching extension. It does not disclose what happens if the job is not in awaiting_retry or whether a repeated retry is safe.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences that are front-loaded with the scope constraint, followed by the one non-obvious constraint on the optional parameter. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter, non-idempotent mutation on a specific job state, the description covers the essential precondition and the parameter constraint. Minor gaps remain around failure behavior and error cases, but nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already documents both job_id and filename, including 'Directory and encoded settings cannot change.' The description's filename sentence ('changes the basename in the same directory; keep its extension') largely restates the schema, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Retry... finalization of an awaiting_retry job') and narrows scope with 'only finalization,' which distinguishes it from start_export or get_export_status without naming them. Clear enough to act on, but it doesn't explicitly say which sibling to use for non-awaiting_retry jobs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The precondition 'awaiting_retry job' is a clear when-to-use signal, and 'only finalization' implicitly excludes full re-renders. There are no explicit exclusions or named alternatives (e.g. what to do if the job is failed rather than awaiting_retry), so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_keyframeA
Idempotent

Insert or update one key on a layer param by time (t_us, timeline-absolute), snapped to the frame first: a key on that frame is updated in place, id kept. On a Static track the first key replaces the static value, which is not kept — key the start value too, or use set_param_track. value is typed by param_key: a number, or {r,g,b,a} (0..255) for "color"; an effect param needs no prior write and must sit in its catalog range. easing eases the segment leaving the key, or on the last key the one arriving at it; omitted, a new key inherits the easing of the segment it splits. Returns the key (keyframe_id, t_us, local_t_us). Sides, continuity, Auto tangents: update_keyframe.

NameRequiredDescriptionDefault
t_usYesKey time, timeline-absolute, µs.
valueYesTyped by `param_key`: a number for scalar params (x, y, path_progress, scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity, gain_db, pan, effect params), {r,g,b,a} (0..255) for "color". Path mode takes path_progress (a fraction) instead of x/y.
easingNoEasing of the segment leaving the key (on the last key, the one arriving at it): {"preset":"<id>"} or a raw {"kind":...}. Writes this key's out/segment and the next key's in.
layer_idYesLayer id.
param_keyYesVisual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>].

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations (which only declare idempotent, non-destructive, closed-world): it discloses the snap-to-frame reconciliation rule, that an existing key is updated in place with its id preserved, and the important caveat that a Static track's static value is discarded. The easing inheritance default for a split segment is another non-obvious behavior. It stops short of describing failure modes (e.g. out-of-catalog effect range errors), keeping it at 4 rather than 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and tightly written with zero filler sentences; every clause carries a rule an agent needs. It is dense — heavy backticking, parentheticals and semicolon chains make it slower to scan than it could be — but nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by stating the return shape (`keyframe_id`, `t_us`, `local_t_us`). Combined with the snap rule, static-track caveat, value typing and easing defaults, an agent has everything needed to call this correctly for a 5-parameter nested-schema mutation tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3; the description earns above that by adding semantics the schema lacks — that `value` is typed by `param_key` (number vs {r,g,b,a} 0..255), that an effect param needs no prior write but must sit in its catalog range, and that omitted `easing` makes a new key inherit the easing of the segment it splits. The `easing` object itself is left to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a precise verb+resource ("Insert or update one key on a layer param by time") and immediately qualifies scope with the timeline-absolute unit and snap-to-frame rule. It distinguishes itself from siblings by naming set_param_track for static values and update_keyframe for sides/continuity/Auto tangents, so an agent can route correctly without opening another schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to deviate: on a Static track the first key replaces the static value, so either key the start value too or use set_param_track instead. It also redirects tangent/continuity work to update_keyframe. Both alternatives are named with the condition that selects them.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_layer_flagsA
Idempotent

Set enabled and/or locked on exactly these layers in one recorded edit; omit one to leave it alone, and name at least one. Nothing is expanded: pass link partners (link_id in project://tracks) to hide or lock a linked pair. enabled is the layer's output in preview and export. A locked layer refuses edits; its track's lock is separate (set_track_flags). A locked layer or track (LayerLocked / TrackLocked) refuses the visibility write for the whole batch: unlock in its own call first. Hide and lock is one call.

NameRequiredDescriptionDefault
lockedNoWhether the layer refuses edits. Omitted leaves it alone.
enabledNotrue shows, false hides — preview and export alike. Omitted leaves it alone.
layer_idsYesThe layers to set, all in one composition.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only supply openWorldHint=false, idempotentHint=true, and destructiveHint=false; the description adds substantial behavior beyond that: the edit is recorded (undoable), omitted fields are untouched, link partners are not implicitly expanded, locked layers refuse edits, and a lock anywhere in the batch rejects the whole visibility write with LayerLocked/TrackLocked. This is exactly the failure-mode and atomicity context an agent needs before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and constraint, and no sentence is filler. The telegraphic, clause-heavy style (semicolons, backticked jargon, "Nothing is expanded") is efficient but slightly harder to parse than it needs to be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-parameter flag-setter with no output schema but solid annotations, the description covers the action, the batch semantics, the cross-tool boundary (track lock vs. layer lock), link handling, and the error precondition. Nothing needed to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, and the description largely restates the schema's own wording for `enabled` and `locked` (preview/export output, refuses edits). It does add one non-duplicated constraint — `layer_ids` must all belong to a single composition — which is meaningful beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ("Set") and specific resource/properties ("`enabled` and/or `locked` on exactly these layers in one recorded edit"), and explicitly separates itself from the nearest sibling by noting "its track's lock is separate (`set_track_flags`)". An agent can distinguish this from set_track_flags without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use rules: omit a field to leave it alone, name at least one layer, and pass link partners to affect a linked pair because "Nothing is expanded". It also states the when-not precondition — a locked layer or track causes the whole batch to fail, so "unlock in its own call first" — and notes the batching preference ("Hide and lock is one call").

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_marker_anchorA
Idempotent

Tie a marker to a clip so the mark FOLLOWS it through moves, trims, splits and composition crossings, or cut it loose with layer_id: null. layer_id must be a clip of the marker's own composition. Tying names the source instant the mark already sits on, so nothing moves; t_us stays the field to read. Refuses without writing: a layer in another composition (CrossCompositionSet), a kind with no source window such as Color or Text (WrongLayerKind), a marker outside the clip's span (InvalidArgument — update_marker it onto the clip first). Re-tying replaces the tie. Untying keeps the frame currently shown and is the one exit from hibernating; untying a free marker records nothing.

NameRequiredDescriptionDefault
layer_idYesThe clip to follow, or null to cut the marker loose.
marker_idYesMarker id.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the annotations by disclosing that refusals write nothing, that re-tying replaces the existing tie, that tying is positionally inert, and that untying is the one exit from the hibernating state. This is precisely the kind of mutation-safety and state-transition context annotations alone cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then the constraints, then the refusal list, then the untying semantics. Every sentence carries information, though the dense parenthetical error-code style makes it slightly heavy to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter mutation tool with no output schema, the definition covers preconditions, failure modes, idempotent replacement, and state transitions. Nothing an agent needs to call it correctly is left unexplained.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and already documents both params, but the description adds a real constraint the schema omits: layer_id must be a clip of the marker's own composition, with CrossCompositionSet as the failure mode. It also clarifies that null is not a no-op but an untying operation with distinct semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource pair (tie a marker to a clip) and its inverse (cut loose with layer_id: null), and distinguishes the operation from marker editing by noting that t_us stays the field to read. An agent can tell exactly what changes and what does not.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use (make the mark follow moves/trims/splits/crossings), when-not (a free marker records nothing on untie), and a concrete alternative for the failure case: use update_marker to move the marker onto the clip first. Refusal conditions are enumerated with error codes.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_param_trackA
Destructive

Replace a whole param track in one undo step, discarding its keys: {"mode":"Static","value":v}, or {"mode":"Keyframed","value":[keys],"extrapolate"?} (Hold/Hold when omitted). A key needs only {t_us (timeline-absolute), value}; easing (as set_keyframe's) or in/out/segment/continuity shape the curve, else Linear. get_param_track's track is this shape and round-trips as is; IDs are generated, so omit them. Two keys snapping onto one frame are refused, naming both. A Text layer's static scale stays 1 (ADR 0049). Returns the committed keys {keyframe_id, t_us, value} and extrapolate, or the static value.

NameRequiredDescriptionDefault
trackYesAn animation track: {"mode":"Static","value":v} or {"mode":"Keyframed","value":[keyframes],"extrapolate":{before, after}} (Hold/Hold when omitted). Values are typed by `param_key` — a number, or {r,g,b,a} (integers 0..255) for "color".
layer_idYesLayer id.
param_keyYesVisual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>].

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the destructiveHint annotation, the description discloses that the replacement happens in one undo step, discards existing keys, refuses two keys snapping onto one frame while naming both, special-cases Text static scale, and returns the committed keys or static value. This is substantial behavioral context beyond the supplied annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but front-loads the core action and then proceeds through track shape, key requirements, validation, and return values. It is appropriately sized for a nested track-replacement tool, though some clauses are packed tightly and the ADR reference is specialized.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex nested tool with no output schema, the description covers the input shape, round-trip behavior with get_param_track, validation refusal, special Text behavior, defaults, and return format. An agent has enough context to construct and interpret the call.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the baseline is 3, but the description adds meaningful semantics: IDs are generated and should be omitted, a key minimally needs only t_us and value, easing replaces the key's out/segment and next key's in, and the returned shape is described. These additions go beyond simply restating the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: "Replace a whole param track in one undo step, discarding its keys." That scope clearly distinguishes it from set_keyframe and update_keyframe, which operate on individual keys, and it explicitly connects the shape to get_param_track.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly indicates the tool is for replacing an entire track and warns that existing keys are discarded, while noting that get_param_track's track round-trips as-is. It does not explicitly say when to prefer set_keyframe/update_keyframe instead, so the alternative routing is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_positionA
Destructive

Replace a layer's position outright, motion included: XY tracks, or a motion path with a scalar progress track. Keys are timed local_t_us (layer-local) and need only local_t_us/value (Linear, identity tangents); nodes need only point (Line, Corner, zero handles); IDs are generated, so omit them. A static update_layer_params x/y also flattens XY animation; translate_position offsets it instead. One undo step; returns the position as committed.

NameRequiredDescriptionDefault
layer_idYesLayer id.
positionYesXY: `x`/`y` tracks in composition px. Path: `path.nodes` plus a `progress` track, 0..1 = distance along the path (Hold/Loop/PingPong extrapolation only).

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and openWorldHint=false, so the safety profile is covered; the description still adds real behavior beyond them — 'One undo step' scopes the undo blast radius and 'returns the position as committed' describes the effect. It stops short of saying what happens to pre-existing keys on failure or what errors arise if the layer is missing, so it is strong but not exhaustive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and mode split, then defaults, then sibling routing, then side effects — a sensible ordering. It is dense with semicolons and a touch cramped, but every clause carries distinct information and none is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter tool with heavy nested objects and no output schema, the description covers the mode choice, minimal key/node shapes, default tangents and segments, undo scope, and the return value. What remains uncovered — failure modes and whether existing keys are merged or wiped — is modest against what is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description genuinely adds meaning: keys 'need only local_t_us/value (Linear, identity tangents)', nodes 'need only point (Line, Corner, zero handles)', and 'IDs are generated, so omit them' tells the agent which schema fields are safe to leave out. That is exactly the omission guidance a deeply nested schema cannot convey on its own.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource+scope: 'Replace a layer's position outright, motion included', then immediately enumerates the two modes (XY tracks vs. motion path with a scalar progress track). It explicitly distinguishes itself from siblings translate_position and update_layer_params in the same breath.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names both alternatives and the exact condition that selects each: a static update_layer_params x/y 'also flattens XY animation', while 'translate_position offsets it instead'. That is an explicit when-to-use-this-vs-that rule rather than an implied one.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_project_settingsA
Idempotent

Update the project's editing preferences; only the fields you send apply, and an unknown key or an empty patch is refused. Unrecorded — preferences are setup, patched into every history snapshot, so undo walks past them (the update_composition contract). Fields: auto_pair_audio_on_import, prefer_proxies, proxy_override, shot_review, pause_review (the last two validated and refused as a whole, against the detectors' own bounds; null clears one back to defaults). Returns { settings, changed }; changed names the fields that moved (empty: all already set). Read current values from project://settings.

NameRequiredDescriptionDefault
patchYesSettings patch. Only the fields you include are applied; `null` has a per-field meaning given below and is never 'unset'.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotent and non-destructive, but the description adds the crucial fact those annotations cannot convey: the operation is "Unrecorded — preferences are setup, patched into every history snapshot, so undo walks past them," meaning undo will not reverse it. It also discloses validation atomicity (the last two fields "validated and refused as a whole"), null-means-reset semantics, and the return shape `{ settings, changed }`.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and its patch semantics, then the undo caveat, then fields, then return value — a sensible order with no filler sentences. The style is dense and parenthetical-heavy ("(the `update_composition` contract)", "(empty: all already set)"), which asks the reader to unpack cross-references, costing a bit of clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, and the description compensates by stating the return object and the meaning of `changed`, including the empty case. Combined with the refusal rules, the reset semantics, the undo caveat, and the pointer to `project://settings` for current values, an agent has everything needed to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the nested field descriptions already document bounds, units, and null handling, so baseline 3 applies. The description does contribute two things the schema lacks — that the top-level patch is partial-apply and that shot_review/pause_review are validated atomically — plus the reminder that null clears rather than unsets, but these are refinements rather than new parameter meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ("Update the project's editing preferences") and immediately enumerates the exact field names the patch accepts, so an agent knows this is a project-wide settings mutation rather than a composition/layer edit like update_composition or update_layer_params. The scope is unambiguous without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operating context: read-modify-write via "Read current values from `project://settings`", partial-patch semantics ("only the fields you send apply"), and explicit rejection conditions (unknown key, empty patch). It does not name a sibling alternative or exclusion, but no sibling tool performs this function, so the guidance covers the realistic decision points.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_role_flagsA
Idempotent

Mute/solo an audio role; omit one flag to leave it alone, and name at least one. role ∈ {dialogue,music,sfx,voiceover}. Mute wins over solo; any solo silences non-soloed roles. Gates preview AND export. Unrecorded (undo does not revert it) and not in the review diff — restore the flags before handing back. A mix change the user reviews is set_role_gain.

NameRequiredDescriptionDefault
roleYesThe audio role.
soloNoPlay this role alone. Omitted leaves it alone.
mutedNoSilence the role. Omitted leaves it alone.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by disclosing precedence ('Mute wins over solo'), cross-role interaction ('any solo silences non-soloed roles'), blast radius ('Gates preview AND export'), and two non-obvious persistence caveats ('Unrecorded (undo does not revert it) and not in the review diff'). The instruction to restore flags before handing back is exactly the kind of consequence an agent cannot infer from idempotentHint/destructiveHint=false.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action, then semantics, then consequences, then the sibling pointer — good ordering with no filler sentences. It is somewhat dense and semicolon-chained, which costs a little readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-parameter flag mutation with no output schema, everything needed is present: valid role values, omission semantics, precedence rules, export/preview impact, and the undo exception. Nothing an agent must know before calling is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns a notch more by stating the interaction semantics of the two booleans (mute overrides solo, solo mutes non-soloed roles) and the at-least-one rule, which the schema does not encode. The role enum restatement is redundant with the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb pair ('Mute/solo') plus resource ('an audio role') and an exact enum of the affected roles. The final sentence explicitly separates it from `set_role_gain`, so an agent can pick between the two siblings without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete call-shape rules ('omit one flag to leave it alone, and name at least one') and routes mix-change work to `set_role_gain`. It lacks an explicit when-not-to-use condition for adjacent tools such as `set_track_flags` or `set_layer_flags`, which is the only remaining gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_role_gainA
Idempotent

Set an audio role's mix gain (dB). role ∈ {dialogue,music,sfx,voiceover}. Recorded (undoable). Folds into every layer of that role at mix time.

NameRequiredDescriptionDefault
roleYesThe audio role.
gain_dbYesRole gain, dB; 0 = unity.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotentHint=true, destructiveHint=false and openWorldHint=false, and the description is consistent with them. It adds real context beyond the annotations: the change is "Recorded (undoable)" and it "Folds into every layer of that role at mix time," clarifying that the gain is applied non-destructively at mix rather than baked into layers. It still omits clamping/valid dB range and what state the call returns.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four tight fragments with the core action front-loaded and no filler. The telegraphic style ("Recorded (undoable)") is compact but slightly clipped, and the mix-time note lands last where it is easy to skim past.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter setter with no output schema, the description covers the action, target set, undoability and mix-time propagation, which is nearly everything an agent needs. Minor gaps remain around accepted dB range and whether a project session must be active.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both parameters and the role enum are already fully documented in the schema, establishing a baseline of 3. The description's "(dB)" and the role set merely restate schema content; the one genuinely additive phrase, "folds into every layer of that role at mix time," describes effect rather than parameter meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Set an audio role's mix gain") and enumerates the valid roles, so the agent knows exactly which operation and domain this covers. It does not explicitly separate itself from the nearby sibling set_role_flags, leaving that distinction to be inferred from the noun (gain vs. flags).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the fixed role enum tells the agent which targets are legal, and "at mix time" hints at when the value takes effect. There is no explicit guidance on when to choose this over set_role_flags or a per-layer gain tool, and no stated prerequisites such as needing an open project.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_track_flagsA
Idempotent

Set a track's enabled and/or locked flag; omit (or null) one to leave it alone, and name at least one. locked is what every TrackLocked refusal points at — a locked track rejects edits to its layers, and clearing it here is the fix. enabled is the track's output in preview and export; its layers stay put. A layer's own locked is separate (set_layer_flags), and an edit needs both clear. Mute/solo live on roles: set_role_flags. Unrecorded.

NameRequiredDescriptionDefault
lockedNoWhether the track refuses edits to its layers. Omitted leaves it alone.
enabledNoThe track's output, preview and export alike. Omitted leaves it alone.
track_idYesTrack id.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotency, non-destructiveness, and closed-world behavior. The description adds useful behavioral context beyond that: a locked track causes TrackLocked refusals, clearing locked is the fix, enabled controls preview/export output, and layer locks are separate. The trailing 'Unrecorded.' hints at undo/history behavior but is terse and not fully explained.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and front-loads the core operation, then explains flag effects and alternatives. It is mostly efficient, though 'Unrecorded.' is ambiguous and some flag semantics repeat the schema descriptions.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple three-parameter flag-setting tool with annotations and no output schema, the description covers the operation, parameter constraints, behavioral effects, and sibling alternatives. An agent has enough information to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description still adds meaning beyond the schema by specifying omit/null semantics, the 'name at least one' constraint, and how track-level locked differs from layer-level locked.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: set a track's enabled and/or locked flag. It explicitly distinguishes this from set_layer_flags and set_role_flags, so an agent can identify the correct tool without opening sibling schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit usage rules: omit or null one flag to leave it alone, and name at least one. It also names alternatives directly, pointing layer locks to set_layer_flags and mute/solo to set_role_flags, and explains that an edit needs both track and layer locks clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

shift_layersA

Shift every layer starting at or after t_from_us by one delta_us, as one recorded edit — on track_ids, or on every track of the composition. A positive delta opens room there (the ripple insert); a negative one closes [t_from_us + delta_us, t_from_us) the way delete_layers { ripple: true } closes a hole, refusing by the same names (RippleInsideHole: a layer starts inside the span; RippleCollision, RippleLinkStraddles, RippleLockedLayer) and keeping each carried transition. A link the sweep would split is ShiftLinkStraddles; a start before 0 refuses. Each layer snaps on its own grid. To move named layers, move_layers. Returns { moved: [layer records], delta_us }.

NameRequiredDescriptionDefault
delta_usYesSigned shift, µs; positive opens room, negative closes the span before t_from_us. Not 0.
t_from_usYesShift every layer starting at or after this time, timeline, µs.
track_idsNoOnly these tracks. Omit for every track.
composition_idNoThe composition to sweep; omit for the root.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false and destructiveHint=false; the description goes well beyond them, disclosing that the operation is 'one recorded edit', that transitions ride along with the sweep, that each layer snaps on its own grid, and enumerating the exact refusal codes (`RippleInsideHole`, `RippleCollision`, `RippleLinkStraddles`, `RippleLockedLayer`, `ShiftLinkStraddles`) plus the sub-zero-start refusal. That is precisely the failure-mode context an agent needs before invoking a ripple edit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core verb and scope, and nearly every clause carries information an agent would otherwise have to infer. The middle sentence is dense — error-name lists and the ripple/delete analogy stack up — but nothing is genuinely redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, yet the description supplies the return shape (`{ moved: [layer records], delta_us }`), the scope options, the sign semantics, the refusal conditions, and the undoable/recorded nature of the edit. For a 4-parameter ripple-mutation tool, nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description still adds meaning by tying `delta_us` sign to insert-vs-close semantics and by clarifying that `t_from_us` is an inclusive 'at or after' threshold rather than a point. The `track_ids`-vs-every-track scope is restated but not deepened beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening clause names a specific verb and resource with scope: 'Shift every layer starting at or after `t_from_us` by one `delta_us` ... on `track_ids`, or on every track.' It also names the sibling that does the related-but-different job ('To move named layers, `move_layers`'), so the agent can separate the two without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit alternatives: `move_layers` for relocating named layers and `delete_layers { ripple: true }` as the analogous hole-closing operation. The positive/negative delta explanation effectively tells the agent which direction to use. What it lacks is a crisp 'use this when you need to insert room at a point' framing, but the routing information is present.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

split_layerA

Split at sorted, grid-snapped times in one atomic edit. Each half retains its mapped content window. Linked members are cut too and form a separate link per segment unless escape_link. Returns layer_ids, the actual t_cut_us and siblings: [{ layer_id, segments }], each link partner cut with it.

NameRequiredDescriptionDefault
layer_idYesLayer id.
t_cut_usYesInterior timeline cuts, µs; snapped, sorted, deduplicated. Any invalid cut rejects all.
escape_linkNoAct on this layer alone, leaving its link partners in place. Default false.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint=false and destructiveHint=false; the description adds the non-obvious behavior that linked members are also cut and that each segment forms a separate link unless escape_link is set. Atomicity ("one atomic edit") and the guarantee that each half retains its mapped content window are also disclosed. It stops short of saying whether the split is undoable or what happens at timeline boundaries.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense sentences that front-load the core action and then layer on link behavior and return shape with no filler. The telegraphic style ("each link partner cut with it") is efficient but borders on terse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description correctly supplies the return shape (layer_ids, actual t_cut_us, siblings with segments), which is essential for a caller. Combined with atomicity and link-propagation behavior, it covers what an agent needs for a 3-parameter mutation. Minor gaps remain around error surface and undo.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so all three parameters are already documented, and the description largely restates them (snapped/sorted cuts, escape_link's effect on links). The added value is limited to framing escape_link as producing a separate link per segment rather than acting on one layer. Baseline 3 applies when the schema carries the semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Split at sorted, grid-snapped times in one atomic edit" gives a specific verb and resource plus the operation's key character (atomic multi-cut). It is clearly distinct from trim_layer or auto_split_by_shot, though it never names those siblings explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the name and by the mention of escape_link, but there is no explicit when-to-use guidance and no statement about when to prefer this over trim_layer or auto_split_by_shot. The one conditional it does give (link partners cut unless escape_link) is behavioral rather than routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

start_exportA

Start an asynchronous export. Use one request_id per intent; reuse it when reconnecting. Settings, path, extension and an on_conflict: fail collision are refused before a job exists. get_export_status { wait_s } reports the actual completed path.

NameRequiredDescriptionDefault
rangeNoSpan inside the root composition, snapped to its frame grid. Omit for the whole composition.
settingsNoPartial per-job overrides, applied after preset_id. Without preset_id, uses saved project settings then the global default. Does not change the preset or saved project settings.
preset_idNoExact preset ID from list_export_presets. Built-in IDs start with builtin:.
request_idNoUnique export intent id. Reuse with identical arguments after reconnecting.
on_conflictNoDefault rename adds a number. Fail requires the exact name. Neither overwrites.
output_pathNoAbsolute candidate file path in an existing folder or the project output/. Its extension must match the container (.mp4, .mov, .mkv; audio-only .m4a, Opus .mka): get_export_options reports it as extension. Omit for project/output/project-name.ext.
allow_experimental_10bitNoExplicit opt-in for experimental HEVC/AV1 10-bit export.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the safety profile (readOnlyHint=false, destructiveHint=false), and the description adds genuinely new behavior: the job is asynchronous, validation of settings/path/extension/on_conflict=fail happens before any job is created (fail-fast semantics), and progress is polled elsewhere. It stops short of saying what a successful call returns immediately (a job handle/id) or whether concurrent exports are allowed. There is a mild tension between the request_id reuse guidance and idempotentHint=false, but it reads as explicit-dedupe-only rather than a direct contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the core action, no filler. The third sentence is telegraphic to the point of being hard to parse on first read ('Settings, path, extension and an on_conflict: fail collision are refused before a job exists'), which costs a point but the information is still recoverable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter tool with nested objects and no output schema, the description covers the essentials: async nature, dedupe key, fail-fast validation, and where the resulting path surfaces. The rich schema handles parameter detail, so the only remaining gap is what the immediate response contains after a job is accepted.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter including the nested settings object is already documented. The description only echoes a few of them (request_id reuse, on_conflict=fail collision, path/extension) without adding format or interaction detail beyond the schema. Baseline 3 is appropriate when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource — 'Start an asynchronous export' — which clearly separates it from get_export_status, retry_export, and cancel_export among the siblings. The 'asynchronous' qualifier is the key differentiator from a synchronous render, though it never explicitly names the sibling tools it replaces.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use one request_id per intent; reuse it when reconnecting' is a concrete usage rule for the agent's call pattern, and pointing at get_export_status { wait_s } tells the agent what to do next. What's missing is explicit guidance on when NOT to use this tool (e.g. versus retry_export or render_frames), so the routing to alternatives is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

synthesize_speechA

Synthesize speech with the configured cloud TTS provider (OpenAI tts-1; the text is uploaded) and place it as a voiceover Audio layer, one placement or none: a refused placement leaves nothing in the pool. text ≤ 4096 chars; voice; optional speed 0.25..4.0 (default ≈ 1.0); composition_id (default root); t_start_us (default: the composition's duration, so it appends); target_track_id, else the topmost unlocked track whose audio lane is free across the clip, else a new 'Voiceover' track. The MP3 is cached by (model, voice, speed, text), so a repeat costs no API request. Returns { layer_id, media_id, track_id, t_start_us, t_end_us, cached }.

NameRequiredDescriptionDefault
textYesText to synthesize. tts-1 caps at 4096 characters.
speedNo0.25..4.0 for tts-1. Omit to use the provider default (~1.0).
voiceYesThe tts-1 voice.
t_start_usNoTimeline start, µs. Defaults to the composition's `duration_us`, so the voiceover appends at the end.
composition_idNoA Group's composition to place in; omit for the root.
target_track_idNoTrack to place on. Omitted: the topmost unlocked track whose audio lane is free across the clip, else a new 'Voiceover' track.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it discloses that text is uploaded to a cloud provider (consistent with openWorldHint), that placement is all-or-nothing ('a refused placement leaves nothing in the pool'), and that the MP3 is cached by (model, voice, speed, text) so repeats cost no API request. It also enumerates the returned fields, which no output schema supplies.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action and the side effect, then packs constraints, defaults, and the return shape into one dense but readable block. A few clauses (the caching detail, the track-fallback chain) are wordy, but no sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers everything an agent needs for a 6-parameter mutation with an external API dependency: cost/network implications, atomicity of failure, default placement behavior, caching, and the exact return object despite no output schema existing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the description's parameter notes (4096-char cap, speed range/default, composition_id root default, t_start_us append default, track fallback chain) largely restate what the schema already documents. It consolidates the semantics usefully but adds little genuinely new meaning per parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Synthesize speech') plus the concrete outcome ('place it as a voiceover Audio layer') and names the backend provider (OpenAI tts-1). That distinguishes it cleanly from neighbors like analyze_audio, transcribe_clip, and import_media.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for when the tool applies (turn text into a voiceover layer) and spells out placement resolution including the append-by-default behavior. It does not explicitly name alternatives or exclusions (e.g., when to import a pre-made audio file instead), so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

transcribe_clipA
Read-only

Transcribe the audio that plays on 1–20 VideoClip or Audio layers (a VideoClip through its linked Audio member). Returns { transcripts: [{ source: { layer_id, signature }, backend, segments: [{ t_start_us, t_end_us, text, words: [{ t_start_us, t_end_us, text }] }], language, word_timing }], failed? }, one per layer in order, timeline µs; hand transcripts to apply_transcripts as is. Cut pauses first, caption after: a clip changed since is refused there. failed lists layers that refused, with why. t_start_us/t_end_us narrow one layer's window. language is BCP-47; a model that does not cover it, or the language it detects, refuses with options. whisper_cpp and funasr run on this machine; openai (cloud) and byo_endpoint (the user's server) UPLOAD the audio — name one in backend only with the user's consent. Without backend the model selected in Settings runs, never another; if it cannot, the refusal names what it lacks and the ready engines. A retry after a client timeout joins the running job.

NameRequiredDescriptionDefault
backendNoStrict engine override; that engine serves or the call errors. `openai` and `byo_endpoint` upload the audio.
languageNoSpoken language, BCP-47 (`"en"`, `"zh-CN"`). Auto-detect when omitted.
t_end_usNoOptional window end (exclusive), timeline µs; one layer only. Defaults to the layer's `t_end_us`. Must lie within the layer.
layer_idsYesVideoClip or Audio layers to transcribe (1–20); one envelope each, in this order. A VideoClip is read through its linked Audio member.
t_start_usNoOptional window start, timeline µs; one layer only. Defaults to the layer's `t_start_us`. Must lie within the layer.
normalize_audioNoExplicit opt-in: normalize only the transcription copy toward -3 dBFS peak, at most +24 dB. Original media/timeline stay unchanged. Default false.
word_timestampsNoAsk for exact per-word times where the engine can emit them. Default true; `false` forces SRT-style interpolated words. The result's `word_timing` reports what you got.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say readOnly/openWorld; the description adds far more: which engines run locally vs upload audio, the consent requirement, refusal behavior when a model lacks the language, refusal for clips changed since, and that a retry after client timeout joins the running job. That is exactly the context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action and return shape, then moves to workflow and safety caveats in roughly priority order. Some sentences are densely packed (the return-shape clause and the backend paragraph), but no sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, yet the description spells out the full envelope including transcripts, segments, word timing, and the failed list, plus per-layer ordering and time units. Nothing an agent needs to call and consume the result is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds cross-parameter constraints the schema only implies: t_start_us/t_end_us narrow one layer's window, language refusal passes back detected-language options, and backend omission falls back to the Settings model with no silent substitution.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Transcribe the audio that plays on 1–20 VideoClip or Audio layers') and clarifies the VideoClip-through-linked-Audio resolution. An agent can distinguish it from analyze_audio, detect_pauses, or extract_clip_audio from the sentence alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives ordering guidance ('Cut pauses first, caption after') and routes output to apply_transcripts 'as is', plus an explicit consent rule for choosing a cloud backend. It does not name sibling alternatives such as detect_pauses or apply_transcripts by when-to-use condition, so it falls short of a full routing statement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

translate_positionA

Offset a layer's position by (dx, dy) composition px as one undo step, keeping its motion: in XY mode every x/y key (or the static value), in Path mode every node (handles and progress kept). Returns the position as committed, as set_position does.

NameRequiredDescriptionDefault
dxYesShift in x, composition px.
dyYesShift in y, composition px.
layer_idYesLayer id.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the supplied annotations: it discloses that the whole offset commits as a single undo step, that existing motion is preserved rather than flattened, that in XY mode every x/y keyframe or static value is rewritten, and that Path mode keeps nodes, handles and progress intact. It also states the return value is the committed position, matching set_position's contract.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense sentence plus a short return clause, front-loaded with the core verb and delta. Nothing is wasted, though the nested parenthetical about XY vs Path modes takes a second read to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-parameter mutation with no output schema, the definition covers what changes, how it commits atomically, what is preserved per layer mode, and what is returned. An agent has enough to call it correctly without guessing at side effects.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and both dx/dy already document 'composition px', so the description adds no parameter-level meaning beyond restating the unit. The XY/Path distinction is behavioral context rather than per-parameter guidance. Baseline 3 is appropriate when the schema carries the parameter burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (offset a layer's position) with the exact delta semantics (dx, dy in composition px), and implicitly contrasts with the sibling set_position by being relative rather than absolute. The mode-specific behavior (XY keys vs Path nodes) further pins down what the operation touches.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The relative-offset framing makes the choice against set_position (absolute placement) reasonably clear, and the XY/Path clause tells the agent the tool is valid for both layer types. It stops short of an explicit 'use this instead of set_position when...' routing sentence or any stated preconditions such as layer lock state.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

trim_layerA
Idempotent

Trim an edge to t_edge_us. Source time follows the clip rate; keyframes remain glued to content. Aligned linked edges follow unless escape_link. Refuses targets outside the legal source/timeline window. Returns committed spans, trimmed siblings and grid adjustments.

NameRequiredDescriptionDefault
edgeYesWhich edge moves: in = t_start_us, out = t_end_us.
layer_idYesLayer id.
t_edge_usYesWhere the edge lands, timeline, µs.
escape_linkNoAct on this layer alone, leaving its link partners in place. Default false.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotent and non-destructive behavior, and the description goes further by disclosing that keyframes stay glued to content, linked edges follow unless escape_link is set, illegal targets are refused, and grid adjustments may occur. The 'Returns committed spans, trimmed siblings and grid adjustments' line adds return-shape context despite there being no output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Five short sentences, each carrying distinct information, with the core action front-loaded and the conditional link behavior and refusal rule following in logical order. No filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a four-parameter mutation tool with no output schema, the description covers the action, edge-case refusal, link side effects, and return contents. A minor gap is the absence of guidance on permission or targeting prerequisites, but overall it is sufficient to call the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond it: 'Source time follows the clip rate' clarifies how t_edge_us is interpreted, and 'Aligned linked edges follow unless escape_link' explains escape_link's operational consequence. That is genuine semantic value on top of an already complete schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource combination ('Trim an edge to t_edge_us'), which is precise enough for an agent to distinguish a trim operation from siblings like split_layer or retime_layers. It doesn't explicitly name an alternative sibling, which keeps it from a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied through the described link/escape_link behavior and the legal-window refusal, giving some context for when the tool applies. However, there is no explicit statement of when to reach for trim_layer versus related editing tools, so the guidance remains inferential.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

undoA
Destructive

Undo the newest edit by anyone: history is shared, so it may be the user's — check undone.actor, and redo puts it back. NothingToUndo at the origin. Only timeline edits record — layers, tracks, markers, transitions, links, Groups, role gains (set_role_gain), and media removals that cascade. Outside the stack and untouched by undo: media imports, the composition envelope (update_composition), project settings (set_project_settings), track and role flags, and loading a project (which resets history). Answers undone: the op reverted.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare destructiveHint and openWorldHint=false; the description goes well beyond by disclosing shared history, the `undone.actor` check, the `NothingToUndo` failure at the origin, and the exact set of operations that enter the stack. It could be slightly sharper on whether the undo itself can be undone partially or what happens if the underlying target has since changed, which keeps it off a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and the shared-history caveat, then the covered/not-covered lists. Dense but nearly every clause carries new information; the long em-dash enumeration is slightly run-on and could be split for scannability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter mutation tool with no output schema, the description supplies the acting scope, error condition, recordable-operation list, exclusion list, and the returned field. Nothing an agent needs in order to call it correctly appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so the schema contributes nothing beyond an empty object. The description compensates by documenting the meaningful response field `undone` and its `undone.actor` subfield, giving the agent the return contract it needs.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (undo) and resource (the newest edit), plus the crucial scope fact that history is shared across actors. It explicitly contrasts with the `redo` sibling, so an agent can distinguish the two without inspecting schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit when: any recorded timeline edit. It also enumerates what is NOT undoable (media imports, composition envelope, project settings, track/role flags, project loading) and names `redo` as the inverse action. This is a full when/when-not/alternative breakdown.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ungroup_layerA

Expand a Group layer back into its members, in place. Refuses unless the Group is PLAIN — identity transform, static opacity 1, no effects (GroupNotPlain { reason }), because those apply to the composite and would be discarded; reset them first or keep the Group. Members intersecting the Group's [src_in_us, src_out_us) window are copied into the parent at the same on-screen time, trimmed to the window; members wholly outside are dropped. The composition's tracks become fresh tracks at the Group's z position; inner links and transitions carry over. The composition is removed when nothing else references it. One undo restores the Group.

NameRequiredDescriptionDefault
layer_idYesThe Group layer (its params.kind is CompositionRef).

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say openWorldHint=false and destructiveHint=false; the description goes far beyond them, disclosing that non-PLAIN groups are refused with a structured `GroupNotPlain { reason }`, that members are trimmed to the `[src_in_us, src_out_us)` window, that out-of-window members are dropped, that inner links/transitions carry over and tracks are recreated at the Group's z position, that the composition is garbage-collected when unreferenced, and that one undo restores it. The undo-restores statement is what reconciles the composition removal with destructiveHint=false, so there is no contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action, then the precondition and remedy, then the member/track/composition consequences, then undo. Every clause carries distinct information — no restatement of the name and no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter mutation with no output schema, the behavioral surface (refusal mode, trimming, link carry-over, composition cleanup, undo) is unusually complete. The only gap is that the return value on success is never hinted at, though the named `GroupNotPlain { reason }` error shape partially covers the failure path.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single parameter is already documented as "The Group layer (its params.kind is CompositionRef)", so the schema carries the burden. The description repeats rather than extends this, adding only window semantics that govern the member copy behavior rather than the argument itself.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Expand a Group layer back into its members, in place" gives a precise inverse verb, the resource it operates on, and the in-place modifier. Combined with the ELISION of sibling operations (create_group, add_group_members, delete_composition), an agent can tell immediately this is the dissolve operation rather than a group mutation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states an explicit precondition with a concrete remedy: the Group must be PLAIN, and if not you should "reset them first or keep the Group." That is real when/when-not guidance. It stops short of naming a sibling tool it is an alternative to (e.g., delete_composition or create_group) and gives no guidance on ordering relative to those tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_compositionA
Idempotent

Update a composition's envelope — canvas width/height, fps, sample_rate, channels, color_space, background, duration_us; only fields you set apply; composition_id names a Group's composition, the root when omitted. Unrecorded: the envelope is setup, so the patch reaches every history snapshot and undo walks past it. fps is LOCKED once the timeline, any history snapshot or any checkpoint holds a layer — refused with FpsLockedByContent { current, requested, layer_count, locked_by: "current" | "history" }; set the rate on a project that has never held a layer, or empty the timeline and reopen the project to clear a history lock. sample_rate is never locked. Setting duration_us PINS the duration so layer edits stop auto-fitting it; duration_us: null (alone in the patch) unpins it and refits to the layers.

NameRequiredDescriptionDefault
patchYesComposition envelope patch. Only fields you set are applied.
composition_idNoThe composition to patch; omit for the root. fps / sample_rate / channels are one lattice for the whole project and cascade to every composition.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses critical behavior: the envelope patch is unrecorded, reaches every history snapshot, and undo walks past it. It also gives the exact FpsLockedByContent error shape and the conditions that cause the lock, plus the duration-pinning/unpinning side effect. These are exactly the behavioral details an agent needs before mutating project state.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but front-loaded: the first clause identifies the operation and fields, and the remaining sentences cover lock and undo behavior. Every sentence carries useful information, though the semicolon-heavy structure could be easier to scan as separate clauses.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex stateful mutation with no output schema, the description covers the important behavioral edges: field application, composition targeting, fps locking, sample rate exemption, duration pinning, and undo/history behavior. An agent has enough context to invoke it correctly and anticipate the main failure mode.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3. The description still adds meaning by clarifying that composition_id names a Group's composition and defaults to the root, and by tying fps/sample_rate/channels to project-wide cascading semantics. Some patch semantics are repeated from the schema, keeping this at 4 rather than 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource — updating a composition's envelope — and enumerates the affected fields (width/height, fps, sample_rate, channels, color_space, background, duration_us). It also distinguishes root versus Group composition via composition_id, so an agent can tell what this tool changes without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear operational guidance: only set fields apply, composition_id is omitted for the root, fps is locked once content exists, and sample_rate is never locked. It also explains how to resolve an fps lock. It does not explicitly compare against related siblings such as set_project_settings or rename_composition, which keeps it from a full 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_effectA
Idempotent

Update an effect: patch is { enabled?, params? }, at least one; params merge key by key as plain numbers, null unsetting a key back to its catalog default. A value written to a keyframed param replaces its keys; animate with set_keyframe on effects[<effect_id>].params[<key>]. Unknown keys and out-of-range values are refused, never partially applied. Returns the effect record.

NameRequiredDescriptionDefault
patchYesEffect patch; only the fields sent are applied.
layer_idYesLayer id.
effect_idYesEffect id.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (idempotent, non-destructive), it discloses the behaviors that matter for a mutation: params merge key-by-key, `null` resets to catalog default, writing to a keyframed param destroys its keys, and invalid input is refused atomically rather than partially applied. It also states the return value.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense sentences with zero filler; the patch shape and merge semantics are front-loaded, followed by the keyframe caveat and the atomic-failure guarantee. Every clause carries distinct information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-parameter nested-patch mutation with no output schema, the description covers shape, merge behavior, failure atomicity, and the return value ("Returns the effect record"). Nothing an agent needs to call it safely is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning the schema lacks: key-by-key merge semantics, the at-least-one-field rule, keyframe replacement on write, and the set_keyframe alternative. The `effects[...].params[...]` path syntax further clarifies addressing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ("Update an effect") and immediately specifies the exact patch shape `{ enabled?, params? }` with the constraint that at least one field is required. It is clearly distinguished from sibling mutation tools like add_effect/delete_effect by naming the set_keyframe route for animation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description routes keyframe animation explicitly to set_keyframe on `effects[<effect_id>].params[<key>]`, which is a concrete when-to-use-something-else rule. It does not state exclusions such as when to prefer delete_effect + add_effect over patching, but the guidance present is actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_export_presetA
Idempotent

Change a preset in one write: name and/or settings of a personal preset, and/or default: true on any preset, built-ins too. Pass at least one. Existing projects and admitted jobs keep their copied settings.

NameRequiredDescriptionDefault
nameNoUnique personal preset name, trimmed, at most 40 characters.
defaultNoUse this preset when a project has no saved export settings. Set it on another preset to change it.
settingsNoPartial portable output settings in snake_case. Omitted fields retain base values.
preset_idYesExact preset ID from list_export_presets. Built-in IDs start with builtin:.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare a non-destructive, idempotent write, so the description's job is to add mutation detail — and it does: a single atomic write, partial semantics, and the key side effect that existing projects and admitted jobs keep their already-copied settings rather than being retroactively updated. That non-propagation caveat is exactly the kind of behavior an agent cannot get from annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: what changes first, the at-least-one constraint second, the side-effect caveat last. No restatement of the name or title and no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with a deeply nested settings object, high schema coverage, and no output schema, the definition covers the essentials: mutability scope per preset type, the minimum-argument rule, and the non-propagation guarantee. It stops short of saying what a successful response contains or how invalid/conflicting settings errors surface.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so the baseline is 3; the description earns above that by mapping parameters to preset types (name/settings only on personal presets, default:true on any preset including built-ins), which the schema does not say. It also reinforces the partial-merge rule for settings that the schema already documents.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (change) and resource (a preset), and enumerates exactly what is mutable: name and/or settings on personal presets, default:true on any preset including built-ins. The verb itself separates it from create_export_preset / delete_export_preset, though no sibling is named explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage constraints are implied rather than stated: the reader must infer that personal presets are the only ones whose name/settings can change, and that built-ins accept only the default flag. 'Pass at least one' gives a concrete validity rule, but there is no explicit statement of when to prefer this over create_export_preset or delete_export_preset.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_keyframeA
Idempotent

Change one keyframe by id in one commit — any of: t_us (move it, timeline-absolute, snapped to the frame; the track re-sorts; a frame another key holds is refused, KeyframeOccupied), easing (as set_keyframe's: the segment leaving the key, or on the last key the one arriving at it; read back in preset_ids), in / out (one side's tangent {x, y}, stored Free — x within [0, 1], y may overshoot — its segment becoming Spline; a side written on an Auto key frees the whole key), continuity ("Smooth" re-derives in from out, "Broken" changes no number), smooth: true (both sides Auto, solved on write and kept smooth as neighbours move; the adjacent segments become Spline). At least one; applied in that order, smooth alone or with t_us. Returns the key.

NameRequiredDescriptionDefault
inNoA tangent to write: {x, y} in the owning segment's unit square — x within [0, 1] (refused outside), y may overshoot. Stored Free.
outNoA tangent to write: {x, y} in the owning segment's unit square — x within [0, 1] (refused outside), y may overshoot. Stored Free.
t_usNoNew timeline-absolute time, µs.
easingNoEasing of the segment leaving the key (on the last key, the one arriving at it): {"preset":"<id>"} or a raw {"kind":...}. Writes this key's out/segment and the next key's in.
smoothNoAuto tangents on both sides, Smooth continuity. Only true; a side written later frees the key.
layer_idYesLayer id.
param_keyYesVisual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>].
continuityNoSmooth keeps the two sides at one slope (re-derived from `out`); Broken lets them differ.
keyframe_idYesKeyframe id.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the annotations (idempotentHint, destructiveHint=false, openWorldHint=false) by disclosing refusal behavior (`KeyframeOccupied` when another key holds the frame), re-sorting of the track, ordering of application, and side effects such as writing a tangent on an Auto key freeing the whole key and adjacent segments becoming Spline. These are non-obvious cross-parameter side effects an agent could not infer from the schema or annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads verb, resource, and scope in the first clause, then presents facets in applied order, mirroring execution semantics. It is dense with backticks and parentheticals and one clause chain runs long, but every clause carries operational information rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 9-parameter nested mutation tool with no output schema, the description covers ordering, refusal conditions, per-facet side effects, and the return value ("Returns the key"). Nothing an agent needs to invoke it safely is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so a 3 is the floor, and the description exceeds it by explaining semantics the schema cannot: `easing` targets the segment leaving the key (the arriving one on the last key), is read back via preset_ids, `continuity: Smooth` re-derives in from out while Broken changes no number, and `smooth` solves tangents on write and keeps them smooth as neighbours move. It omits little beyond the `x`/`y` unit-square detail, which the schema already covers.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with scope: "Change one keyframe by id in one commit", then enumerates the exact editable facets (t_us, easing, in/out, continuity, smooth). This distinguishes it from set_keyframe/delete_keyframe siblings without requiring the schema to be opened.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operational context: "At least one; applied in that order, `smooth` alone or with `t_us`", and it cross-references set_keyframe's easing semantics so the agent knows where the convention came from. It stops short of an explicit "use set_keyframe to create a new key instead" routing statement, so no full when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_layer_paramsA
Idempotent

Patch static fields of one layer; fields are kind-specific (schema variants). A static write replaces that field's animation, x/y included (Path mode refuses x/y: translate_position); set_param_track animates. scale_linked links the scale pair; while linked, one axis writes both. Text has no scale fields: resize its box. src_in_us slips the source window (span kept); retime_layers changes the rate. Returns the layer with params, each patched field as committed (values are quantized); locked layers and invalid values are refused.

NameRequiredDescriptionDefault
patchYesKind-tagged patch: `kind` must match the layer's, and only that kind's fields are accepted (one variant per kind); a key outside the set is refused naming it.
layer_idYesLayer id.

TDQS

A4.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description carries substantial behavioral weight beyond the annotations: a static write replaces that field's animation, values come back quantized, refusals happen for locked layers and invalid values, and the return value is the layer with the committed params. However, it discloses that writes replace animation while the annotations declare destructiveHint=false, a tension the description does not reconcile (the scale_linked data loss is only noted in the schema, not here).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then alternatives, then edge cases, then return/refusal semantics — a sensible order with no filler sentences. It is heavily compressed (backticked field names, stacked parentheticals), which costs some readability for an agent parsing it, but every sentence carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a complex tool: seven kind variants, nested objects, no output schema. The description still covers the selection rule (kind must match), the destructive consequences of static writes, the refusal conditions, and what comes back, which is everything an agent needs before calling it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already defines each field, and the description mostly stays at the cross-cutting level. It does add genuine meaning the schema cannot: kind-specific variants, the linked-scale rule that one axis writes both, the slip semantics of src_in_us versus trim_layer, and the text-box workaround.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Patch static fields of one layer', then immediately scopes it with 'fields are kind-specific (schema variants)'. It names the siblings it is not (set_param_track, translate_position, retime_layers), so an agent can separate it from adjacent mutation tools without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing is given for each alternative: animate with set_param_track, move x/y in Path mode with translate_position, change playback rate with retime_layers, resize text via its box because Text has no scale fields. It also states the negative condition (locked layers and invalid values are refused).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_markerA
Idempotent

Update a marker. Setting t_us re-sorts the marker list. On a marker ANCHORED to a clip, t_us names the time the mark should read and moves the ANCHOR to make it read that, so the mark keeps following its clip from the new offset — a time outside that clip's span is refused, and t_us together with t_end_us is refused (an anchored region's end follows its anchor by itself; patch one or the other).

NameRequiredDescriptionDefault
patchYesMarker patch; only fields you set apply. The anchor is `set_marker_anchor`'s, not patchable here.
marker_idYesMarker id.

TDQS

A3.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare non-destructive and idempotent, but the description goes well beyond them: setting t_us re-sorts the marker list, an anchored marker's ANCHOR physically moves to preserve its clip offset, out-of-span times are refused, and t_us plus t_end_us together are refused. These side effects and failure conditions are exactly the context an agent needs before mutating state.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the verb, then the most surprising behavior (re-sort, anchor movement, refusal rules) in descending order of importance. It is one dense paragraph with heavy parenthetical nesting, but no sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter nested patch with no output schema, the definition covers the one genuinely subtle field (t_us) and its interaction with t_end_us. It does not say what the call returns or whether non-geometric fields like note/label have any side effects, but those are minor for an idempotent, non-destructive update.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns above that by explaining that t_us means "the time the mark should read" on an anchored marker and by stating the mutual exclusion with t_end_us. The remaining fields (note, label, color) are left entirely to the schema, which is acceptable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Update a marker" states a specific verb and resource, and the following sentences clarify what kind of update (re-sorting, anchor movement). It never names the neighbouring tools (add_marker, delete_marker, set_marker_anchor) in the description itself, so differentiation is inferred rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance and no routing to alternatives; an agent is not told when to reach for this versus add_marker or set_marker_anchor. The only directive ("patch one or the other") concerns parameter combination, not tool selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_motif_filesA
Destructive

Batch edit draft files; requires current expected_revision. Each entry replaces a file with text or base64 bytes (at most 4 MiB decoded per call), applies exact-match edits to an existing text file, or deletes a path. Prefer edits over resending a whole file. The whole package must remain valid. Linked drafts write through to their directory.

NameRequiredDescriptionDefault
filesYesAtomic batch of file changes.
motif_idYesMotif id (list_motifs).
expected_revisionYesRevision returned by open, read or preview.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and openWorldHint=false; the description adds value beyond that with the per-call 4 MiB decoded budget, the validation constraint that 'the whole package must remain valid', and the notable side effect that 'Linked drafts write through to their directory'. It does not state what happens on a stale revision (rejection vs. merge) or what is returned, which is the remaining transparency gap for a destructive batch write.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four sentences, no filler, with the operation and its revision precondition front-loaded before the mode list and the 'prefer edits' heuristic. Dense but each sentence carries distinct information; only the mode enumeration partially duplicates the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, atomic, multi-mode batch mutation the description covers scope, limits, validation and write-through side effects well. However, with no output schema it never says what a successful call returns (presumably the new revision needed for the next call) or how a revision mismatch surfaces, which an agent needs to chain calls safely.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter and every oneOf branch is already documented, giving a baseline of 3. The description's prose enumeration of entry types mostly restates the schema, and its '4 MiB decoded per call' figure is an aggregate limit not present in the schema (which caps each file at 256 KiB decoded), so it adds only marginal meaning beyond the structured fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource ('Batch edit draft files') and immediately enumerates the four entry modes (replace with text, replace with base64, exact-match edits, delete). This clearly separates it from read_motif, preview_motif, open_motif_draft and install_motif, though no sibling is named explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a real preference rule ('Prefer edits over resending a whole file') and states a hard precondition ('requires current expected_revision'), which tells the agent when the call will be rejected. It stops short of naming alternatives or when-not-to-use cases, so it is clear context rather than full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_tackA
Idempotent

Change a tack's label, body, kind or status — resolved once you fixed what it pointed at, dismissed when it no longer matters, open to raise it again. At least one field. Its place is fixed at creation; to move one, delete and create it again. Returns the tack as project://tacks reads it. Unrecorded.

NameRequiredDescriptionDefault
patchYesOnly the fields you set apply.
tack_idYesTack id.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover idempotency, non-destructiveness, and closed-world scope, so the bar is lower, and the description still adds real context: partial-patch semantics, the immutability of a tack's placement, and 'Unrecorded' signalling the change is not captured in history. The return behavior is described by reference ('as project://tacks reads it'). 'Unrecorded' is terse enough to be slightly ambiguous about which history is meant.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The mutable fields and status semantics are front-loaded, and the constraint and immutability notes follow in a logical order with no filler. The final one-word sentence 'Unrecorded.' is efficient but borders on cryptic, costing a little clarity for its brevity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter partial-update tool with no output schema, the description covers the essential ground: what is mutable, the minimum payload, what cannot change, and what comes back. What remains unstated is how a rejected or conflicting patch is reported, which is a minor gap given the annotations already declare idempotent, non-destructive behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the nested patch object is already documented, so the baseline is 3. The description adds value beyond the schema by stating the 'at least one field' constraint, which is not encoded as minProperties in the schema, and by giving operational meaning to each status enum value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource ('Change a tack's...') and enumerates exactly which fields are mutable (label, body, kind, status). An agent can immediately distinguish this from create_tacks and delete_tacks in the sibling list without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains when to use each status value ('resolved' once fixed, 'dismissed' when it no longer matters, 'open' to raise again) and states the 'at least one field' precondition. It also gives an explicit when-not for placement: location is fixed at creation, so moving requires delete and recreate. It stops short of naming a sibling alternative for relocation, but the condition is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_transitionA
Idempotent

Patch a transition's duration_us, kind/direction and/or extended_us in one recorded commit; only fields you set apply. direction rides with kind: switching to Wipe/Slide needs both, and direction alone or beside Crossfade is rejected. Geometry is two targets: extended_us is the borrowed share of the overlap (0 = pure placement, duration_us = pure borrow); the outgoing layer ends at its exit frame + extended_us, the incoming starts duration_us before that. With extended_us OMITTED the trimmed ranges are preserved — growing moves the incoming layer further left and never borrows, shrinking returns borrowed tail first then moves it right. Only an explicit extended_us grows the borrow (checked against the remaining tail: TransitionInsufficientHandle { available_us }); a NEGATIVE one is a deliberate tail trim of real content. Link siblings follow the incoming layer; a move onto occupied space or across t = 0 refuses the commit. TransitionNotFound for an unknown id.

NameRequiredDescriptionDefault
kindNoNew kind; send `direction` with Wipe / Slide.
directionNoMotion direction; rides with `kind` (Wipe / Slide need it, Crossfade refuses it).
duration_usNoNew transition length, µs.
extended_usNoBorrowed-tail target in µs, at most duration_us. Omit to preserve trimmed ranges; negative = deliberate tail trim of real content.
transition_idYesTransition id.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already mark this as idempotent and non-destructive, but the description adds substantial behavioral detail beyond them: validation coupling between `kind` and `direction`, geometry semantics for `extended_us`, preservation of trimmed ranges when omitted, link-sibling behavior, refusal on occupied space or crossing t = 0, and specific error cases.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action and then elaborates on constraints and geometry. It is dense and symbol-heavy, but most sentences carry substantive information rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex mutation tool with no output schema, the description covers the key field interactions, preservation behavior, validation failures, and commit refusal conditions. An agent has enough information to invoke it correctly without needing undocumented assumptions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so each parameter is already documented. The description adds meaningful cross-parameter semantics, especially how `extended_us` controls borrowed overlap versus placement and how `direction` must ride with `kind`; this goes beyond the per-field schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Patch a transition's `duration_us`, `kind`/`direction` and/or `extended_us` in one recorded commit.' It clearly distinguishes this from `add_transition` and `delete_transition` by emphasizing patching existing fields and that 'only fields you set apply.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear usage context: fields are optional, `direction` must accompany `kind` for Wipe/Slide, and `extended_us` has distinct behavior when omitted versus explicitly set. It does not explicitly name sibling alternatives such as `add_transition`, but the update-only scope is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

weftcut_statusA
Read-only

Report whether the WeftCut desktop app is currently running and reachable, and which project it has open. Returns the endpoint state and what to do next when it is not running. Costs nothing; call this first when WeftCut tools appear to be missing or failing.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds genuinely new behavioral context: it is free to call, it returns endpoint state plus remediation guidance, and it is the correct first probe when sibling tools fail — none of which is in the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences: the first states what it reports, the second what it returns, the third when to call it. Purpose is front-loaded and every sentence carries distinct information with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only probe with no output schema, the description covers what it checks, what it returns at a high level, and when to invoke it. It does not itemize the returned fields, but that gap is small given the tool's simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is no parameter semantics to document and the description cannot be faulted for omission. Baseline 4 applies for a no-argument tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific resource (the WeftCut desktop app) and precise checks: whether it is running and reachable, plus which project is open. It is clearly a diagnostics/status read, distinct from action siblings like launch_weftcut or open_project.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit trigger: "call this first when WeftCut tools appear to be missing or failing," which is actionable context an agent can apply directly. It stops short of naming the follow-up alternative (e.g., launch_weftcut) even though it promises the response will indicate what to do next.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 84 tool updatesv0.6.0
    • Removedadd_audio_layer
    • Removedadd_color_layer
    • Changedadd_effect1 field changed
      • addedInput schema / properties / params
        Added value: +{
        +  "additionalProperties": {
        +    "description": "A static value.",
        +    "type": "number"
        +  },
        +  "description": "Initial values, param key → number, each within its catalog range, e.g. {\"amount\": -20}. Omitted keys take the catalog default.",
        +  "type": "object"
        +}
    • Removedadd_group_layer
    • Addedadd_layers
    • Changedadd_marker5 fields changed
      • changedInput schema / properties / color / description
        Previous value: -"Marker colour."New value: +"Marker colour; omit for the default."
      • removedInput schema / properties / end_t_us
        Removed value: -{
        -  "description": "Region end, timeline; omit for a point marker, µs.",
        -  "type": "integer"
        -}
      • addedInput schema / properties / note
        Added value: +{
        +  "description": "Long text, shown only in the marker panel.",
        +  "type": "string"
        +}
      • addedInput schema / properties / t_end_us
        Added value: +{
        +  "description": "Region end, timeline; omit for a point marker, µs.",
        +  "type": "integer"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "color",
        -  "label",
        -  "t_us"
        -]New value: +[
        +  "label",
        +  "t_us"
        +]
    • Removedadd_motif_layer
    • Removedadd_text_layer
    • Removedadd_video_layer
    • Changedanalyze_audio4 fields changed
      • removedInput schema / properties / end_us
        Removed value: -{
        -  "description": "Source-absolute end, exclusive. Default start + 60 seconds, capped at media end. At most 60 seconds per call.",
        -  "type": "integer"
        -}
      • addedInput schema / properties / src_end_us
        Added value: +{
        +  "description": "Source-absolute end, exclusive. Default start + 60 seconds, capped at media end. At most 60 seconds per call.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / src_start_us
        Added value: +{
        +  "description": "Source-absolute start in microseconds, inclusive. Default 0.",
        +  "type": "integer"
        +}
      • removedInput schema / properties / start_us
        Removed value: -{
        -  "description": "Source-absolute start in microseconds, inclusive. Default 0.",
        -  "type": "integer"
        -}
    • Changedanalyze_clip7 fields changed
      • changedInput schema / properties / layer_id / description
        Previous value: -"Target VideoClip layer id."New value: +"A VideoClip: the answer is clipped to the source it plays and carries\nits `mapping`."
      • addedInput schema / properties / media_id
        Added value: +{
        +  "description": "A pooled video, scanned whole (placed or not).",
        +  "type": "string"
        +}
      • changedInput schema / properties / passes / description
        Previous value: -"Which passes to run — a subset of `[\"shots\", \"stats\", \"events\"]`.\nDefault all. Drop `\"stats\"` / `\"events\"` to skip per-shot frame sampling\nand return timing only."New value: +"Which passes to run. Default shots, stats, events; `[\"shots\"]` is\ntiming only (no frame sampling). `\"spans\"` is opt-in: one sampled\ndecode of the source for dark / soft / frozen spans."
      • addedInput schema / properties / passes / items / description
        Added value: +"Which `analyze_clip` passes run."
      • addedInput schema / properties / passes / items / enum
        Added value: +[
        +  "shots",
        +  "stats",
        +  "events",
        +  "spans"
        +]
      • addedInput schema / properties / step_us
        Added value: +{
        +  "description": "The spans pass's sampling step (microseconds), 100000..=10000000.\nDefault 500000. Needs `\"spans\"` in `passes`.",
        +  "type": "integer"
        +}
      • removedInput schema / required
        Removed value: -[
        -  "layer_id"
        -]
    • Changedapply_transcripts12 fields changed
      • changedInput schema / properties / composition_id / description
        Previous value: -"Composition to create in — a Group's id from `project://compositions`; omit for the root."New value: +"Composition whose captions are meant — a Group's id from `project://compositions`; omit for the root."
      • removedInput schema / properties / source_layer_ids
        Removed value: -{
        -  "description": "Parallel to `transcripts`: the layer each was transcribed from.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • changedInput schema / properties / transcripts / description
        Previous value: -"One entry per transcribed clip, in the shape `transcribe_clip` returns."New value: +"`transcribe_clip`'s `transcripts`, or your own in that shape."
      • changedInput schema / properties / transcripts / items / properties / segments / description
        Previous value: -"Cues, with timeline-absolute microsecond bounds."New value: +"Cues, timeline µs."
      • changedInput schema / properties / transcripts / items / properties / segments / items / properties / t_end_us / description
        Previous value: -"Cue end (exclusive), timeline-absolute, µs."New value: +"Cue end (exclusive), timeline, µs."
      • changedInput schema / properties / transcripts / items / properties / segments / items / properties / t_start_us / description
        Previous value: -"Cue start, timeline-absolute, µs."New value: +"Cue start, timeline, µs."
      • changedInput schema / properties / transcripts / items / properties / segments / items / properties / words / description
        Previous value: -"Word offsets, timeline-absolute like the cue. Empty is allowed."New value: +"Word offsets, timeline µs like the cue. Empty is allowed."
      • changedInput schema / properties / transcripts / items / properties / segments / items / properties / words / items / properties / t_end_us / description
        Previous value: -"Word end (exclusive), timeline-absolute, µs."New value: +"Word end (exclusive), timeline, µs."
      • changedInput schema / properties / transcripts / items / properties / segments / items / properties / words / items / properties / t_start_us / description
        Previous value: -"Word start, timeline-absolute, µs."New value: +"Word start, timeline, µs."
      • addedInput schema / properties / transcripts / items / properties / source
        Added value: +{
        +  "description": "The clip it was transcribed from, as `transcribe_clip` names it; a `signature` that no longer matches refuses.",
        +  "properties": {
        +    "layer_id": {
        +      "description": "The layer that was read.",
        +      "type": "string"
        +    },
        +    "signature": {
        +      "description": "Its state when read.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "layer_id"
        +  ],
        +  "type": "object"
        +}
      • changedInput schema / properties / transcripts / items / properties / word_timing / description
        Previous value: -"`transcribe_clip`'s field of the same name: where the word offsets came from. `none` stores cues with no word timing."New value: +"Where the word offsets came from. `none` stores cues with no word timing."
      • addedInput schema / properties / transcripts / maxItems
        Added value: +1000
    • Changedbegin_agent_session3 fields changed
      • addedInput schema / properties / force
        Added value: +{
        +  "description": "End another connection's session (its owner gone) and begin yours. Default false.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / lock
        Added value: +{
        +  "description": "Lock the user's undo for the session. Default true; false leaves it free.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / reason / description
        Previous value: -"What this work session is for; shown to the user beside the busy badge."New value: +"What this work session is for; shown to the user beside the busy badge and in place of undo."
    • Removedbegin_file_upload
    • Removedclear_keyframes
    • Changedcompare_frames10 fields changed
      • changedInput schema / properties / a / properties / layer_id / description
        Previous value: -"Target VideoClip layer id."New value: +"Or a VideoClip, read for its source."
      • addedInput schema / properties / a / properties / media_id
        Added value: +{
        +  "description": "A pooled video (placed or not).",
        +  "type": "string"
        +}
      • addedInput schema / properties / a / properties / src_us
        Added value: +{
        +  "description": "Source-absolute microseconds of the frame to sample (the space\n`analyze_clip`'s `src_keyframe_us` uses).",
        +  "type": "integer"
        +}
      • removedInput schema / properties / a / properties / t_us
        Removed value: -{
        -  "description": "SOURCE-ABSOLUTE microseconds of the frame to sample (the space\n`analyze_clip`'s `keyframe_t_us` uses).",
        -  "type": "integer"
        -}
      • changedInput schema / properties / a / required
        Previous value: -[
        -  "layer_id",
        -  "t_us"
        -]New value: +[
        +  "src_us"
        +]
      • changedInput schema / properties / b / properties / layer_id / description
        Previous value: -"Target VideoClip layer id."New value: +"Or a VideoClip, read for its source."
      • addedInput schema / properties / b / properties / media_id
        Added value: +{
        +  "description": "A pooled video (placed or not).",
        +  "type": "string"
        +}
      • addedInput schema / properties / b / properties / src_us
        Added value: +{
        +  "description": "Source-absolute microseconds of the frame to sample (the space\n`analyze_clip`'s `src_keyframe_us` uses).",
        +  "type": "integer"
        +}
      • removedInput schema / properties / b / properties / t_us
        Removed value: -{
        -  "description": "SOURCE-ABSOLUTE microseconds of the frame to sample (the space\n`analyze_clip`'s `keyframe_t_us` uses).",
        -  "type": "integer"
        -}
      • changedInput schema / properties / b / required
        Previous value: -[
        -  "layer_id",
        -  "t_us"
        -]New value: +[
        +  "src_us"
        +]
    • Changedcorrect_caption_text2 fields changed
      • addedInput schema / properties / script
        Added value: +{
        +  "description": "The full verbatim transcript of the speech these captions show, correctly spelled.",
        +  "maxLength": 100000,
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[]New value: +[
        +  "script"
        +]
    • Changedcreate_export_preset2 fields changed
      • changedInput schema / properties / settings / description
        Previous value: -"Partial portable output settings in snake_case. Excludes engines, hardware acceleration, paths and ranges. Omitted fields retain base values."New value: +"Partial portable output settings in snake_case. Omitted fields retain base values."
      • changedInput schema / properties / settings / properties / resolution_height / description
        Previous value: -"Output height in pixels, downscale only. Null follows composition; omission keeps saved setting."New value: +"Output height in pixels, downscale only. Null follows composition."
    • Changedcreate_tacks2 fields changed
      • removedInput schema / properties / tacks / items / properties / end_t_us
        Removed value: -{
        -  "description": "Range end, timeline; omit for a point, µs.",
        -  "type": "integer"
        -}
      • addedInput schema / properties / tacks / items / properties / t_end_us
        Added value: +{
        +  "description": "Range end, timeline; omit for a point, µs.",
        +  "type": "integer"
        +}
    • Removeddelete_checkpoint
    • Removeddelete_file_transfer
    • Changeddelete_motif3 fields changed
      • removedInput schema / properties / id
        Removed value: -{
        -  "description": "Motif id.",
        -  "type": "string"
        -}
      • addedInput schema / properties / motif_id
        Added value: +{
        +  "description": "Motif id (list_motifs).",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "id"
        -]New value: +[
        +  "motif_id"
        +]
    • Changeddescribe_clip12 fields changed
      • changedInput schema / properties / backend / description
        Previous value: -"Strict engine override: `\"qwen3_vl\"` | `\"minicpm_v\"` | `\"byo_endpoint\"`.\nThat engine serves or the call errors; nothing is substituted. Omitted:\nthe user's preferred engine, then availability."New value: +"Strict engine override; that engine serves or the call errors.\n`byo_endpoint` uploads frames."
      • addedInput schema / properties / backend / enum
        Added value: +[
        +  "qwen3_vl",
        +  "minicpm_v",
        +  "byo_endpoint"
        +]
      • changedInput schema / properties / focus / description
        Previous value: -"`\"general\"` or `\"shot-type\"` (biases `tags` toward shot type / camera).\nDefault: the app's setting, else `\"general\"`. Cache key."New value: +"`shot-type` biases `tags` toward shot type / camera. Default: the app's\nsetting, else `general`. Cache key."
      • addedInput schema / properties / focus / enum
        Added value: +[
        +  "general",
        +  "shot-type"
        +]
      • changedInput schema / properties / layer_id / description
        Previous value: -"Target VideoClip layer id."New value: +"Or a VideoClip: the default window is the source it plays, and the\nanswer carries its `mapping`."
      • addedInput schema / properties / media_id
        Added value: +{
        +  "description": "A pooled video, described whole by default (placed or not).",
        +  "type": "string"
        +}
      • removedInput schema / properties / purpose
        Removed value: -{
        -  "default": "clip",
        -  "description": "Cache purpose: clip content (default) or individual shot identification.\nIndependent of prompt focus; results are never shared across purposes.",
        -  "enum": [
        -    "clip",
        -    "shot"
        -  ],
        -  "type": "string"
        -}
      • addedInput schema / properties / src_end_us
        Added value: +{
        +  "description": "Optional exclusive window end, source-absolute microseconds. Defaults to\nthe end of the source the layer plays. Must lie within it.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / src_start_us
        Added value: +{
        +  "description": "Optional window start, source-absolute microseconds (the space the\nanswer's segments and `analyze_clip`'s shots use). Defaults to the start\nof the source the layer plays. Must lie within it.",
        +  "type": "integer"
        +}
      • removedInput schema / properties / t_end_us
        Removed value: -{
        -  "description": "Optional window end in timeline microseconds. Defaults to the layer's\n`t_end_us`. Must lie within the layer.",
        -  "type": "integer"
        -}
      • removedInput schema / properties / t_start_us
        Removed value: -{
        -  "description": "Optional window start in timeline microseconds. Defaults to the layer's\n`t_start_us`. Must lie within the layer.",
        -  "type": "integer"
        -}
      • removedInput schema / required
        Removed value: -[
        -  "layer_id"
        -]
    • Changeddetect_pauses3 fields changed
      • removedInput schema / properties / bridge_us
        Removed value: -{
        -  "description": "A loud run shorter than this (µs) inside a quiet run does not end the\npause. Default 80000 (80ms). Must be ≥ 0 and below `min_pause_us`.",
        -  "type": "integer"
        -}
      • removedInput schema / properties / threshold_amp
        Removed value: -{
        -  "description": "Peak amplitude threshold in [0.0, 1.0]. Anything strictly below this\ncounts as quiet. Default 0.02 (≈ -34 dBFS).",
        -  "type": "number"
        -}
      • addedInput schema / properties / threshold_db
        Added value: +{
        +  "description": "Peak threshold, dBFS (≤ 0). Anything strictly below it counts as\nquiet. Default -34.",
        +  "type": "number"
        +}
    • Removeddry_run
    • Changedend_agent_session1 field changed
      • removedInput schema / properties / force
        Removed value: -{
        -  "description": "End another connection's session too. Default false.",
        -  "type": "boolean"
        -}
    • Changedexport_captions1 field changed
      • addedInput schema / properties / range
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "Snapped to the frame grid as start_export snaps it; omit for all cues.",
        +  "properties": {
        +    "t_end_us": {
        +      "description": "Exclusive end, timeline, µs.",
        +      "type": "integer"
        +    },
        +    "t_start_us": {
        +      "description": "Inclusive start, timeline, µs.",
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "t_start_us",
        +    "t_end_us"
        +  ],
        +  "type": "object"
        +}
    • Changedexport_motif3 fields changed
      • removedInput schema / properties / id
        Removed value: -{
        -  "description": "Motif id.",
        -  "type": "string"
        -}
      • addedInput schema / properties / motif_id
        Added value: +{
        +  "description": "Motif id (list_motifs).",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "id"
        -]New value: +[
        +  "motif_id",
        +  "path"
        +]
    • Changedget_export_status1 field changed
      • addedInput schema / properties / wait_s
        Added value: +{
        +  "description": "Block up to this many seconds for a state change.",
        +  "maximum": 60,
        +  "minimum": 0,
        +  "type": "integer"
        +}
    • Removedget_frame_interpolation_capabilities
    • Changedimport_media3 fields changed
      • removedInput schema / properties / path
        Removed value: -{
        -  "description": "Path to a video / audio / image / subtitle file the host can read: absolute, or relative to the open project's folder.",
        -  "type": "string"
        -}
      • addedInput schema / properties / paths
        Added value: +{
        +  "description": "1–50 video / audio / image / subtitle files the host can read: absolute, or relative to the open project's folder.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "maxItems": 50,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "path"
        -]New value: +[
        +  "paths"
        +]
    • Changedinstall_motif3 fields changed
      • removedInput schema / properties / draft_id
        Removed value: -{
        -  "description": "Editable draft id.",
        -  "type": "string"
        -}
      • addedInput schema / properties / motif_id
        Added value: +{
        +  "description": "Motif id (list_motifs).",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "draft_id",
        -  "expected_revision"
        -]New value: +[
        +  "motif_id",
        +  "expected_revision"
        +]
    • Changedjump_to3 fields changed
      • removedInput schema / properties / index
        Removed value: -{
        -  "description": "Absolute history index, in `project://history`'s numbering (`window_start + i`).",
        -  "type": "integer"
        -}
      • addedInput schema / properties / op_id
        Added value: +{
        +  "description": "The op to land on: an `ops[].op_id` of `project://history`.",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "index"
        -]New value: +[
        +  "op_id"
        +]
    • Removedlist_checkpoints
    • Removedmove_layer
    • Addedmove_layers
    • Changedmove_layers_to_composition4 fields changed
      • changedInput schema / properties / anchor_layer_id / description
        Previous value: -"Which member `anchor_t_start_us` positions; every other member keeps its offset from it."New value: +"Which member `t_start_us` positions; every other member keeps its offset from it."
      • removedInput schema / properties / anchor_t_start_us
        Removed value: -{
        -  "description": "The anchor's start time on the DESTINATION's clock — absolute, not a delta.",
        -  "type": "integer"
        -}
      • addedInput schema / properties / t_start_us
        Added value: +{
        +  "description": "The anchor's start time on the DESTINATION's clock — absolute, not a delta.",
        +  "type": "integer"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "anchor_layer_id",
        -  "anchor_t_start_us",
        -  "layer_ids",
        -  "to_composition_id"
        -]New value: +[
        +  "anchor_layer_id",
        +  "t_start_us",
        +  "layer_ids",
        +  "to_composition_id"
        +]
    • Changedopen_motif_draft1 field changed
      • changedInput schema / properties / source / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "kind": {
        -        "const": "directory",
        -        "description": "Source type."
        -      },
        -      "path": {
        -        "description": "Absolute package directory on the app machine.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "path"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "kind": {
        -        "const": "zip",
        -        "description": "Source type."
        -      },
        -      "path": {
        -        "description": "Absolute path on the app machine.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "path"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "file_id": {
        -        "description": "Temporary file transfer id.",
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "zip",
        -        "description": "Source type."
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "file_id"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "id": {
        -        "description": "Motif id.",
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "motif",
        -        "description": "Source type."
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "id"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "kind": {
        -        "const": "empty",
        -        "description": "Source type."
        -      },
        -      "name": {
        -        "description": "Initial display name.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "kind": {
        +        "const": "directory",
        +        "description": "Source type."
        +      },
        +      "path": {
        +        "description": "Absolute package directory on the app machine.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "path"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "kind": {
        +        "const": "zip",
        +        "description": "Source type."
        +      },
        +      "path": {
        +        "description": "Absolute path on the app machine.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "path"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "kind": {
        +        "const": "motif",
        +        "description": "Source type."
        +      },
        +      "motif_id": {
        +        "description": "Motif id (list_motifs).",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "motif_id"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "kind": {
        +        "const": "copy",
        +        "description": "Source type."
        +      },
        +      "motif_id": {
        +        "description": "Motif id (list_motifs).",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "motif_id"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "kind": {
        +        "const": "empty",
        +        "description": "Source type."
        +      },
        +      "name": {
        +        "description": "Display name; the draft's first publication takes its id from it.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedpaste_layers6 fields changed
      • addedInput schema / properties / delta_us
        Added value: +{
        +  "description": "Start of the seed's clone relative to the seed's own start, so every clone shifts by that much. Exclusive with `t_start_us`.",
        +  "type": "integer"
        +}
      • removedInput schema / properties / t_offset_us
        Removed value: -{
        -  "description": "Start of the seed's clone relative to the seed's own start, so `t_offset_us` shifts every clone by that much. Mutually exclusive with `t_start_us`.",
        -  "type": "integer"
        -}
      • changedInput schema / properties / t_start_us / description
        Previous value: -"Absolute start time of the seed's clone; the other clones keep their offsets from it. Mutually exclusive with `t_offset_us`."New value: +"Absolute start time of the seed's clone; the other clones keep their offsets from it. Exclusive with `delta_us`."
      • removedInput schema / properties / target_track_id
        Removed value: -{
        -  "description": "Track for the seed's clone. Omit to keep it on the seed's track.",
        -  "type": "string"
        -}
      • addedInput schema / properties / track_id
        Added value: +{
        +  "description": "Track for the seed's clone. Omit to keep it on the seed's track.",
        +  "type": "string"
        +}
      • addedInput schema / properties / unique
        Added value: +{
        +  "description": "Give each Group clone its own deep copy of the Group's composition, so editing inside it leaves the source alone. Default false: another instance of the same composition.",
        +  "type": "boolean"
        +}
    • Removedping
    • Changedpreview_motif7 fields changed
      • changedInput schema / properties / height / description
        Previous value: -"Maximum image height in pixels; the whole frame is scaled to fit."New value: +"Maximum frame height in pixels; the whole canvas is scaled to fit."
      • removedInput schema / properties / id
        Removed value: -{
        -  "description": "Motif id.",
        -  "type": "string"
        -}
      • addedInput schema / properties / local_t_s
        Added value: +{
        +  "description": "1–24 times, in seconds from the Motif's start (its frame(t) time), not timeline time.",
        +  "items": {
        +    "minimum": 0,
        +    "type": "number"
        +  },
        +  "maxItems": 24,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / properties / motif_id
        Added value: +{
        +  "description": "Motif id (list_motifs).",
        +  "type": "string"
        +}
      • removedInput schema / properties / t_sec
        Removed value: -{
        -  "description": "Absolute content time in seconds.",
        -  "type": "number"
        -}
      • changedInput schema / properties / width / description
        Previous value: -"Maximum image width in pixels; the whole frame is scaled to fit."New value: +"Maximum frame width in pixels (default 640); the whole canvas is scaled to fit."
      • changedInput schema / required
        Previous value: -[
        -  "id",
        -  "t_sec"
        -]New value: +[
        +  "motif_id",
        +  "local_t_s"
        +]
    • Removedread_file_transfer
    • Changedread_motif4 fields changed
      • removedInput schema / properties / encoding
        Removed value: -{
        -  "description": "text for UTF-8; file for a download id.",
        -  "enum": [
        -    "text",
        -    "file"
        -  ],
        -  "type": "string"
        -}
      • removedInput schema / properties / id
        Removed value: -{
        -  "description": "Motif id.",
        -  "type": "string"
        -}
      • addedInput schema / properties / motif_id
        Added value: +{
        +  "description": "Motif id (list_motifs).",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "id"
        -]New value: +[
        +  "motif_id"
        +]
    • Changedread_project4 fields changed
      • addedInput schema / properties / path
        Added value: +{
        +  "description": "For `skill`: a file beside SKILL.md, as SKILL.md names it (`craft/rules.md`); omit for SKILL.md.",
        +  "type": "string"
        +}
      • addedInput schema / properties / src_us
        Added value: +{
        +  "description": "For `media_frame`: the frame time in the source, µs.",
        +  "type": "integer"
        +}
      • removedInput schema / properties / t_us
        Removed value: -{
        -  "description": "For `media_frame`: the frame time in the SOURCE, µs.",
        -  "type": "integer"
        -}
      • changedInput schema / properties / view / enum
        Previous value: -[
        -  "current",
        -  "composition",
        -  "compositions",
        -  "media",
        -  "tracks",
        -  "layer",
        -  "markers",
        -  "links",
        -  "transitions",
        -  "settings",
        -  "history",
        -  "session",
        -  "effects",
        -  "tacks",
        -  "taste",
        -  "media_thumbnail",
        -  "media_frame"
        -]New value: +[
        +  "composition",
        +  "compositions",
        +  "media",
        +  "tracks",
        +  "layer",
        +  "markers",
        +  "links",
        +  "transitions",
        +  "settings",
        +  "history",
        +  "session",
        +  "effects",
        +  "tacks",
        +  "taste",
        +  "skill",
        +  "media_thumbnail",
        +  "media_frame"
        +]
    • Changedremove_pauses4 fields changed
      • changedInput schema / properties / min_pause_us / description
        Previous value: -"Shortest pause worth removing, in microseconds — the same parameter `detect_pauses` takes. Omit to use that tool's own default."New value: +"Shortest pause worth removing, µs, as `detect_pauses` takes it. Omit for its default."
      • addedInput schema / properties / pauses
        Added value: +{
        +  "description": "Timeline ranges to cut, as `detect_pauses` returned them; replaces detection, so not with `threshold_db` / `min_pause_us`.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "t_end_us": {
        +        "description": "Pause end (exclusive), timeline, µs.",
        +        "type": "integer"
        +      },
        +      "t_start_us": {
        +        "description": "Pause start, timeline, µs.",
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "t_start_us",
        +      "t_end_us"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 1000,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • removedInput schema / properties / threshold_amp
        Removed value: -{
        -  "description": "Peak amplitude threshold in [0.0, 1.0], the same parameter `detect_pauses` takes. Omit to use that tool's own default.",
        -  "type": "number"
        -}
      • addedInput schema / properties / threshold_db
        Added value: +{
        +  "description": "Peak threshold, dBFS (≤ 0), as `detect_pauses` takes it. Omit for its default.",
        +  "type": "number"
        +}
    • Removedrename_export_preset
    • Addedrename_layer
    • Changedrender_frames3 fields changed
      • addedInput schema / properties / t_us
        Added value: +{
        +  "description": "Timeline times in µs.",
        +  "items": {
        +    "minimum": 0,
        +    "type": "integer"
        +  },
        +  "maxItems": 24,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • removedInput schema / properties / times_us
        Removed value: -{
        -  "description": "Composition times in µs.",
        -  "items": {
        -    "minimum": 0,
        -    "type": "integer"
        -  },
        -  "maxItems": 24,
        -  "minItems": 1,
        -  "type": "array"
        -}
      • addedInput schema / properties / without
        Added value: +{
        +  "description": "Skip clip effects; the answer lists them in omitted. Crops and transitions still refuse.",
        +  "items": {
        +    "enum": [
        +      "effects"
        +    ],
        +    "type": "string"
        +  },
        +  "maxItems": 1,
        +  "minItems": 1,
        +  "type": "array"
        +}
    • Removedrestyle_captions
    • Changedrestyle_to_taste3 fields changed
      • changedInput schema / properties / graphic_role / description
        Previous value: -"Every Text layer with this role."New value: +"Every Text or Motif layer with this role; null selects the untagged ones."
      • changedInput schema / properties / graphic_role / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
      • changedInput schema / properties / layer_ids / description
        Previous value: -"Text layers to restyle."New value: +"Text or Motif layers to restyle."
    • Changedretime_layers3 fields changed
      • addedInput schema / properties / preserve_pitch
        Added value: +{
        +  "description": "Keep the pitch of the Audio and Group clips when the rate changes. Omit to leave the policy alone.",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / target / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "kind": {
        -        "const": "Rate",
        -        "description": "Rate target.",
        -        "type": "string"
        -      },
        -      "value": {
        -        "additionalProperties": false,
        -        "description": "Reduced positive rational.",
        -        "properties": {
        -          "den": {
        -            "description": "Denominator.",
        -            "minimum": 1,
        -            "type": "integer"
        -          },
        -          "num": {
        -            "description": "Numerator.",
        -            "minimum": 1,
        -            "type": "integer"
        -          }
        -        },
        -        "required": [
        -          "num",
        -          "den"
        -        ],
        -        "type": "object"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "value"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "duration_us": {
        -        "description": "Target microseconds.",
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "kind": {
        -        "const": "Duration",
        -        "description": "Duration target.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "kind",
        -      "duration_us"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "kind": {
        +        "const": "Rate",
        +        "description": "Rate target.",
        +        "type": "string"
        +      },
        +      "value": {
        +        "additionalProperties": false,
        +        "description": "Reduced positive rational: source µs per timeline µs.",
        +        "properties": {
        +          "den": {
        +            "description": "Denominator.",
        +            "minimum": 1,
        +            "type": "integer"
        +          },
        +          "num": {
        +            "description": "Numerator.",
        +            "minimum": 1,
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "num",
        +          "den"
        +        ],
        +        "type": "object"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "value"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "duration_us": {
        +        "description": "Target microseconds.",
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "kind": {
        +        "const": "Duration",
        +        "description": "Duration target.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "kind",
        +      "duration_us"
        +    ],
        +    "type": "object"
        +  }
        +]
      • changedInput schema / required
        Previous value: -[
        -  "layer_ids",
        -  "target"
        -]New value: +[
        +  "layer_ids"
        +]
    • Removedripple_delete_gap
    • Removedseparate_audio_to_new_track
    • Removedset_default_export_preset
    • Removedset_extrapolation
    • Removedset_frame_interpolation
    • Removedset_history_lock
    • Changedset_keyframe2 fields changed
      • addedInput schema / properties / easing
        Added value: +{
        +  "description": "Easing of the segment leaving the key (on the last key, the one arriving at it): {\"preset\":\"<id>\"} or a raw {\"kind\":...}. Writes this key's out/segment and the next key's in.",
        +  "properties": {
        +    "amplitude": {
        +      "description": "Elastic only: overshoot amplitude, >= 1. Omit for the default 1.",
        +      "type": "number"
        +    },
        +    "dir": {
        +      "description": "Elastic/Bounce only: easing direction.",
        +      "enum": [
        +        "In",
        +        "Out",
        +        "InOut"
        +      ],
        +      "type": "string"
        +    },
        +    "kind": {
        +      "description": "A raw easing kind, instead of a preset.",
        +      "enum": [
        +        "Hold",
        +        "Linear",
        +        "Bezier",
        +        "Elastic",
        +        "Bounce"
        +      ],
        +      "type": "string"
        +    },
        +    "p1": {
        +      "description": "Bezier only: first control point [x, y]; x within [0, 1].",
        +      "items": {
        +        "type": "number"
        +      },
        +      "maxItems": 2,
        +      "minItems": 2,
        +      "type": "array"
        +    },
        +    "p2": {
        +      "description": "Bezier only: second control point [x, y]; x within [0, 1].",
        +      "items": {
        +        "type": "number"
        +      },
        +      "maxItems": 2,
        +      "minItems": 2,
        +      "type": "array"
        +    },
        +    "period": {
        +      "description": "Elastic only: oscillation period, > 0. Omit for the default 0.3.",
        +      "type": "number"
        +    },
        +    "preset": {
        +      "description": "Preset id from the canonical easing table (e.g. \"ease_in_out\", \"ease_out_expo\"); read back in preset_ids.",
        +      "enum": [
        +        "linear",
        +        "hold",
        +        "ease",
        +        "ease_in",
        +        "ease_out",
        +        "ease_in_out",
        +        "ease_in_sine",
        +        "ease_out_sine",
        +        "ease_in_out_sine",
        +        "ease_in_quad",
        +        "ease_out_quad",
        +        "ease_in_out_quad",
        +        "ease_in_cubic",
        +        "ease_out_cubic",
        +        "ease_in_out_cubic",
        +        "ease_in_quart",
        +        "ease_out_quart",
        +        "ease_in_out_quart",
        +        "ease_in_quint",
        +        "ease_out_quint",
        +        "ease_in_out_quint",
        +        "ease_in_expo",
        +        "ease_out_expo",
        +        "ease_in_out_expo",
        +        "ease_in_circ",
        +        "ease_out_circ",
        +        "ease_in_out_circ",
        +        "ease_in_back",
        +        "ease_out_back",
        +        "ease_in_out_back",
        +        "ease_in_elastic",
        +        "ease_out_elastic",
        +        "ease_in_out_elastic",
        +        "ease_in_bounce",
        +        "ease_out_bounce",
        +        "ease_in_out_bounce"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "required": [],
        +  "type": "object"
        +}
      • removedInput schema / properties / interp
        Removed value: -{
        -  "description": "Easing: {\"kind\":\"Hold\"} | {\"kind\":\"Linear\"} | {\"kind\":\"Bezier\",\"p1\":[x,y],\"p2\":[x,y]} | {\"kind\":\"Elastic\",\"dir\",amplitude?,period?} | {\"kind\":\"Bounce\",\"dir\"}.",
        -  "properties": {
        -    "amplitude": {
        -      "description": "Elastic only: overshoot amplitude, >= 1. Omit for the default 1.",
        -      "type": "number"
        -    },
        -    "dir": {
        -      "description": "Elastic/Bounce only: easing direction.",
        -      "enum": [
        -        "In",
        -        "Out",
        -        "InOut"
        -      ],
        -      "type": "string"
        -    },
        -    "kind": {
        -      "description": "Easing kind of the segment leaving the key.",
        -      "enum": [
        -        "Hold",
        -        "Linear",
        -        "Bezier",
        -        "Elastic",
        -        "Bounce"
        -      ],
        -      "type": "string"
        -    },
        -    "p1": {
        -      "description": "Bezier only: first control point [x, y]; x within [0, 1].",
        -      "items": {
        -        "type": "number"
        -      },
        -      "maxItems": 2,
        -      "minItems": 2,
        -      "type": "array"
        -    },
        -    "p2": {
        -      "description": "Bezier only: second control point [x, y]; x within [0, 1].",
        -      "items": {
        -        "type": "number"
        -      },
        -      "maxItems": 2,
        -      "minItems": 2,
        -      "type": "array"
        -    },
        -    "period": {
        -      "description": "Elastic only: oscillation period, > 0. Omit for the default 0.3.",
        -      "type": "number"
        -    }
        -  },
        -  "required": [
        -    "kind"
        -  ],
        -  "type": "object"
        -}
    • Addedset_layer_flags
    • Removedset_layers_enabled
    • Changedset_param_track5 fields changed
      • changedInput schema / properties / track / properties / extrapolate / description
        Previous value: -"What the track does outside its keys, per side: Hold | Loop | PingPong | Offset | Continue (see set_extrapolation)."New value: +"Outside the keys, per side: Hold (end value) | Loop (repeat from the first key) | PingPong | Offset (each cycle adds last − first) | Continue (end velocity). Period = last − first; path_progress takes Hold/Loop/PingPong."
      • addedInput schema / properties / track / properties / value / items / properties / easing
        Added value: +{
        +  "description": "As set_keyframe's `easing`: {\"preset\":\"<id>\"} or a raw {\"kind\":...}; replaces this key's out/segment and the next key's in.",
        +  "type": "object"
        +}
      • changedInput schema / properties / track / properties / value / items / properties / in / required
        Previous value: -[
        -  "x",
        -  "y",
        -  "mode"
        -]New value: +[
        +  "mode"
        +]
      • changedInput schema / properties / track / properties / value / items / properties / out / required
        Previous value: -[
        -  "x",
        -  "y",
        -  "mode"
        -]New value: +[
        +  "mode"
        +]
      • changedInput schema / properties / track / properties / value / items / properties / t_us / description
        Previous value: -"Key time; timeline-absolute for set_param_track, layer-local for set_position, µs."New value: +"Key time, timeline, µs."
    • Changedset_position10 fields changed
      • addedInput schema / properties / position / oneOf
        Added value: +[
        +  {
        +    "properties": {
        +      "mode": {
        +        "const": "XY",
        +        "description": "XY needs both tracks."
        +      }
        +    },
        +    "required": [
        +      "mode",
        +      "x",
        +      "y"
        +    ]
        +  },
        +  {
        +    "properties": {
        +      "mode": {
        +        "const": "Path",
        +        "description": "Path needs the route and its progress."
        +      }
        +    },
        +    "required": [
        +      "mode",
        +      "path",
        +      "progress"
        +    ]
        +  }
        +]
      • addedInput schema / properties / position / properties / progress / properties / value / items / properties / local_t_us
        Added value: +{
        +  "description": "Layer-local key time, µs.",
        +  "type": "integer"
        +}
      • removedInput schema / properties / position / properties / progress / properties / value / items / properties / t_us
        Removed value: -{
        -  "description": "Layer-local time, µs.",
        -  "type": "integer"
        -}
      • changedInput schema / properties / position / properties / progress / properties / value / items / required
        Previous value: -[
        -  "t_us",
        -  "value"
        -]New value: +[
        +  "local_t_us",
        +  "value"
        +]
      • addedInput schema / properties / position / properties / x / properties / value / items / properties / local_t_us
        Added value: +{
        +  "description": "Layer-local key time, µs.",
        +  "type": "integer"
        +}
      • removedInput schema / properties / position / properties / x / properties / value / items / properties / t_us
        Removed value: -{
        -  "description": "Layer-local time, µs.",
        -  "type": "integer"
        -}
      • changedInput schema / properties / position / properties / x / properties / value / items / required
        Previous value: -[
        -  "t_us",
        -  "value"
        -]New value: +[
        +  "local_t_us",
        +  "value"
        +]
      • addedInput schema / properties / position / properties / y / properties / value / items / properties / local_t_us
        Added value: +{
        +  "description": "Layer-local key time, µs.",
        +  "type": "integer"
        +}
      • removedInput schema / properties / position / properties / y / properties / value / items / properties / t_us
        Removed value: -{
        -  "description": "Layer-local time, µs.",
        -  "type": "integer"
        -}
      • changedInput schema / properties / position / properties / y / properties / value / items / required
        Previous value: -[
        -  "t_us",
        -  "value"
        -]New value: +[
        +  "local_t_us",
        +  "value"
        +]
    • Removedset_preserve_pitch
    • Changedset_project_settings6 fields changed
      • changedInput schema / properties / patch / properties / auto_pair_audio_on_import / description
        Previous value: -"Whether `add_video_layer` also places and links the source's audio. Default on; off places a video silent."New value: +"The default of `add_layers` video `audio`: on places and links the source's audio, off places a video silent. Default on."
      • removedInput schema / properties / patch / properties / correction_script
        Removed value: -{
        -  "description": "Reference text `correct_caption_text` corrects against — the script, notes, the spelling of every name. Must be set before that call.",
        -  "type": "string"
        -}
      • changedInput schema / properties / patch / properties / pause_review / description
        Previous value: -"Pause parameters `detect_pauses` / `remove_pauses` run at, or `null` for their defaults. `threshold_amp` in [0, 1], `min_pause_us` > 0, `pad_us` >= 0 with `2 * pad_us < min_pause_us`."New value: +"The Pauses section's parameters, or `null` for the defaults. `threshold_db` ≤ 0, `min_pause_us` > 0, `pad_us` >= 0 with `2 * pad_us < min_pause_us`."
      • removedInput schema / properties / patch / properties / pause_review / properties / threshold_amp
        Removed value: -{
        -  "description": "Peak amplitude below which audio counts as a pause, 0..1.",
        -  "type": "number"
        -}
      • addedInput schema / properties / patch / properties / pause_review / properties / threshold_db
        Added value: +{
        +  "description": "Peak level below which audio counts as a pause, dBFS.",
        +  "type": "number"
        +}
      • changedInput schema / properties / patch / properties / pause_review / required
        Previous value: -[
        -  "threshold_amp",
        -  "min_pause_us",
        -  "pad_us"
        -]New value: +[
        +  "threshold_db",
        +  "min_pause_us",
        +  "pad_us"
        +]
    • Changedset_role_flags3 fields changed
      • changedInput schema / properties / muted / description
        Previous value: -"Silence the bus. Omitted leaves it alone."New value: +"Silence the role. Omitted leaves it alone."
      • changedInput schema / properties / role / description
        Previous value: -"The mixing bus."New value: +"The audio role."
      • changedInput schema / properties / solo / description
        Previous value: -"Play this bus alone. Omitted leaves it alone."New value: +"Play this role alone. Omitted leaves it alone."
    • Changedset_role_gain2 fields changed
      • changedInput schema / properties / gain_db / description
        Previous value: -"Bus gain, dB; 0 = unity."New value: +"Role gain, dB; 0 = unity."
      • changedInput schema / properties / role / description
        Previous value: -"The mixing bus."New value: +"The audio role."
    • Removedset_scale_linked
    • Changedshift_layers8 fields changed
      • changedInput schema / properties / composition_id / description
        Previous value: -"With `from_t_us`: the composition to sweep; omit for the root."New value: +"The composition to sweep; omit for the root."
      • changedInput schema / properties / delta_us / description
        Previous value: -"Signed shift, µs; positive moves later. Not 0."New value: +"Signed shift, µs; positive opens room, negative closes the span before t_from_us. Not 0."
      • removedInput schema / properties / escape_link
        Removed value: -{
        -  "description": "With `layer_ids`: leave link partners in place. Default false.",
        -  "type": "boolean"
        -}
      • removedInput schema / properties / from_t_us
        Removed value: -{
        -  "description": "Shift every layer starting at or after this time, timeline, µs.",
        -  "type": "integer"
        -}
      • removedInput schema / properties / layer_ids
        Removed value: -{
        -  "description": "The layers to shift, all in one composition. Exactly one of this and `from_t_us`.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • addedInput schema / properties / t_from_us
        Added value: +{
        +  "description": "Shift every layer starting at or after this time, timeline, µs.",
        +  "type": "integer"
        +}
      • changedInput schema / properties / track_ids / description
        Previous value: -"With `from_t_us`: only these tracks. Omit for every track."New value: +"Only these tracks. Omit for every track."
      • changedInput schema / required
        Previous value: -[
        -  "delta_us"
        -]New value: +[
        +  "t_from_us",
        +  "delta_us"
        +]
    • Removedsmooth_keyframes
    • Changedsplit_layer3 fields changed
      • removedInput schema / properties / at_t_us
        Removed value: -{
        -  "description": "Interior timeline cuts, µs; snapped, sorted, deduplicated. Any invalid cut rejects all.",
        -  "items": {
        -    "type": "integer"
        -  },
        -  "minItems": 1,
        -  "type": "array"
        -}
      • addedInput schema / properties / t_cut_us
        Added value: +{
        +  "description": "Interior timeline cuts, µs; snapped, sorted, deduplicated. Any invalid cut rejects all.",
        +  "items": {
        +    "type": "integer"
        +  },
        +  "minItems": 1,
        +  "type": "array"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "layer_id",
        -  "at_t_us"
        -]New value: +[
        +  "layer_id",
        +  "t_cut_us"
        +]
    • Changedstart_export8 fields changed
      • changedInput schema / properties / output_path / description
        Previous value: -"Absolute candidate file path. Omit for project/output/project-name.ext; explicit parent must exist."New value: +"Absolute candidate file path in an existing folder or the project output/. Its extension must match the container (.mp4, .mov, .mkv; audio-only .m4a, Opus .mka): get_export_options reports it as extension. Omit for project/output/project-name.ext."
      • removedInput schema / properties / range / properties / end_us
        Removed value: -{
        -  "description": "Exclusive end in microseconds.",
        -  "minimum": 1,
        -  "type": "integer"
        -}
      • removedInput schema / properties / range / properties / start_us
        Removed value: -{
        -  "description": "Inclusive start in microseconds.",
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • addedInput schema / properties / range / properties / t_end_us
        Added value: +{
        +  "description": "Exclusive end, timeline µs.",
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / range / properties / t_start_us
        Added value: +{
        +  "description": "Inclusive start, timeline µs.",
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • changedInput schema / properties / range / required
        Previous value: -[
        -  "start_us",
        -  "end_us"
        -]New value: +[
        +  "t_start_us",
        +  "t_end_us"
        +]
      • changedInput schema / properties / settings / properties / encoder_engine / description
        Previous value: -"Auto selects native. MCP never prompts for or automatically switches to WebCodecs."New value: +"Auto: native, or WebCodecs without WebGL."
      • changedInput schema / properties / settings / properties / resolution_height / description
        Previous value: -"Output height in pixels, downscale only. Null follows composition; omission keeps saved setting."New value: +"Output height in pixels, downscale only. Null follows composition."
    • Changedsynthesize_speech5 fields changed
      • addedInput schema / properties / composition_id
        Added value: +{
        +  "description": "A Group's composition to place in; omit for the root.",
        +  "type": "string"
        +}
      • changedInput schema / properties / t_start_us / description
        Previous value: -"Optional timeline start in microseconds. Defaults to the composition's\ncurrent `duration_us` so the voiceover appends at the end."New value: +"Timeline start, µs. Defaults to the composition's `duration_us`, so\nthe voiceover appends at the end."
      • changedInput schema / properties / target_track_id / description
        Previous value: -"Optional Audio track id. If omitted, lands on the first existing Audio\ntrack or auto-creates one labeled \"Voiceover\"."New value: +"Track to place on. Omitted: the topmost unlocked track whose audio lane\nis free across the clip, else a new 'Voiceover' track."
      • changedInput schema / properties / voice / description
        Previous value: -"Voice identifier. tts-1 accepts: alloy, echo, fable, onyx, nova, shimmer."New value: +"The tts-1 voice."
      • addedInput schema / properties / voice / enum
        Added value: +[
        +  "alloy",
        +  "echo",
        +  "fable",
        +  "onyx",
        +  "nova",
        +  "shimmer"
        +]
    • Changedtranscribe_clip8 fields changed
      • changedInput schema / properties / backend / description
        Previous value: -"Strict engine override: `\"openai\"` | `\"whisper_cpp\"` | `\"funasr\"` |\n`\"byo_endpoint\"`. That engine serves or the call errors; nothing is\nsubstituted. Omitted: the user's preferred engine, then availability."New value: +"Strict engine override; that engine serves or the call errors.\n`openai` and `byo_endpoint` upload the audio."
      • addedInput schema / properties / backend / enum
        Added value: +[
        +  "openai",
        +  "whisper_cpp",
        +  "funasr",
        +  "byo_endpoint"
        +]
      • changedInput schema / properties / language / description
        Previous value: -"Optional ISO-639-1 language hint (`\"en\"`, `\"zh\"`). Auto-detect when omitted."New value: +"Spoken language, BCP-47 (`\"en\"`, `\"zh-CN\"`). Auto-detect when omitted."
      • removedInput schema / properties / layer_id
        Removed value: -{
        -  "description": "Target VideoClip or Audio layer id.",
        -  "type": "string"
        -}
      • addedInput schema / properties / layer_ids
        Added value: +{
        +  "description": "VideoClip or Audio layers to transcribe (1–20); one envelope each, in\nthis order. A VideoClip is read through its linked Audio member.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "maxItems": 20,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • changedInput schema / properties / t_end_us / description
        Previous value: -"Optional transcription window end in timeline microseconds.\nDefaults to the layer's `t_end_us`. Must lie within the layer."New value: +"Optional window end (exclusive), timeline µs; one layer only. Defaults\nto the layer's `t_end_us`. Must lie within the layer."
      • changedInput schema / properties / t_start_us / description
        Previous value: -"Optional transcription window start in timeline microseconds.\nDefaults to the layer's `t_start_us`. Must lie within the layer."New value: +"Optional window start, timeline µs; one layer only. Defaults to the\nlayer's `t_start_us`. Must lie within the layer."
      • changedInput schema / required
        Previous value: -[
        -  "layer_id"
        -]New value: +[
        +  "layer_ids"
        +]
    • Removedtranslate_path
    • Addedtranslate_position
    • Changedtrim_layer3 fields changed
      • removedInput schema / properties / new_t_us
        Removed value: -{
        -  "description": "Where the edge lands, timeline, µs.",
        -  "type": "integer"
        -}
      • addedInput schema / properties / t_edge_us
        Added value: +{
        +  "description": "Where the edge lands, timeline, µs.",
        +  "type": "integer"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "edge",
        -  "layer_id",
        -  "new_t_us"
        -]New value: +[
        +  "edge",
        +  "layer_id",
        +  "t_edge_us"
        +]
    • Changedupdate_effect4 fields changed
      • changedInput schema / properties / patch / description
        Previous value: -"Effect patch. Only fields you set are applied; `params` merges key-by-key, and a null value removes its key."New value: +"Effect patch; only the fields sent are applied."
      • changedInput schema / properties / patch / properties / params / additionalProperties / description
        Previous value: -"An AnimTrack — {\"mode\":\"Static\",\"value\":<number>} for a v1 param — or null to unset the key. Keyframe a visual effect param through set_keyframe instead."New value: +"A static value, or null for the catalog default."
      • changedInput schema / properties / patch / properties / params / additionalProperties / type
        Previous value: -[
        -  "object",
        -  "null"
        -]New value: +[
        +  "number",
        +  "null"
        +]
      • changedInput schema / properties / patch / properties / params / description
        Previous value: -"Param key → AnimTrack, or null to remove the key. v1 effect params are scalar, e.g. {\"strength\": {\"mode\":\"Static\",\"value\":8}}."New value: +"Param key → number, or null to unset it, e.g. {\"strength\": 8}."
    • Changedupdate_export_preset5 fields changed
      • addedInput schema / properties / default
        Added value: +{
        +  "description": "Use this preset when a project has no saved export settings. Set it on another preset to change it.",
        +  "enum": [
        +    true
        +  ],
        +  "type": "boolean"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Unique personal preset name, trimmed, at most 40 characters.",
        +  "maxLength": 40,
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / settings / description
        Previous value: -"Partial portable output settings in snake_case. Excludes engines, hardware acceleration, paths and ranges. Omitted fields retain base values."New value: +"Partial portable output settings in snake_case. Omitted fields retain base values."
      • changedInput schema / properties / settings / properties / resolution_height / description
        Previous value: -"Output height in pixels, downscale only. Null follows composition; omission keeps saved setting."New value: +"Output height in pixels, downscale only. Null follows composition."
      • changedInput schema / required
        Previous value: -[
        -  "preset_id",
        -  "settings"
        -]New value: +[
        +  "preset_id"
        +]
    • Changedupdate_keyframe4 fields changed
      • changedInput schema / properties / easing / description
        Previous value: -"Either {\"preset\":\"<id>\"} — a canonical named preset, baked to its params — or a raw kind (same forms as set_keyframe interp)."New value: +"Easing of the segment leaving the key (on the last key, the one arriving at it): {\"preset\":\"<id>\"} or a raw {\"kind\":...}. Writes this key's out/segment and the next key's in."
      • changedInput schema / properties / easing / properties / kind / description
        Previous value: -"Easing kind of the segment leaving the key."New value: +"A raw easing kind, instead of a preset."
      • changedInput schema / properties / easing / properties / preset / description
        Previous value: -"Preset id from the canonical easing table (e.g. \"ease_in_out\", \"ease_out_expo\", \"ease_in_out_bounce\")."New value: +"Preset id from the canonical easing table (e.g. \"ease_in_out\", \"ease_out_expo\"); read back in preset_ids."
      • addedInput schema / properties / smooth
        Added value: +{
        +  "const": true,
        +  "description": "Auto tangents on both sides, Smooth continuity. Only true; a side written later frees the key.",
        +  "type": "boolean"
        +}
    • Removedupdate_layer
    • Changedupdate_layer_params1 field changed
      • changedInput schema / properties / patch / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "align": {
        -        "description": "Horizontal alignment inside the box.",
        -        "enum": [
        -          "Left",
        -          "Center",
        -          "Right"
        -        ],
        -        "type": "string"
        -      },
        -      "anchor_x": {
        -        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        -        "type": "number"
        -      },
        -      "box_h": {
        -        "description": "Layout box height, composition px, local (before `scale`). null = auto height. Refused when the layer has no box_w and the patch supplies none.",
        -        "exclusiveMinimum": 0,
        -        "type": [
        -          "number",
        -          "null"
        -        ]
        -      },
        -      "box_w": {
        -        "description": "Layout box width, composition px, local (before `scale`). null = auto width.",
        -        "exclusiveMinimum": 0,
        -        "type": [
        -          "number",
        -          "null"
        -        ]
        -      },
        -      "color": {
        -        "description": "Fill colour.",
        -        "properties": {
        -          "a": {
        -            "description": "Alpha 0..255; 255 opaque.",
        -            "type": "integer"
        -          },
        -          "b": {
        -            "description": "Blue 0..255.",
        -            "type": "integer"
        -          },
        -          "g": {
        -            "description": "Green 0..255.",
        -            "type": "integer"
        -          },
        -          "r": {
        -            "description": "Red 0..255.",
        -            "type": "integer"
        -          }
        -        },
        -        "required": [
        -          "r",
        -          "g",
        -          "b",
        -          "a"
        -        ],
        -        "type": "object"
        -      },
        -      "content": {
        -        "description": "The text; newlines are honoured.",
        -        "type": "string"
        -      },
        -      "font_family": {
        -        "description": "Font family name.",
        -        "type": "string"
        -      },
        -      "font_size_px": {
        -        "description": "Font size, composition px.",
        -        "type": "number"
        -      },
        -      "font_weight": {
        -        "description": "CSS weight 100..900; 400 regular, 700 bold.",
        -        "type": "integer"
        -      },
        -      "graphic_role": {
        -        "description": "Graphic role (see add_text_layer); null clears.",
        -        "pattern": "^[a-z][a-z0-9_]{0,31}$",
        -        "type": [
        -          "string",
        -          "null"
        -        ]
        -      },
        -      "intro": {
        -        "description": "Entrance played from the layer start (400 ms, or a third of a short layer); null: none.",
        -        "enum": [
        -          "FadeIn",
        -          "SlideUp",
        -          "SlideDown",
        -          "Typewriter",
        -          null
        -        ],
        -        "type": [
        -          "string",
        -          "null"
        -        ]
        -      },
        -      "italic": {
        -        "description": "Italic face.",
        -        "type": "boolean"
        -      },
        -      "kind": {
        -        "const": "Text",
        -        "description": "Fields of a Text layer."
        -      },
        -      "letter_spacing": {
        -        "description": "Letter spacing, px.",
        -        "type": "number"
        -      },
        -      "line_height": {
        -        "description": "Line height, px; 0 = the font metrics.",
        -        "type": "number"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "outline_color": {
        -        "description": "Stroke colour.",
        -        "properties": {
        -          "a": {
        -            "description": "Alpha 0..255; 255 opaque.",
        -            "type": "integer"
        -          },
        -          "b": {
        -            "description": "Blue 0..255.",
        -            "type": "integer"
        -          },
        -          "g": {
        -            "description": "Green 0..255.",
        -            "type": "integer"
        -          },
        -          "r": {
        -            "description": "Red 0..255.",
        -            "type": "integer"
        -          }
        -        },
        -        "required": [
        -          "r",
        -          "g",
        -          "b",
        -          "a"
        -        ],
        -        "type": "object"
        -      },
        -      "outline_width": {
        -        "description": "Stroke width, composition px; 0 removes the outline.",
        -        "type": "number"
        -      },
        -      "outro": {
        -        "description": "Exit played into the layer end; null: none.",
        -        "enum": [
        -          "FadeOut",
        -          "SlideUp",
        -          "SlideDown",
        -          null
        -        ],
        -        "type": [
        -          "string",
        -          "null"
        -        ]
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "shadow": {
        -        "description": "Drop shadow, or null for none.",
        -        "properties": {
        -          "blur": {
        -            "description": "Blur radius, composition px; 0 is hard-edged.",
        -            "minimum": 0,
        -            "type": "number"
        -          },
        -          "color": {
        -            "description": "Shadow colour.",
        -            "properties": {
        -              "a": {
        -                "description": "Alpha 0..255; 255 opaque.",
        -                "type": "integer"
        -              },
        -              "b": {
        -                "description": "Blue 0..255.",
        -                "type": "integer"
        -              },
        -              "g": {
        -                "description": "Green 0..255.",
        -                "type": "integer"
        -              },
        -              "r": {
        -                "description": "Red 0..255.",
        -                "type": "integer"
        -              }
        -            },
        -            "required": [
        -              "r",
        -              "g",
        -              "b",
        -              "a"
        -            ],
        -            "type": "object"
        -          },
        -          "offset_x": {
        -            "description": "Horizontal offset, composition px.",
        -            "type": "number"
        -          },
        -          "offset_y": {
        -            "description": "Vertical offset, composition px.",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "color",
        -          "offset_x",
        -          "offset_y",
        -          "blur"
        -        ],
        -        "type": [
        -          "object",
        -          "null"
        -        ]
        -      },
        -      "valign": {
        -        "description": "Vertical alignment inside the box.",
        -        "enum": [
        -          "Top",
        -          "Middle",
        -          "Bottom"
        -        ],
        -        "type": "string"
        -      },
        -      "x": {
        -        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: set_position / translate_path.",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "The anchor point's y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        -        "type": "number"
        -      },
        -      "crop": {
        -        "additionalProperties": false,
        -        "description": "Static retained source rectangle in normalized 0..1 coordinates, before transform. x/y are top-left; w/h positive, contained in source. Null resets. Does not change scale or position.",
        -        "properties": {
        -          "h": {
        -            "description": "Height.",
        -            "exclusiveMinimum": 0,
        -            "maximum": 1,
        -            "type": "number"
        -          },
        -          "w": {
        -            "description": "Width.",
        -            "exclusiveMinimum": 0,
        -            "maximum": 1,
        -            "type": "number"
        -          },
        -          "x": {
        -            "description": "Left.",
        -            "maximum": 1,
        -            "minimum": 0,
        -            "type": "number"
        -          },
        -          "y": {
        -            "description": "Top.",
        -            "maximum": 1,
        -            "minimum": 0,
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "x",
        -          "y",
        -          "w",
        -          "h"
        -        ],
        -        "type": [
        -          "object",
        -          "null"
        -        ]
        -      },
        -      "fade_in_us": {
        -        "description": "Fade-in length, µs.",
        -        "type": "integer"
        -      },
        -      "fade_out_us": {
        -        "description": "Fade-out length, µs.",
        -        "type": "integer"
        -      },
        -      "flip_h": {
        -        "description": "Mirror horizontally.",
        -        "type": "boolean"
        -      },
        -      "flip_v": {
        -        "description": "Mirror vertically.",
        -        "type": "boolean"
        -      },
        -      "kind": {
        -        "const": "VideoClip",
        -        "description": "Fields of a VideoClip layer."
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "src_out_us": {
        -        "description": "Source out point (exclusive), µs.",
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: set_position / translate_path.",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "The anchor point's y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        -        "type": "number"
        -      },
        -      "fade_in_us": {
        -        "description": "Fade-in length, µs.",
        -        "type": "integer"
        -      },
        -      "fade_out_us": {
        -        "description": "Fade-out length, µs.",
        -        "type": "integer"
        -      },
        -      "graphic_role": {
        -        "description": "Graphic role (see add_text_layer); null clears.",
        -        "pattern": "^[a-z][a-z0-9_]{0,31}$",
        -        "type": [
        -          "string",
        -          "null"
        -        ]
        -      },
        -      "kind": {
        -        "const": "ImageOverlay",
        -        "description": "Fields of a ImageOverlay layer."
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "x": {
        -        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: set_position / translate_path.",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "The anchor point's y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        -        "type": "number"
        -      },
        -      "graphic_role": {
        -        "description": "Graphic role (see add_text_layer); null clears.",
        -        "pattern": "^[a-z][a-z0-9_]{0,31}$",
        -        "type": [
        -          "string",
        -          "null"
        -        ]
        -      },
        -      "kind": {
        -        "const": "Motif",
        -        "description": "Fields of a Motif layer."
        -      },
        -      "motif_id": {
        -        "description": "Motif id from list_motifs.",
        -        "type": "string"
        -      },
        -      "motif_version": {
        -        "description": "Motif version to bind.",
        -        "type": "integer"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "props": {
        -        "description": "Motif props, matched against its props_schema.",
        -        "type": "object"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: set_position / translate_path.",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "The anchor point's y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "color": {
        -        "description": "Fill colour.",
        -        "properties": {
        -          "a": {
        -            "description": "Alpha 0..255; 255 opaque.",
        -            "type": "integer"
        -          },
        -          "b": {
        -            "description": "Blue 0..255.",
        -            "type": "integer"
        -          },
        -          "g": {
        -            "description": "Green 0..255.",
        -            "type": "integer"
        -          },
        -          "r": {
        -            "description": "Red 0..255.",
        -            "type": "integer"
        -          }
        -        },
        -        "required": [
        -          "r",
        -          "g",
        -          "b",
        -          "a"
        -        ],
        -        "type": "object"
        -      },
        -      "height": {
        -        "description": "Colour block height, px.",
        -        "type": "integer"
        -      },
        -      "kind": {
        -        "const": "Color",
        -        "description": "Fields of a Color layer."
        -      },
        -      "width": {
        -        "description": "Colour block width, px.",
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "fade_in_us": {
        -        "description": "Fade-in length, µs.",
        -        "type": "integer"
        -      },
        -      "fade_out_us": {
        -        "description": "Fade-out length, µs.",
        -        "type": "integer"
        -      },
        -      "gain_db": {
        -        "description": "Gain, dB; written Static, replacing any keyframes.",
        -        "type": "number"
        -      },
        -      "kind": {
        -        "const": "Audio",
        -        "description": "Fields of a Audio layer."
        -      },
        -      "mute": {
        -        "description": "Silence the clip.",
        -        "type": "boolean"
        -      },
        -      "pan": {
        -        "description": "Stereo pan, -1 (left) .. 1 (right); written Static.",
        -        "type": "number"
        -      },
        -      "role": {
        -        "description": "Mixing bus.",
        -        "enum": [
        -          "dialogue",
        -          "music",
        -          "sfx",
        -          "voiceover"
        -        ],
        -        "type": "string"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "src_out_us": {
        -        "description": "Source out point (exclusive), µs.",
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        -        "type": "number"
        -      },
        -      "blend_mode": {
        -        "description": "How the Group composites over what lies below.",
        -        "enum": [
        -          "Normal",
        -          "Multiply",
        -          "Screen",
        -          "Overlay",
        -          "Darken",
        -          "Lighten",
        -          "Add",
        -          "Difference"
        -        ],
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "CompositionRef",
        -        "description": "Fields of a CompositionRef layer."
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "src_out_us": {
        -        "description": "Source out point (exclusive), µs.",
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: set_position / translate_path.",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "The anchor point's y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "align": {
        +        "description": "Horizontal alignment inside the box.",
        +        "enum": [
        +          "Left",
        +          "Center",
        +          "Right"
        +        ],
        +        "type": "string"
        +      },
        +      "anchor_x": {
        +        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        +        "type": "number"
        +      },
        +      "box_h": {
        +        "description": "Layout box height, composition px, local (before `scale`). null = auto height. Refused when the layer has no box_w and the patch supplies none.",
        +        "exclusiveMinimum": 0,
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "box_w": {
        +        "description": "Layout box width, composition px, local (before `scale`). null = auto width.",
        +        "exclusiveMinimum": 0,
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "color": {
        +        "description": "Fill colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "content": {
        +        "description": "The text; newlines are honoured.",
        +        "type": "string"
        +      },
        +      "font_family": {
        +        "description": "Font family name.",
        +        "type": "string"
        +      },
        +      "font_size_px": {
        +        "description": "Font size, composition px.",
        +        "type": "number"
        +      },
        +      "font_weight": {
        +        "description": "CSS weight 100..900; 400 regular, 700 bold.",
        +        "type": "integer"
        +      },
        +      "graphic_role": {
        +        "description": "Graphic role; null clears.",
        +        "pattern": "^[a-z][a-z0-9_]{0,31}$",
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "intro": {
        +        "description": "Entrance played from the layer start (400 ms, or a third of a short layer); null: none.",
        +        "enum": [
        +          "FadeIn",
        +          "SlideUp",
        +          "SlideDown",
        +          "Typewriter",
        +          null
        +        ],
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "italic": {
        +        "description": "Italic face.",
        +        "type": "boolean"
        +      },
        +      "kind": {
        +        "const": "Text",
        +        "description": "Fields of a Text layer."
        +      },
        +      "letter_spacing": {
        +        "description": "Letter spacing, px.",
        +        "type": "number"
        +      },
        +      "line_height": {
        +        "description": "Line height, px; 0 = the font metrics.",
        +        "type": "number"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "outline_color": {
        +        "description": "Stroke colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "outline_width": {
        +        "description": "Stroke width, composition px; 0 removes the outline.",
        +        "type": "number"
        +      },
        +      "outro": {
        +        "description": "Exit played into the layer end; null: none.",
        +        "enum": [
        +          "FadeOut",
        +          "SlideUp",
        +          "SlideDown",
        +          null
        +        ],
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "shadow": {
        +        "description": "Drop shadow, or null for none.",
        +        "properties": {
        +          "blur": {
        +            "description": "Blur radius, composition px; 0 is hard-edged.",
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "color": {
        +            "description": "Shadow colour.",
        +            "properties": {
        +              "a": {
        +                "description": "Alpha 0..255; 255 opaque.",
        +                "type": "integer"
        +              },
        +              "b": {
        +                "description": "Blue 0..255.",
        +                "type": "integer"
        +              },
        +              "g": {
        +                "description": "Green 0..255.",
        +                "type": "integer"
        +              },
        +              "r": {
        +                "description": "Red 0..255.",
        +                "type": "integer"
        +              }
        +            },
        +            "required": [
        +              "r",
        +              "g",
        +              "b",
        +              "a"
        +            ],
        +            "type": "object"
        +          },
        +          "offset_x": {
        +            "description": "Horizontal offset, composition px.",
        +            "type": "number"
        +          },
        +          "offset_y": {
        +            "description": "Vertical offset, composition px.",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "color",
        +          "offset_x",
        +          "offset_y",
        +          "blur"
        +        ],
        +        "type": [
        +          "object",
        +          "null"
        +        ]
        +      },
        +      "valign": {
        +        "description": "Vertical alignment inside the box.",
        +        "enum": [
        +          "Top",
        +          "Middle",
        +          "Bottom"
        +        ],
        +        "type": "string"
        +      },
        +      "x": {
        +        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: translate_position / set_position.",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "The anchor point's y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        +        "type": "number"
        +      },
        +      "crop": {
        +        "additionalProperties": false,
        +        "description": "Static retained source rectangle in normalized 0..1 coordinates, before transform. x/y are top-left; w/h positive, contained in source. Null resets. Does not change scale or position.",
        +        "properties": {
        +          "h": {
        +            "description": "Height.",
        +            "exclusiveMinimum": 0,
        +            "maximum": 1,
        +            "type": "number"
        +          },
        +          "w": {
        +            "description": "Width.",
        +            "exclusiveMinimum": 0,
        +            "maximum": 1,
        +            "type": "number"
        +          },
        +          "x": {
        +            "description": "Left.",
        +            "maximum": 1,
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "y": {
        +            "description": "Top.",
        +            "maximum": 1,
        +            "minimum": 0,
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "x",
        +          "y",
        +          "w",
        +          "h"
        +        ],
        +        "type": [
        +          "object",
        +          "null"
        +        ]
        +      },
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "flip_h": {
        +        "description": "Mirror horizontally.",
        +        "type": "boolean"
        +      },
        +      "flip_v": {
        +        "description": "Mirror vertically.",
        +        "type": "boolean"
        +      },
        +      "kind": {
        +        "const": "VideoClip",
        +        "description": "Fields of a VideoClip layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_linked": {
        +        "description": "After the scale fields: true links the pair, copying the scale_x track onto scale_y (destructive to an animated scale_y); false unlinks.",
        +        "type": "boolean"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs — a slip: the window moves and keeps its length, so the span is unchanged. Its end follows; change the length with trim_layer.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: translate_position / set_position.",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "The anchor point's y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        +        "type": "number"
        +      },
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "graphic_role": {
        +        "description": "Graphic role; null clears.",
        +        "pattern": "^[a-z][a-z0-9_]{0,31}$",
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "kind": {
        +        "const": "ImageOverlay",
        +        "description": "Fields of a ImageOverlay layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_linked": {
        +        "description": "After the scale fields: true links the pair, copying the scale_x track onto scale_y (destructive to an animated scale_y); false unlinks.",
        +        "type": "boolean"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "x": {
        +        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: translate_position / set_position.",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "The anchor point's y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        +        "type": "number"
        +      },
        +      "graphic_role": {
        +        "description": "Graphic role; null clears.",
        +        "pattern": "^[a-z][a-z0-9_]{0,31}$",
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "kind": {
        +        "const": "Motif",
        +        "description": "Fields of a Motif layer."
        +      },
        +      "motif_id": {
        +        "description": "Motif id from list_motifs.",
        +        "type": "string"
        +      },
        +      "motif_version": {
        +        "description": "Motif version to bind.",
        +        "type": "integer"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "props": {
        +        "description": "Motif props, matched against its props_schema.",
        +        "type": "object"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_linked": {
        +        "description": "After the scale fields: true links the pair, copying the scale_x track onto scale_y (destructive to an animated scale_y); false unlinks.",
        +        "type": "boolean"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs — a slip: the window moves and keeps its length, so the span is unchanged. Its end follows; change the length with trim_layer.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: translate_position / set_position.",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "The anchor point's y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "color": {
        +        "description": "Fill colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "height": {
        +        "description": "Colour block height, px.",
        +        "type": "integer"
        +      },
        +      "kind": {
        +        "const": "Color",
        +        "description": "Fields of a Color layer."
        +      },
        +      "width": {
        +        "description": "Colour block width, px.",
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "gain_db": {
        +        "description": "Gain, dB; written Static, replacing any keyframes.",
        +        "type": "number"
        +      },
        +      "kind": {
        +        "const": "Audio",
        +        "description": "Fields of a Audio layer."
        +      },
        +      "mute": {
        +        "description": "Silence the clip.",
        +        "type": "boolean"
        +      },
        +      "pan": {
        +        "description": "Stereo pan, -1 (left) .. 1 (right); written Static.",
        +        "type": "number"
        +      },
        +      "role": {
        +        "description": "Audio role, whose gain and flags fold into the mix.",
        +        "enum": [
        +          "dialogue",
        +          "music",
        +          "sfx",
        +          "voiceover"
        +        ],
        +        "type": "string"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs — a slip: the window moves and keeps its length, so the span is unchanged. Its end follows; change the length with trim_layer.",
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        +        "type": "number"
        +      },
        +      "kind": {
        +        "const": "CompositionRef",
        +        "description": "Fields of a CompositionRef layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_linked": {
        +        "description": "After the scale fields: true links the pair, copying the scale_x track onto scale_y (destructive to an animated scale_y); false unlinks.",
        +        "type": "boolean"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs — a slip: the window moves and keeps its length, so the span is unchanged. Its end follows; change the length with trim_layer.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: translate_position / set_position.",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "The anchor point's y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  }
        +]
    • Changedupdate_marker5 fields changed
      • changedInput schema / properties / patch / description
        Previous value: -"Marker patch; only fields you set apply. `end_t_us` can be set, never cleared (remove + re-add). The anchor is `set_marker_anchor`'s, not patchable here."New value: +"Marker patch; only fields you set apply. The anchor is `set_marker_anchor`'s, not patchable here."
      • removedInput schema / properties / patch / properties / end_t_us
        Removed value: -{
        -  "description": "Region end, timeline; turns a point marker into a region, µs.",
        -  "type": "integer"
        -}
      • changedInput schema / properties / patch / properties / label / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • changedInput schema / properties / patch / properties / note / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • addedInput schema / properties / patch / properties / t_end_us
        Added value: +{
        +  "description": "Region end, timeline µs (exclusive); a point marker becomes a region. null turns a region back into a point.",
        +  "type": [
        +    "integer",
        +    "null"
        +  ]
        +}
    • Changedupdate_motif_files4 fields changed
      • removedInput schema / properties / draft_id
        Removed value: -{
        -  "description": "Editable draft id.",
        -  "type": "string"
        -}
      • changedInput schema / properties / files / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "path": {
        -        "description": "Path relative to the Motif root.",
        -        "type": "string"
        -      },
        -      "text": {
        -        "description": "Complete UTF-8 file contents.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "path",
        -      "text"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "file_id": {
        -        "description": "Temporary file transfer id.",
        -        "type": "string"
        -      },
        -      "path": {
        -        "description": "Path relative to the Motif root.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "path",
        -      "file_id"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "edits": {
        -        "description": "Replacements applied in order to the current UTF-8 file.",
        -        "items": {
        -          "additionalProperties": false,
        -          "properties": {
        -            "new": {
        -              "description": "Replacement text.",
        -              "type": "string"
        -            },
        -            "old": {
        -              "description": "Exact text to replace; must occur exactly once in the file.",
        -              "minLength": 1,
        -              "type": "string"
        -            }
        -          },
        -          "required": [
        -            "old",
        -            "new"
        -          ],
        -          "type": "object"
        -        },
        -        "minItems": 1,
        -        "type": "array"
        -      },
        -      "path": {
        -        "description": "Path relative to the Motif root.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "path",
        -      "edits"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "delete": {
        -        "const": true,
        -        "description": "Remove this file."
        -      },
        -      "path": {
        -        "description": "Path relative to the Motif root.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "path",
        -      "delete"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "path": {
        +        "description": "Path relative to the Motif root.",
        +        "type": "string"
        +      },
        +      "text": {
        +        "description": "Complete UTF-8 file contents.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "path",
        +      "text"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "base64": {
        +        "description": "Canonical base64 of the whole file, at most 256 KiB decoded.",
        +        "type": "string"
        +      },
        +      "path": {
        +        "description": "Path relative to the Motif root.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "path",
        +      "base64"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "edits": {
        +        "description": "Replacements applied in order to the current UTF-8 file.",
        +        "items": {
        +          "additionalProperties": false,
        +          "properties": {
        +            "new": {
        +              "description": "Replacement text.",
        +              "type": "string"
        +            },
        +            "old": {
        +              "description": "Exact text to replace; must occur exactly once in the file.",
        +              "minLength": 1,
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "old",
        +            "new"
        +          ],
        +          "type": "object"
        +        },
        +        "minItems": 1,
        +        "type": "array"
        +      },
        +      "path": {
        +        "description": "Path relative to the Motif root.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "path",
        +      "edits"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "delete": {
        +        "const": true,
        +        "description": "Remove this file."
        +      },
        +      "path": {
        +        "description": "Path relative to the Motif root.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "path",
        +      "delete"
        +    ],
        +    "type": "object"
        +  }
        +]
      • addedInput schema / properties / motif_id
        Added value: +{
        +  "description": "Motif id (list_motifs).",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "draft_id",
        -  "expected_revision",
        -  "files"
        -]New value: +[
        +  "motif_id",
        +  "expected_revision",
        +  "files"
        +]
    • Removedwrite_file_chunk
  2. 4 tool updatesv0.5.5
    • Changeddescribe_clip2 fields changed
      • changedInput schema / properties / fps / description
        Previous value: -"Frames sampled per second (higher = finer, costlier; capped to the\nmodel's context). Default: the app's setting, else 1.0. Cache key."New value: +"Frames sampled per second (higher = finer, more requests). Default:\nthe app's setting, else 1.0. Cache key."
      • addedInput schema / properties / refresh
        Added value: +{
        +  "default": false,
        +  "description": "Describe again even when cached, replacing the earlier run (default\nfalse).",
        +  "type": "boolean"
        +}
    • Changedimport_media1 field changed
      • changedInput schema / properties / path / description
        Previous value: -"Absolute path to a video / audio / image / subtitle file the host can read."New value: +"Path to a video / audio / image / subtitle file the host can read: absolute, or relative to the open project's folder."
    • Changedread_project1 field changed
      • changedInput schema / properties / id / description
        Previous value: -"The layer id for view `layer`; the media id for `media_thumbnail` / `media_frame`."New value: +"The layer id for view `layer`; the media id for `media` (optional) / `media_thumbnail` / `media_frame`."
    • Changedtranscribe_clip1 field changed
      • changedInput schema / properties / backend / description
        Previous value: -"Strict engine override: `\"openai\"` | `\"whisper_cpp\"` | `\"funasr\"`.\nThat engine serves or the call errors; nothing is substituted. Omitted:\nthe user's preferred engine, then availability."New value: +"Strict engine override: `\"openai\"` | `\"whisper_cpp\"` | `\"funasr\"` |\n`\"byo_endpoint\"`. That engine serves or the call errors; nothing is\nsubstituted. Omitted: the user's preferred engine, then availability."
  3. 10 tool updatesv0.5.4
    • Changedadd_motif_layer2 fields changed
      • addedInput schema / properties / graphic_role
        Added value: +{
        +  "description": "What the layer is for: title, lower_third, callout, credit, logo, plate, illustration, none, or a custom name. Omitted: the manifest's; null: none.",
        +  "pattern": "^[a-z][a-z0-9_]{0,31}$",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • changedInput schema / properties / motif_id / description
        Previous value: -"Motif id from `list_motifs` (built-ins: \"countdown\", \"lower-third\", \"text-fx\")."New value: +"Motif id from `list_motifs` (built-ins: \"countdown\", \"lower-third\", \"text-fx\"; a style's role Motifs: `project://taste` → motifs)."
    • Changedadd_text_layer1 field changed
      • addedInput schema / properties / graphic_role
        Added value: +{
        +  "description": "What the layer is for: title, lower_third, callout, credit, logo, plate, illustration, none, or a custom name.",
        +  "pattern": "^[a-z][a-z0-9_]{0,31}$",
        +  "type": "string"
        +}
    • Changedadd_video_layer1 field changed
      • addedInput schema / properties / graphic_role
        Added value: +{
        +  "description": "What the layer is for: title, lower_third, callout, credit, logo, plate, illustration, none, or a custom name. Image only.",
        +  "pattern": "^[a-z][a-z0-9_]{0,31}$",
        +  "type": "string"
        +}
    • Addedcheck_composition
    • Changedpreview_motif2 fields changed
      • changedInput schema / properties / height / description
        Previous value: -"Capture height in pixels."New value: +"Maximum image height in pixels; the whole frame is scaled to fit."
      • changedInput schema / properties / width / description
        Previous value: -"Capture width in pixels."New value: +"Maximum image width in pixels; the whole frame is scaled to fit."
    • Changedread_project1 field changed
      • changedInput schema / properties / view / enum
        Previous value: -[
        -  "current",
        -  "composition",
        -  "compositions",
        -  "media",
        -  "tracks",
        -  "layer",
        -  "markers",
        -  "links",
        -  "transitions",
        -  "settings",
        -  "history",
        -  "session",
        -  "effects",
        -  "tacks",
        -  "media_thumbnail",
        -  "media_frame"
        -]New value: +[
        +  "current",
        +  "composition",
        +  "compositions",
        +  "media",
        +  "tracks",
        +  "layer",
        +  "markers",
        +  "links",
        +  "transitions",
        +  "settings",
        +  "history",
        +  "session",
        +  "effects",
        +  "tacks",
        +  "taste",
        +  "media_thumbnail",
        +  "media_frame"
        +]
    • Addedrender_frames
    • Addedrestyle_to_taste
    • Changedupdate_layer_params1 field changed
      • changedInput schema / properties / patch / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "align": {
        -        "description": "Horizontal alignment inside the box.",
        -        "enum": [
        -          "Left",
        -          "Center",
        -          "Right"
        -        ],
        -        "type": "string"
        -      },
        -      "anchor_x": {
        -        "description": "Pivot x, fraction of the width (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Pivot y, fraction of the height (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "box_h": {
        -        "description": "Layout box height, composition px, local (before `scale`). null = auto height. Refused when the layer has no box_w and the patch supplies none.",
        -        "exclusiveMinimum": 0,
        -        "type": [
        -          "number",
        -          "null"
        -        ]
        -      },
        -      "box_w": {
        -        "description": "Layout box width, composition px, local (before `scale`). null = auto width.",
        -        "exclusiveMinimum": 0,
        -        "type": [
        -          "number",
        -          "null"
        -        ]
        -      },
        -      "color": {
        -        "description": "Fill colour.",
        -        "properties": {
        -          "a": {
        -            "description": "Alpha 0..255; 255 opaque.",
        -            "type": "integer"
        -          },
        -          "b": {
        -            "description": "Blue 0..255.",
        -            "type": "integer"
        -          },
        -          "g": {
        -            "description": "Green 0..255.",
        -            "type": "integer"
        -          },
        -          "r": {
        -            "description": "Red 0..255.",
        -            "type": "integer"
        -          }
        -        },
        -        "required": [
        -          "r",
        -          "g",
        -          "b",
        -          "a"
        -        ],
        -        "type": "object"
        -      },
        -      "content": {
        -        "description": "The text; newlines are honoured.",
        -        "type": "string"
        -      },
        -      "font_family": {
        -        "description": "Font family name.",
        -        "type": "string"
        -      },
        -      "font_size_px": {
        -        "description": "Font size, composition px.",
        -        "type": "number"
        -      },
        -      "font_weight": {
        -        "description": "CSS weight 100..900; 400 regular, 700 bold.",
        -        "type": "integer"
        -      },
        -      "italic": {
        -        "description": "Italic face.",
        -        "type": "boolean"
        -      },
        -      "kind": {
        -        "const": "Text",
        -        "description": "Fields of a Text layer."
        -      },
        -      "letter_spacing": {
        -        "description": "Letter spacing, px.",
        -        "type": "number"
        -      },
        -      "line_height": {
        -        "description": "Line height, px; 0 = the font metrics.",
        -        "type": "number"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "outline_color": {
        -        "description": "Stroke colour.",
        -        "properties": {
        -          "a": {
        -            "description": "Alpha 0..255; 255 opaque.",
        -            "type": "integer"
        -          },
        -          "b": {
        -            "description": "Blue 0..255.",
        -            "type": "integer"
        -          },
        -          "g": {
        -            "description": "Green 0..255.",
        -            "type": "integer"
        -          },
        -          "r": {
        -            "description": "Red 0..255.",
        -            "type": "integer"
        -          }
        -        },
        -        "required": [
        -          "r",
        -          "g",
        -          "b",
        -          "a"
        -        ],
        -        "type": "object"
        -      },
        -      "outline_width": {
        -        "description": "Stroke width, composition px; 0 removes the outline.",
        -        "type": "number"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "shadow": {
        -        "description": "Drop shadow, or null for none.",
        -        "properties": {
        -          "blur": {
        -            "description": "Blur radius, composition px; 0 is hard-edged.",
        -            "minimum": 0,
        -            "type": "number"
        -          },
        -          "color": {
        -            "description": "Shadow colour.",
        -            "properties": {
        -              "a": {
        -                "description": "Alpha 0..255; 255 opaque.",
        -                "type": "integer"
        -              },
        -              "b": {
        -                "description": "Blue 0..255.",
        -                "type": "integer"
        -              },
        -              "g": {
        -                "description": "Green 0..255.",
        -                "type": "integer"
        -              },
        -              "r": {
        -                "description": "Red 0..255.",
        -                "type": "integer"
        -              }
        -            },
        -            "required": [
        -              "r",
        -              "g",
        -              "b",
        -              "a"
        -            ],
        -            "type": "object"
        -          },
        -          "offset_x": {
        -            "description": "Horizontal offset, composition px.",
        -            "type": "number"
        -          },
        -          "offset_y": {
        -            "description": "Vertical offset, composition px.",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "color",
        -          "offset_x",
        -          "offset_y",
        -          "blur"
        -        ],
        -        "type": [
        -          "object",
        -          "null"
        -        ]
        -      },
        -      "valign": {
        -        "description": "Vertical alignment inside the box.",
        -        "enum": [
        -          "Top",
        -          "Middle",
        -          "Bottom"
        -        ],
        -        "type": "string"
        -      },
        -      "x": {
        -        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "Anchor y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Pivot x, fraction of the width (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Pivot y, fraction of the height (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "crop": {
        -        "additionalProperties": false,
        -        "description": "Static retained source rectangle in normalized 0..1 coordinates, before transform. x/y are top-left; w/h positive, contained in source. Null resets. Does not change scale or position.",
        -        "properties": {
        -          "h": {
        -            "description": "Height.",
        -            "exclusiveMinimum": 0,
        -            "maximum": 1,
        -            "type": "number"
        -          },
        -          "w": {
        -            "description": "Width.",
        -            "exclusiveMinimum": 0,
        -            "maximum": 1,
        -            "type": "number"
        -          },
        -          "x": {
        -            "description": "Left.",
        -            "maximum": 1,
        -            "minimum": 0,
        -            "type": "number"
        -          },
        -          "y": {
        -            "description": "Top.",
        -            "maximum": 1,
        -            "minimum": 0,
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "x",
        -          "y",
        -          "w",
        -          "h"
        -        ],
        -        "type": [
        -          "object",
        -          "null"
        -        ]
        -      },
        -      "fade_in_us": {
        -        "description": "Fade-in length, µs.",
        -        "type": "integer"
        -      },
        -      "fade_out_us": {
        -        "description": "Fade-out length, µs.",
        -        "type": "integer"
        -      },
        -      "flip_h": {
        -        "description": "Mirror horizontally.",
        -        "type": "boolean"
        -      },
        -      "flip_v": {
        -        "description": "Mirror vertically.",
        -        "type": "boolean"
        -      },
        -      "kind": {
        -        "const": "VideoClip",
        -        "description": "Fields of a VideoClip layer."
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "src_out_us": {
        -        "description": "Source out point (exclusive), µs.",
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "Anchor y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Pivot x, fraction of the width (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Pivot y, fraction of the height (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "fade_in_us": {
        -        "description": "Fade-in length, µs.",
        -        "type": "integer"
        -      },
        -      "fade_out_us": {
        -        "description": "Fade-out length, µs.",
        -        "type": "integer"
        -      },
        -      "kind": {
        -        "const": "ImageOverlay",
        -        "description": "Fields of a ImageOverlay layer."
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "x": {
        -        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "Anchor y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Pivot x, fraction of the width (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Pivot y, fraction of the height (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "kind": {
        -        "const": "Motif",
        -        "description": "Fields of a Motif layer."
        -      },
        -      "motif_id": {
        -        "description": "Motif id from list_motifs.",
        -        "type": "string"
        -      },
        -      "motif_version": {
        -        "description": "Motif version to bind.",
        -        "type": "integer"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "props": {
        -        "description": "Motif props, matched against its props_schema.",
        -        "type": "object"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "Anchor y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "color": {
        -        "description": "Fill colour.",
        -        "properties": {
        -          "a": {
        -            "description": "Alpha 0..255; 255 opaque.",
        -            "type": "integer"
        -          },
        -          "b": {
        -            "description": "Blue 0..255.",
        -            "type": "integer"
        -          },
        -          "g": {
        -            "description": "Green 0..255.",
        -            "type": "integer"
        -          },
        -          "r": {
        -            "description": "Red 0..255.",
        -            "type": "integer"
        -          }
        -        },
        -        "required": [
        -          "r",
        -          "g",
        -          "b",
        -          "a"
        -        ],
        -        "type": "object"
        -      },
        -      "height": {
        -        "description": "Colour block height, px.",
        -        "type": "integer"
        -      },
        -      "kind": {
        -        "const": "Color",
        -        "description": "Fields of a Color layer."
        -      },
        -      "width": {
        -        "description": "Colour block width, px.",
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "fade_in_us": {
        -        "description": "Fade-in length, µs.",
        -        "type": "integer"
        -      },
        -      "fade_out_us": {
        -        "description": "Fade-out length, µs.",
        -        "type": "integer"
        -      },
        -      "gain_db": {
        -        "description": "Gain, dB; written Static, replacing any keyframes.",
        -        "type": "number"
        -      },
        -      "kind": {
        -        "const": "Audio",
        -        "description": "Fields of a Audio layer."
        -      },
        -      "mute": {
        -        "description": "Silence the clip.",
        -        "type": "boolean"
        -      },
        -      "pan": {
        -        "description": "Stereo pan, -1 (left) .. 1 (right); written Static.",
        -        "type": "number"
        -      },
        -      "role": {
        -        "description": "Mixing bus.",
        -        "enum": [
        -          "dialogue",
        -          "music",
        -          "sfx",
        -          "voiceover"
        -        ],
        -        "type": "string"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "src_out_us": {
        -        "description": "Source out point (exclusive), µs.",
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Pivot x, fraction of the width (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Pivot y, fraction of the height (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "blend_mode": {
        -        "description": "How the Group composites over what lies below.",
        -        "enum": [
        -          "Normal",
        -          "Multiply",
        -          "Screen",
        -          "Overlay",
        -          "Darken",
        -          "Lighten",
        -          "Add",
        -          "Difference"
        -        ],
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "CompositionRef",
        -        "description": "Fields of a CompositionRef layer."
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "src_out_us": {
        -        "description": "Source out point (exclusive), µs.",
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "Anchor y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "align": {
        +        "description": "Horizontal alignment inside the box.",
        +        "enum": [
        +          "Left",
        +          "Center",
        +          "Right"
        +        ],
        +        "type": "string"
        +      },
        +      "anchor_x": {
        +        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        +        "type": "number"
        +      },
        +      "box_h": {
        +        "description": "Layout box height, composition px, local (before `scale`). null = auto height. Refused when the layer has no box_w and the patch supplies none.",
        +        "exclusiveMinimum": 0,
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "box_w": {
        +        "description": "Layout box width, composition px, local (before `scale`). null = auto width.",
        +        "exclusiveMinimum": 0,
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "color": {
        +        "description": "Fill colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "content": {
        +        "description": "The text; newlines are honoured.",
        +        "type": "string"
        +      },
        +      "font_family": {
        +        "description": "Font family name.",
        +        "type": "string"
        +      },
        +      "font_size_px": {
        +        "description": "Font size, composition px.",
        +        "type": "number"
        +      },
        +      "font_weight": {
        +        "description": "CSS weight 100..900; 400 regular, 700 bold.",
        +        "type": "integer"
        +      },
        +      "graphic_role": {
        +        "description": "Graphic role (see add_text_layer); null clears.",
        +        "pattern": "^[a-z][a-z0-9_]{0,31}$",
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "intro": {
        +        "description": "Entrance played from the layer start (400 ms, or a third of a short layer); null: none.",
        +        "enum": [
        +          "FadeIn",
        +          "SlideUp",
        +          "SlideDown",
        +          "Typewriter",
        +          null
        +        ],
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "italic": {
        +        "description": "Italic face.",
        +        "type": "boolean"
        +      },
        +      "kind": {
        +        "const": "Text",
        +        "description": "Fields of a Text layer."
        +      },
        +      "letter_spacing": {
        +        "description": "Letter spacing, px.",
        +        "type": "number"
        +      },
        +      "line_height": {
        +        "description": "Line height, px; 0 = the font metrics.",
        +        "type": "number"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "outline_color": {
        +        "description": "Stroke colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "outline_width": {
        +        "description": "Stroke width, composition px; 0 removes the outline.",
        +        "type": "number"
        +      },
        +      "outro": {
        +        "description": "Exit played into the layer end; null: none.",
        +        "enum": [
        +          "FadeOut",
        +          "SlideUp",
        +          "SlideDown",
        +          null
        +        ],
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "shadow": {
        +        "description": "Drop shadow, or null for none.",
        +        "properties": {
        +          "blur": {
        +            "description": "Blur radius, composition px; 0 is hard-edged.",
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "color": {
        +            "description": "Shadow colour.",
        +            "properties": {
        +              "a": {
        +                "description": "Alpha 0..255; 255 opaque.",
        +                "type": "integer"
        +              },
        +              "b": {
        +                "description": "Blue 0..255.",
        +                "type": "integer"
        +              },
        +              "g": {
        +                "description": "Green 0..255.",
        +                "type": "integer"
        +              },
        +              "r": {
        +                "description": "Red 0..255.",
        +                "type": "integer"
        +              }
        +            },
        +            "required": [
        +              "r",
        +              "g",
        +              "b",
        +              "a"
        +            ],
        +            "type": "object"
        +          },
        +          "offset_x": {
        +            "description": "Horizontal offset, composition px.",
        +            "type": "number"
        +          },
        +          "offset_y": {
        +            "description": "Vertical offset, composition px.",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "color",
        +          "offset_x",
        +          "offset_y",
        +          "blur"
        +        ],
        +        "type": [
        +          "object",
        +          "null"
        +        ]
        +      },
        +      "valign": {
        +        "description": "Vertical alignment inside the box.",
        +        "enum": [
        +          "Top",
        +          "Middle",
        +          "Bottom"
        +        ],
        +        "type": "string"
        +      },
        +      "x": {
        +        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: set_position / translate_path.",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "The anchor point's y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        +        "type": "number"
        +      },
        +      "crop": {
        +        "additionalProperties": false,
        +        "description": "Static retained source rectangle in normalized 0..1 coordinates, before transform. x/y are top-left; w/h positive, contained in source. Null resets. Does not change scale or position.",
        +        "properties": {
        +          "h": {
        +            "description": "Height.",
        +            "exclusiveMinimum": 0,
        +            "maximum": 1,
        +            "type": "number"
        +          },
        +          "w": {
        +            "description": "Width.",
        +            "exclusiveMinimum": 0,
        +            "maximum": 1,
        +            "type": "number"
        +          },
        +          "x": {
        +            "description": "Left.",
        +            "maximum": 1,
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "y": {
        +            "description": "Top.",
        +            "maximum": 1,
        +            "minimum": 0,
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "x",
        +          "y",
        +          "w",
        +          "h"
        +        ],
        +        "type": [
        +          "object",
        +          "null"
        +        ]
        +      },
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "flip_h": {
        +        "description": "Mirror horizontally.",
        +        "type": "boolean"
        +      },
        +      "flip_v": {
        +        "description": "Mirror vertically.",
        +        "type": "boolean"
        +      },
        +      "kind": {
        +        "const": "VideoClip",
        +        "description": "Fields of a VideoClip layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "src_out_us": {
        +        "description": "Source out point (exclusive), µs.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: set_position / translate_path.",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "The anchor point's y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        +        "type": "number"
        +      },
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "graphic_role": {
        +        "description": "Graphic role (see add_text_layer); null clears.",
        +        "pattern": "^[a-z][a-z0-9_]{0,31}$",
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "kind": {
        +        "const": "ImageOverlay",
        +        "description": "Fields of a ImageOverlay layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "x": {
        +        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: set_position / translate_path.",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "The anchor point's y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        +        "type": "number"
        +      },
        +      "graphic_role": {
        +        "description": "Graphic role (see add_text_layer); null clears.",
        +        "pattern": "^[a-z][a-z0-9_]{0,31}$",
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "kind": {
        +        "const": "Motif",
        +        "description": "Fields of a Motif layer."
        +      },
        +      "motif_id": {
        +        "description": "Motif id from list_motifs.",
        +        "type": "string"
        +      },
        +      "motif_version": {
        +        "description": "Motif version to bind.",
        +        "type": "integer"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "props": {
        +        "description": "Motif props, matched against its props_schema.",
        +        "type": "object"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: set_position / translate_path.",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "The anchor point's y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "color": {
        +        "description": "Fill colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "height": {
        +        "description": "Colour block height, px.",
        +        "type": "integer"
        +      },
        +      "kind": {
        +        "const": "Color",
        +        "description": "Fields of a Color layer."
        +      },
        +      "width": {
        +        "description": "Colour block width, px.",
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "gain_db": {
        +        "description": "Gain, dB; written Static, replacing any keyframes.",
        +        "type": "number"
        +      },
        +      "kind": {
        +        "const": "Audio",
        +        "description": "Fields of a Audio layer."
        +      },
        +      "mute": {
        +        "description": "Silence the clip.",
        +        "type": "boolean"
        +      },
        +      "pan": {
        +        "description": "Stereo pan, -1 (left) .. 1 (right); written Static.",
        +        "type": "number"
        +      },
        +      "role": {
        +        "description": "Mixing bus.",
        +        "enum": [
        +          "dialogue",
        +          "music",
        +          "sfx",
        +          "voiceover"
        +        ],
        +        "type": "string"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "src_out_us": {
        +        "description": "Source out point (exclusive), µs.",
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Anchor (pivot), fraction of the width: 0 left, 0.5 centre (default), 1 right.",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Anchor (pivot), fraction of the height: 0 top, 0.5 centre (default), 1 bottom.",
        +        "type": "number"
        +      },
        +      "blend_mode": {
        +        "description": "How the Group composites over what lies below.",
        +        "enum": [
        +          "Normal",
        +          "Multiply",
        +          "Screen",
        +          "Overlay",
        +          "Darken",
        +          "Lighten",
        +          "Add",
        +          "Difference"
        +        ],
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "CompositionRef",
        +        "description": "Fields of a CompositionRef layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "src_out_us": {
        +        "description": "Source out point (exclusive), µs.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "The anchor point's x, composition px: the centre unless anchor_x moves it. Refused in Path mode: set_position / translate_path.",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "The anchor point's y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  }
        +]
    • Changedupdate_motif_files1 field changed
      • changedInput schema / properties / files / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "path": {
        -        "description": "Path relative to the Motif root.",
        -        "type": "string"
        -      },
        -      "text": {
        -        "description": "Complete UTF-8 file contents.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "path",
        -      "text"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "file_id": {
        -        "description": "Temporary file transfer id.",
        -        "type": "string"
        -      },
        -      "path": {
        -        "description": "Path relative to the Motif root.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "path",
        -      "file_id"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "delete": {
        -        "const": true,
        -        "description": "Remove this file."
        -      },
        -      "path": {
        -        "description": "Path relative to the Motif root.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "path",
        -      "delete"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "path": {
        +        "description": "Path relative to the Motif root.",
        +        "type": "string"
        +      },
        +      "text": {
        +        "description": "Complete UTF-8 file contents.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "path",
        +      "text"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "file_id": {
        +        "description": "Temporary file transfer id.",
        +        "type": "string"
        +      },
        +      "path": {
        +        "description": "Path relative to the Motif root.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "path",
        +      "file_id"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "edits": {
        +        "description": "Replacements applied in order to the current UTF-8 file.",
        +        "items": {
        +          "additionalProperties": false,
        +          "properties": {
        +            "new": {
        +              "description": "Replacement text.",
        +              "type": "string"
        +            },
        +            "old": {
        +              "description": "Exact text to replace; must occur exactly once in the file.",
        +              "minLength": 1,
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "old",
        +            "new"
        +          ],
        +          "type": "object"
        +        },
        +        "minItems": 1,
        +        "type": "array"
        +      },
        +      "path": {
        +        "description": "Path relative to the Motif root.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "path",
        +      "edits"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "delete": {
        +        "const": true,
        +        "description": "Remove this file."
        +      },
        +      "path": {
        +        "description": "Path relative to the Motif root.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "path",
        +      "delete"
        +    ],
        +    "type": "object"
        +  }
        +]
  4. 1 tool updatev0.5.2
    • Changeddescribe_clip1 field changed
      • addedInput schema / properties / purpose
        Added value: +{
        +  "default": "clip",
        +  "description": "Cache purpose: clip content (default) or individual shot identification.\nIndependent of prompt focus; results are never shared across purposes.",
        +  "enum": [
        +    "clip",
        +    "shot"
        +  ],
        +  "type": "string"
        +}
  5. 12 tool updatesv0.5.0
    • Addedcreate_export_preset
    • Addedcreate_tacks
    • Addeddelete_export_preset
    • Addeddelete_tacks
    • Changedget_export_options1 field changed
      • addedInput schema / properties / preset_id
        Added value: +{
        +  "description": "Exact preset ID from list_export_presets. Built-in IDs start with builtin:.",
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Addedlist_export_presets
    • Changedread_project1 field changed
      • changedInput schema / properties / view / enum
        Previous value: -[
        -  "current",
        -  "composition",
        -  "compositions",
        -  "media",
        -  "tracks",
        -  "layer",
        -  "markers",
        -  "links",
        -  "transitions",
        -  "settings",
        -  "history",
        -  "session",
        -  "effects",
        -  "media_thumbnail",
        -  "media_frame"
        -]New value: +[
        +  "current",
        +  "composition",
        +  "compositions",
        +  "media",
        +  "tracks",
        +  "layer",
        +  "markers",
        +  "links",
        +  "transitions",
        +  "settings",
        +  "history",
        +  "session",
        +  "effects",
        +  "tacks",
        +  "media_thumbnail",
        +  "media_frame"
        +]
    • Addedrename_export_preset
    • Addedset_default_export_preset
    • Changedstart_export2 fields changed
      • addedInput schema / properties / preset_id
        Added value: +{
        +  "description": "Exact preset ID from list_export_presets. Built-in IDs start with builtin:.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / settings / description
        Previous value: -"Partial per-job overrides; omitted fields use saved project defaults."New value: +"Partial per-job overrides, applied after preset_id. Without preset_id, uses saved project settings then the global default. Does not change the preset or saved project settings."
    • Addedupdate_export_preset
    • Addedupdate_tack
  6. 21 tool updatesv0.4.0
    • Addedbegin_file_upload
    • Addedcancel_export
    • Addeddelete_file_transfer
    • Changeddelete_motif2 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • changedInput schema / properties / id / description
        Previous value: -"The Motif id (from `list_motifs`)."New value: +"Motif id."
    • Addedexport_motif
    • Addedget_export_options
    • Addedget_export_status
    • Removedget_motif_source
    • Changedinstall_motif7 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • changedInput schema / properties / draft_id / description
        Previous value: -"The draft id (from `write_motif_draft`)."New value: +"Editable draft id."
      • addedInput schema / properties / expected_revision
        Added value: +{
        +  "description": "Revision returned by open, read or preview.",
        +  "type": "string"
        +}
      • addedInput schema / properties / expected_version
        Added value: +{
        +  "description": "Current version of the publication target.",
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • removedInput schema / properties / mode
        Removed value: -{
        -  "description": "\"new\" (publish under the draft's own id) or \"update\" (republish over `target_id`, else the draft's recorded target).",
        -  "enum": [
        -    "new",
        -    "update"
        -  ],
        -  "type": "string"
        -}
      • changedInput schema / properties / target_id / description
        Previous value: -"For mode \"update\": the installed Motif to republish over. Omit to use the target the draft recorded (`write_motif_draft { from }`)."New value: +"Installed Motif to replace."
      • changedInput schema / required
        Previous value: -[
        -  "draft_id",
        -  "mode"
        -]New value: +[
        +  "draft_id",
        +  "expected_revision"
        +]
    • Changedlist_motifs3 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • addedInput schema / properties / status
        Added value: +{
        +  "description": "Filter by lifecycle status.",
        +  "enum": [
        +    "builtin",
        +    "installed",
        +    "draft"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[]
    • Addedopen_motif_draft
    • Addedpreview_motif
    • Removedpreview_motif_draft
    • Addedread_file_transfer
    • Addedread_motif
    • Addedretry_export
    • Addedstart_export
    • Changedtranscribe_clip1 field changed
      • addedInput schema / properties / normalize_audio
        Added value: +{
        +  "default": false,
        +  "description": "Explicit opt-in: normalize only the transcription copy toward -3 dBFS\npeak, at most +24 dB. Original media/timeline stay unchanged. Default false.",
        +  "type": "boolean"
        +}
    • Addedupdate_motif_files
    • Addedwrite_file_chunk
    • Removedwrite_motif_draft
  7. 6 tool updatesv0.3.0
    • Addedget_frame_interpolation_capabilities
    • Addedretime_layers
    • Addedset_frame_interpolation
    • Changedset_param_track1 field changed
      • addedInput schema / properties / track / properties / value / items / properties / time_fraction
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "Optional exact sub-microsecond remainder; keeps retimed keys unsnapped.",
        +  "properties": {
        +    "den": {
        +      "description": "Positive denominator; reduced fraction.",
        +      "type": "integer"
        +    },
        +    "num": {
        +      "description": "0 <= num < den.",
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "num",
        +    "den"
        +  ],
        +  "type": "object"
        +}
    • Addedset_preserve_pitch
    • Changedupdate_layer_params1 field changed
      • changedInput schema / properties / patch / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "align": {
        -        "description": "Horizontal alignment inside the box.",
        -        "enum": [
        -          "Left",
        -          "Center",
        -          "Right"
        -        ],
        -        "type": "string"
        -      },
        -      "anchor_x": {
        -        "description": "Pivot x, fraction of the width (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Pivot y, fraction of the height (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "box_h": {
        -        "description": "Layout box height, composition px, local (before `scale`). null = auto height. Refused when the layer has no box_w and the patch supplies none.",
        -        "exclusiveMinimum": 0,
        -        "type": [
        -          "number",
        -          "null"
        -        ]
        -      },
        -      "box_w": {
        -        "description": "Layout box width, composition px, local (before `scale`). null = auto width.",
        -        "exclusiveMinimum": 0,
        -        "type": [
        -          "number",
        -          "null"
        -        ]
        -      },
        -      "color": {
        -        "description": "Fill colour.",
        -        "properties": {
        -          "a": {
        -            "description": "Alpha 0..255; 255 opaque.",
        -            "type": "integer"
        -          },
        -          "b": {
        -            "description": "Blue 0..255.",
        -            "type": "integer"
        -          },
        -          "g": {
        -            "description": "Green 0..255.",
        -            "type": "integer"
        -          },
        -          "r": {
        -            "description": "Red 0..255.",
        -            "type": "integer"
        -          }
        -        },
        -        "required": [
        -          "r",
        -          "g",
        -          "b",
        -          "a"
        -        ],
        -        "type": "object"
        -      },
        -      "content": {
        -        "description": "The text; newlines are honoured.",
        -        "type": "string"
        -      },
        -      "font_family": {
        -        "description": "Font family name.",
        -        "type": "string"
        -      },
        -      "font_size_px": {
        -        "description": "Font size, composition px.",
        -        "type": "number"
        -      },
        -      "font_weight": {
        -        "description": "CSS weight 100..900; 400 regular, 700 bold.",
        -        "type": "integer"
        -      },
        -      "italic": {
        -        "description": "Italic face.",
        -        "type": "boolean"
        -      },
        -      "kind": {
        -        "const": "Text",
        -        "description": "Fields of a Text layer."
        -      },
        -      "letter_spacing": {
        -        "description": "Letter spacing, px.",
        -        "type": "number"
        -      },
        -      "line_height": {
        -        "description": "Line height, px; 0 = the font metrics.",
        -        "type": "number"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "outline_color": {
        -        "description": "Stroke colour.",
        -        "properties": {
        -          "a": {
        -            "description": "Alpha 0..255; 255 opaque.",
        -            "type": "integer"
        -          },
        -          "b": {
        -            "description": "Blue 0..255.",
        -            "type": "integer"
        -          },
        -          "g": {
        -            "description": "Green 0..255.",
        -            "type": "integer"
        -          },
        -          "r": {
        -            "description": "Red 0..255.",
        -            "type": "integer"
        -          }
        -        },
        -        "required": [
        -          "r",
        -          "g",
        -          "b",
        -          "a"
        -        ],
        -        "type": "object"
        -      },
        -      "outline_width": {
        -        "description": "Stroke width, composition px; 0 removes the outline.",
        -        "type": "number"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "shadow": {
        -        "description": "Drop shadow, or null for none.",
        -        "properties": {
        -          "blur": {
        -            "description": "Blur radius, composition px; 0 is hard-edged.",
        -            "minimum": 0,
        -            "type": "number"
        -          },
        -          "color": {
        -            "description": "Shadow colour.",
        -            "properties": {
        -              "a": {
        -                "description": "Alpha 0..255; 255 opaque.",
        -                "type": "integer"
        -              },
        -              "b": {
        -                "description": "Blue 0..255.",
        -                "type": "integer"
        -              },
        -              "g": {
        -                "description": "Green 0..255.",
        -                "type": "integer"
        -              },
        -              "r": {
        -                "description": "Red 0..255.",
        -                "type": "integer"
        -              }
        -            },
        -            "required": [
        -              "r",
        -              "g",
        -              "b",
        -              "a"
        -            ],
        -            "type": "object"
        -          },
        -          "offset_x": {
        -            "description": "Horizontal offset, composition px.",
        -            "type": "number"
        -          },
        -          "offset_y": {
        -            "description": "Vertical offset, composition px.",
        -            "type": "number"
        -          }
        -        },
        -        "required": [
        -          "color",
        -          "offset_x",
        -          "offset_y",
        -          "blur"
        -        ],
        -        "type": [
        -          "object",
        -          "null"
        -        ]
        -      },
        -      "valign": {
        -        "description": "Vertical alignment inside the box.",
        -        "enum": [
        -          "Top",
        -          "Middle",
        -          "Bottom"
        -        ],
        -        "type": "string"
        -      },
        -      "x": {
        -        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "Anchor y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Pivot x, fraction of the width (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Pivot y, fraction of the height (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "fade_in_us": {
        -        "description": "Fade-in length, µs.",
        -        "type": "integer"
        -      },
        -      "fade_out_us": {
        -        "description": "Fade-out length, µs.",
        -        "type": "integer"
        -      },
        -      "flip_h": {
        -        "description": "Mirror horizontally.",
        -        "type": "boolean"
        -      },
        -      "flip_v": {
        -        "description": "Mirror vertically.",
        -        "type": "boolean"
        -      },
        -      "kind": {
        -        "const": "VideoClip",
        -        "description": "Fields of a VideoClip layer."
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "speed": {
        -        "description": "Playback rate; 1 = normal.",
        -        "type": "number"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "src_out_us": {
        -        "description": "Source out point (exclusive), µs.",
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "Anchor y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Pivot x, fraction of the width (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Pivot y, fraction of the height (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "fade_in_us": {
        -        "description": "Fade-in length, µs.",
        -        "type": "integer"
        -      },
        -      "fade_out_us": {
        -        "description": "Fade-out length, µs.",
        -        "type": "integer"
        -      },
        -      "kind": {
        -        "const": "ImageOverlay",
        -        "description": "Fields of a ImageOverlay layer."
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "x": {
        -        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "Anchor y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Pivot x, fraction of the width (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Pivot y, fraction of the height (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "kind": {
        -        "const": "Motif",
        -        "description": "Fields of a Motif layer."
        -      },
        -      "motif_id": {
        -        "description": "Motif id from list_motifs.",
        -        "type": "string"
        -      },
        -      "motif_version": {
        -        "description": "Motif version to bind.",
        -        "type": "integer"
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "props": {
        -        "description": "Motif props, matched against its props_schema.",
        -        "type": "object"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "Anchor y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "color": {
        -        "description": "Fill colour.",
        -        "properties": {
        -          "a": {
        -            "description": "Alpha 0..255; 255 opaque.",
        -            "type": "integer"
        -          },
        -          "b": {
        -            "description": "Blue 0..255.",
        -            "type": "integer"
        -          },
        -          "g": {
        -            "description": "Green 0..255.",
        -            "type": "integer"
        -          },
        -          "r": {
        -            "description": "Red 0..255.",
        -            "type": "integer"
        -          }
        -        },
        -        "required": [
        -          "r",
        -          "g",
        -          "b",
        -          "a"
        -        ],
        -        "type": "object"
        -      },
        -      "height": {
        -        "description": "Colour block height, px.",
        -        "type": "integer"
        -      },
        -      "kind": {
        -        "const": "Color",
        -        "description": "Fields of a Color layer."
        -      },
        -      "width": {
        -        "description": "Colour block width, px.",
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "fade_in_us": {
        -        "description": "Fade-in length, µs.",
        -        "type": "integer"
        -      },
        -      "fade_out_us": {
        -        "description": "Fade-out length, µs.",
        -        "type": "integer"
        -      },
        -      "gain_db": {
        -        "description": "Gain, dB; written Static, replacing any keyframes.",
        -        "type": "number"
        -      },
        -      "kind": {
        -        "const": "Audio",
        -        "description": "Fields of a Audio layer."
        -      },
        -      "mute": {
        -        "description": "Silence the clip.",
        -        "type": "boolean"
        -      },
        -      "pan": {
        -        "description": "Stereo pan, -1 (left) .. 1 (right); written Static.",
        -        "type": "number"
        -      },
        -      "role": {
        -        "description": "Mixing bus.",
        -        "enum": [
        -          "dialogue",
        -          "music",
        -          "sfx",
        -          "voiceover"
        -        ],
        -        "type": "string"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "src_out_us": {
        -        "description": "Source out point (exclusive), µs.",
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "anchor_x": {
        -        "description": "Pivot x, fraction of the width (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "anchor_y": {
        -        "description": "Pivot y, fraction of the height (0.5 = centre).",
        -        "type": "number"
        -      },
        -      "blend_mode": {
        -        "description": "How the Group composites over what lies below.",
        -        "enum": [
        -          "Normal",
        -          "Multiply",
        -          "Screen",
        -          "Overlay",
        -          "Darken",
        -          "Lighten",
        -          "Add",
        -          "Difference"
        -        ],
        -        "type": "string"
        -      },
        -      "kind": {
        -        "const": "CompositionRef",
        -        "description": "Fields of a CompositionRef layer."
        -      },
        -      "opacity": {
        -        "description": "Opacity 0..1.",
        -        "type": "number"
        -      },
        -      "rotation_deg": {
        -        "description": "Rotation, degrees clockwise.",
        -        "type": "number"
        -      },
        -      "scale_x": {
        -        "description": "Horizontal scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "scale_y": {
        -        "description": "Vertical scale factor; 1 = native size.",
        -        "type": "number"
        -      },
        -      "src_in_us": {
        -        "description": "Source in point, µs.",
        -        "type": "integer"
        -      },
        -      "src_out_us": {
        -        "description": "Source out point (exclusive), µs.",
        -        "type": "integer"
        -      },
        -      "x": {
        -        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        -        "type": "number"
        -      },
        -      "y": {
        -        "description": "Anchor y, composition px (refused in Path mode).",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "kind"
        -    ]
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "align": {
        +        "description": "Horizontal alignment inside the box.",
        +        "enum": [
        +          "Left",
        +          "Center",
        +          "Right"
        +        ],
        +        "type": "string"
        +      },
        +      "anchor_x": {
        +        "description": "Pivot x, fraction of the width (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Pivot y, fraction of the height (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "box_h": {
        +        "description": "Layout box height, composition px, local (before `scale`). null = auto height. Refused when the layer has no box_w and the patch supplies none.",
        +        "exclusiveMinimum": 0,
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "box_w": {
        +        "description": "Layout box width, composition px, local (before `scale`). null = auto width.",
        +        "exclusiveMinimum": 0,
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "color": {
        +        "description": "Fill colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "content": {
        +        "description": "The text; newlines are honoured.",
        +        "type": "string"
        +      },
        +      "font_family": {
        +        "description": "Font family name.",
        +        "type": "string"
        +      },
        +      "font_size_px": {
        +        "description": "Font size, composition px.",
        +        "type": "number"
        +      },
        +      "font_weight": {
        +        "description": "CSS weight 100..900; 400 regular, 700 bold.",
        +        "type": "integer"
        +      },
        +      "italic": {
        +        "description": "Italic face.",
        +        "type": "boolean"
        +      },
        +      "kind": {
        +        "const": "Text",
        +        "description": "Fields of a Text layer."
        +      },
        +      "letter_spacing": {
        +        "description": "Letter spacing, px.",
        +        "type": "number"
        +      },
        +      "line_height": {
        +        "description": "Line height, px; 0 = the font metrics.",
        +        "type": "number"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "outline_color": {
        +        "description": "Stroke colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "outline_width": {
        +        "description": "Stroke width, composition px; 0 removes the outline.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "shadow": {
        +        "description": "Drop shadow, or null for none.",
        +        "properties": {
        +          "blur": {
        +            "description": "Blur radius, composition px; 0 is hard-edged.",
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "color": {
        +            "description": "Shadow colour.",
        +            "properties": {
        +              "a": {
        +                "description": "Alpha 0..255; 255 opaque.",
        +                "type": "integer"
        +              },
        +              "b": {
        +                "description": "Blue 0..255.",
        +                "type": "integer"
        +              },
        +              "g": {
        +                "description": "Green 0..255.",
        +                "type": "integer"
        +              },
        +              "r": {
        +                "description": "Red 0..255.",
        +                "type": "integer"
        +              }
        +            },
        +            "required": [
        +              "r",
        +              "g",
        +              "b",
        +              "a"
        +            ],
        +            "type": "object"
        +          },
        +          "offset_x": {
        +            "description": "Horizontal offset, composition px.",
        +            "type": "number"
        +          },
        +          "offset_y": {
        +            "description": "Vertical offset, composition px.",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "color",
        +          "offset_x",
        +          "offset_y",
        +          "blur"
        +        ],
        +        "type": [
        +          "object",
        +          "null"
        +        ]
        +      },
        +      "valign": {
        +        "description": "Vertical alignment inside the box.",
        +        "enum": [
        +          "Top",
        +          "Middle",
        +          "Bottom"
        +        ],
        +        "type": "string"
        +      },
        +      "x": {
        +        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "Anchor y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Pivot x, fraction of the width (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Pivot y, fraction of the height (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "crop": {
        +        "additionalProperties": false,
        +        "description": "Static retained source rectangle in normalized 0..1 coordinates, before transform. x/y are top-left; w/h positive, contained in source. Null resets. Does not change scale or position.",
        +        "properties": {
        +          "h": {
        +            "description": "Height.",
        +            "exclusiveMinimum": 0,
        +            "maximum": 1,
        +            "type": "number"
        +          },
        +          "w": {
        +            "description": "Width.",
        +            "exclusiveMinimum": 0,
        +            "maximum": 1,
        +            "type": "number"
        +          },
        +          "x": {
        +            "description": "Left.",
        +            "maximum": 1,
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "y": {
        +            "description": "Top.",
        +            "maximum": 1,
        +            "minimum": 0,
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "x",
        +          "y",
        +          "w",
        +          "h"
        +        ],
        +        "type": [
        +          "object",
        +          "null"
        +        ]
        +      },
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "flip_h": {
        +        "description": "Mirror horizontally.",
        +        "type": "boolean"
        +      },
        +      "flip_v": {
        +        "description": "Mirror vertically.",
        +        "type": "boolean"
        +      },
        +      "kind": {
        +        "const": "VideoClip",
        +        "description": "Fields of a VideoClip layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "src_out_us": {
        +        "description": "Source out point (exclusive), µs.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "Anchor y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Pivot x, fraction of the width (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Pivot y, fraction of the height (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "kind": {
        +        "const": "ImageOverlay",
        +        "description": "Fields of a ImageOverlay layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "x": {
        +        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "Anchor y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Pivot x, fraction of the width (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Pivot y, fraction of the height (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "kind": {
        +        "const": "Motif",
        +        "description": "Fields of a Motif layer."
        +      },
        +      "motif_id": {
        +        "description": "Motif id from list_motifs.",
        +        "type": "string"
        +      },
        +      "motif_version": {
        +        "description": "Motif version to bind.",
        +        "type": "integer"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "props": {
        +        "description": "Motif props, matched against its props_schema.",
        +        "type": "object"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "Anchor y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "color": {
        +        "description": "Fill colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "height": {
        +        "description": "Colour block height, px.",
        +        "type": "integer"
        +      },
        +      "kind": {
        +        "const": "Color",
        +        "description": "Fields of a Color layer."
        +      },
        +      "width": {
        +        "description": "Colour block width, px.",
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "gain_db": {
        +        "description": "Gain, dB; written Static, replacing any keyframes.",
        +        "type": "number"
        +      },
        +      "kind": {
        +        "const": "Audio",
        +        "description": "Fields of a Audio layer."
        +      },
        +      "mute": {
        +        "description": "Silence the clip.",
        +        "type": "boolean"
        +      },
        +      "pan": {
        +        "description": "Stereo pan, -1 (left) .. 1 (right); written Static.",
        +        "type": "number"
        +      },
        +      "role": {
        +        "description": "Mixing bus.",
        +        "enum": [
        +          "dialogue",
        +          "music",
        +          "sfx",
        +          "voiceover"
        +        ],
        +        "type": "string"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "src_out_us": {
        +        "description": "Source out point (exclusive), µs.",
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Pivot x, fraction of the width (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Pivot y, fraction of the height (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "blend_mode": {
        +        "description": "How the Group composites over what lies below.",
        +        "enum": [
        +          "Normal",
        +          "Multiply",
        +          "Screen",
        +          "Overlay",
        +          "Darken",
        +          "Lighten",
        +          "Add",
        +          "Difference"
        +        ],
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "CompositionRef",
        +        "description": "Fields of a CompositionRef layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "src_out_us": {
        +        "description": "Source out point (exclusive), µs.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "Anchor y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  }
        +]
  8. 14 tool updatesv0.2.2
    • Changedadd_audio_layer1 field changed
      • changedInput schema / properties / composition_id / description
        Previous value: -"Optional cross-check: the composition `track_id` belongs to; refused on mismatch. The track alone fixes the composition."New value: +"Optional composition check for track_id; mismatch rejects. track_id fixes the composition."
    • Changedadd_color_layer1 field changed
      • changedInput schema / properties / composition_id / description
        Previous value: -"Optional cross-check: the composition `track_id` belongs to; refused on mismatch. The track alone fixes the composition."New value: +"Optional composition check for track_id; mismatch rejects. track_id fixes the composition."
    • Changedadd_group_layer1 field changed
      • changedInput schema / properties / composition_id / description
        Previous value: -"Optional cross-check: the composition `track_id` belongs to; refused on mismatch. The track alone fixes the composition."New value: +"Optional composition check for track_id; mismatch rejects. track_id fixes the composition."
    • Changedadd_text_layer1 field changed
      • changedInput schema / properties / composition_id / description
        Previous value: -"Optional cross-check: the composition `track_id` belongs to; refused on mismatch. The track alone fixes the composition."New value: +"Optional composition check for track_id; mismatch rejects. track_id fixes the composition."
    • Changedadd_video_layer1 field changed
      • changedInput schema / properties / composition_id / description
        Previous value: -"Optional cross-check: the composition `track_id` belongs to; refused on mismatch. The track alone fixes the composition."New value: +"Optional composition check for track_id; mismatch rejects. track_id fixes the composition."
    • Changedclear_keyframes1 field changed
      • changedInput schema / properties / param_key / description
        Previous value: -"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."New value: +"Visual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>]."
    • Changeddelete_keyframe1 field changed
      • changedInput schema / properties / param_key / description
        Previous value: -"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."New value: +"Visual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>]."
    • Changedget_param_track1 field changed
      • changedInput schema / properties / param_key / description
        Previous value: -"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."New value: +"Visual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>]."
    • Changedrestack_layer4 fields changed
      • addedInput schema / oneOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "anchor_track_id"
        +      ]
        +    },
        +    "required": [
        +      "anchor_layer_id"
        +    ]
        +  },
        +  {
        +    "not": {
        +      "required": [
        +        "anchor_layer_id"
        +      ]
        +    },
        +    "required": [
        +      "anchor_track_id"
        +    ]
        +  }
        +]
      • changedInput schema / properties / anchor_layer_id / description
        Previous value: -"The visual layer to place it against; may sit on a reserved track."New value: +"The visual layer to place it against; supply exactly one of anchor_layer_id / anchor_track_id."
      • addedInput schema / properties / anchor_track_id
        Added value: +{
        +  "description": "A visual track to place it against, including an empty reserved lane. Supply instead of anchor_layer_id.",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "anchor_layer_id",
        -  "layer_id",
        -  "position"
        -]New value: +[
        +  "layer_id",
        +  "position"
        +]
    • Changedset_extrapolation3 fields changed
      • changedInput schema / properties / after / description
        Previous value: -"After the last key. Hold = the end value; Loop = repeat the cycle; PingPong = alternate cycles reversed; Offset = each cycle adds the last-minus-first delta; Continue = carry the end velocity on as a line."New value: +"After the last key; modes as described by this tool."
      • changedInput schema / properties / before / description
        Previous value: -"Before the first key. Hold = the end value; Loop = repeat the cycle; PingPong = alternate cycles reversed; Offset = each cycle adds the last-minus-first delta; Continue = carry the end velocity on as a line."New value: +"Before the first key; modes as described by this tool."
      • changedInput schema / properties / param_key / description
        Previous value: -"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."New value: +"Visual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>]."
    • Changedset_keyframe1 field changed
      • changedInput schema / properties / param_key / description
        Previous value: -"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."New value: +"Visual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>]."
    • Changedset_param_track1 field changed
      • changedInput schema / properties / param_key / description
        Previous value: -"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."New value: +"Visual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>]."
    • Changedsmooth_keyframes1 field changed
      • changedInput schema / properties / param_key / description
        Previous value: -"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."New value: +"Visual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>]."
    • Changedupdate_keyframe1 field changed
      • changedInput schema / properties / param_key / description
        Previous value: -"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."New value: +"Visual: x/y (XY), path_progress (Path), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text/Color: color; Audio: gain_db, pan; effects[<effect_id>].params[<key>]."
  9. 9 tool updatesv0.2.1
    • Addedanalyze_audio
    • Changedapply_subtitles6 fields changed
      • removedInput schema / properties / body
        Removed value: -{
        -  "description": "Subtitle document body (SRT, ASS, or VTT).",
        -  "type": "string"
        -}
      • addedInput schema / properties / composition_id
        Added value: +{
        +  "description": "Composition to create in — a Group's id from `project://compositions`; omit for the root.",
        +  "type": "string"
        +}
      • removedInput schema / properties / format
        Removed value: -{
        -  "description": "'srt', 'ass', or 'vtt'. Sniffed from body when omitted.",
        -  "type": "string"
        -}
      • addedInput schema / properties / media_id
        Added value: +{
        +  "description": "Subtitle media id.",
        +  "type": "string"
        +}
      • addedInput schema / properties / t_start_us
        Added value: +{
        +  "description": "Where the document's time 0 lands on the timeline; default 0, µs.",
        +  "type": "integer"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "body"
        -]New value: +[
        +  "media_id"
        +]
    • Changedcreate_link1 field changed
      • removedInput schema / properties / label
        Removed value: -{
        -  "description": "Optional name.",
        -  "type": "string"
        -}
    • Addedcreate_project
    • Addedopen_project
    • Changedset_param_track8 fields changed
      • addedInput schema / properties / track / properties / value / items / additionalProperties
        Added value: +false
      • changedInput schema / properties / track / properties / value / items / properties / continuity / description
        Previous value: -"With both sides Free: Smooth keeps their slopes locked equal on write, Broken lets them differ."New value: +"Defaults to Broken. Smooth keeps both Free sides at equal slopes on write."
      • removedInput schema / properties / track / properties / value / items / properties / id
        Removed value: -{
        -  "description": "Key id: an existing one updates that key, a fresh one adds.",
        -  "type": "string"
        -}
      • changedInput schema / properties / track / properties / value / items / properties / in / description
        Previous value: -"Arriving tangent."New value: +"Optional arriving tangent; defaults to identity, Free."
      • changedInput schema / properties / track / properties / value / items / properties / out / description
        Previous value: -"Leaving tangent."New value: +"Optional leaving tangent; defaults to identity, Free."
      • changedInput schema / properties / track / properties / value / items / properties / segment / description
        Previous value: -"Class of the segment LEAVING the key: Spline (reads the tangents) | Hold | Linear | Elastic (dir, amplitude?, period?) | Bounce (dir)."New value: +"Class of the segment LEAVING the key: Spline (reads the tangents) | Hold | Linear | Elastic (dir, amplitude?, period?) | Bounce (dir). Defaults to Linear."
      • changedInput schema / properties / track / properties / value / items / properties / t_us / description
        Previous value: -"Key time, timeline-absolute, µs."New value: +"Key time; timeline-absolute for set_param_track, layer-local for set_position, µs."
      • changedInput schema / properties / track / properties / value / items / required
        Previous value: -[
        -  "id",
        -  "t_us",
        -  "value",
        -  "in",
        -  "out",
        -  "continuity",
        -  "segment"
        -]New value: +[
        +  "t_us",
        +  "value"
        +]
    • Changedset_position23 fields changed
      • addedInput schema / properties / position / properties / path / properties / nodes / items / additionalProperties
        Added value: +false
      • removedInput schema / properties / position / properties / path / properties / nodes / items / properties / id
        Removed value: -{
        -  "description": "Node id, unique and non-empty (yours to mint).",
        -  "type": "string"
        -}
      • changedInput schema / properties / position / properties / path / properties / nodes / items / properties / segment / description
        Previous value: -"Span LEAVING this node: Line, or Cubic (reads the handles)."New value: +"Span LEAVING this node; defaults to Line. Cubic reads the handles."
      • changedInput schema / properties / position / properties / path / properties / nodes / items / properties / tangent_mode / description
        Previous value: -"Corner: handles independent. Smooth: aligned directions, own lengths. Auto: solved from the neighbours on write."New value: +"Defaults to Corner. Smooth aligns handles; Auto solves from neighbours."
      • changedInput schema / properties / position / properties / path / properties / nodes / items / required
        Previous value: -[
        -  "id",
        -  "point",
        -  "in_handle",
        -  "out_handle",
        -  "segment",
        -  "tangent_mode"
        -]New value: +[
        +  "point"
        +]
      • changedInput schema / properties / position / properties / progress / properties / extrapolate / description
        Previous value: -"What the track does outside its keys, per side: Hold | Loop | PingPong | Offset | Continue (see set_extrapolation)."New value: +"Optional {before,after}: Hold/Loop/PingPong/Offset/Continue; Path progress allows the first three. Defaults to Hold/Hold."
      • removedInput schema / properties / position / properties / progress / properties / extrapolate / properties
        Removed value: -{
        -  "after": {
        -    "description": "After the last key.",
        -    "enum": [
        -      "Hold",
        -      "Loop",
        -      "PingPong",
        -      "Offset",
        -      "Continue"
        -    ],
        -    "type": "string"
        -  },
        -  "before": {
        -    "description": "Before the first key.",
        -    "enum": [
        -      "Hold",
        -      "Loop",
        -      "PingPong",
        -      "Offset",
        -      "Continue"
        -    ],
        -    "type": "string"
        -  }
        -}
      • removedInput schema / properties / position / properties / progress / properties / extrapolate / required
        Removed value: -[
        -  "before",
        -  "after"
        -]
      • changedInput schema / properties / position / properties / progress / properties / mode / description
        Previous value: -"Static holds one number; Keyframed animates the key array."New value: +"Static number or animated keys."
      • changedInput schema / properties / position / properties / progress / properties / value / description
        Previous value: -"Static: the number. Keyframed: the keys, in `set_param_track`'s key shape with layer-local `t_us`."New value: +"Number, or keys with generated IDs (omit id)."
      • addedInput schema / properties / position / properties / progress / properties / value / items
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "continuity": {
        +      "description": "Defaults to Broken.",
        +      "enum": [
        +        "Smooth",
        +        "Broken"
        +      ],
        +      "type": "string"
        +    },
        +    "in": {
        +      "description": "Arriving {x,y,mode}; defaults to identity/Free.",
        +      "type": "object"
        +    },
        +    "out": {
        +      "description": "Leaving {x,y,mode}; defaults to identity/Free.",
        +      "type": "object"
        +    },
        +    "segment": {
        +      "description": "{kind,...} from set_param_track; defaults to Linear.",
        +      "type": "object"
        +    },
        +    "t_us": {
        +      "description": "Layer-local time, µs.",
        +      "type": "integer"
        +    },
        +    "value": {
        +      "description": "Scalar value.",
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "t_us",
        +    "value"
        +  ],
        +  "type": "object"
        +}
      • changedInput schema / properties / position / properties / x / properties / extrapolate / description
        Previous value: -"What the track does outside its keys, per side: Hold | Loop | PingPong | Offset | Continue (see set_extrapolation)."New value: +"Optional {before,after}: Hold/Loop/PingPong/Offset/Continue; Path progress allows the first three. Defaults to Hold/Hold."
      • removedInput schema / properties / position / properties / x / properties / extrapolate / properties
        Removed value: -{
        -  "after": {
        -    "description": "After the last key.",
        -    "enum": [
        -      "Hold",
        -      "Loop",
        -      "PingPong",
        -      "Offset",
        -      "Continue"
        -    ],
        -    "type": "string"
        -  },
        -  "before": {
        -    "description": "Before the first key.",
        -    "enum": [
        -      "Hold",
        -      "Loop",
        -      "PingPong",
        -      "Offset",
        -      "Continue"
        -    ],
        -    "type": "string"
        -  }
        -}
      • removedInput schema / properties / position / properties / x / properties / extrapolate / required
        Removed value: -[
        -  "before",
        -  "after"
        -]
      • changedInput schema / properties / position / properties / x / properties / mode / description
        Previous value: -"Static holds one number; Keyframed animates the key array."New value: +"Static number or animated keys."
      • changedInput schema / properties / position / properties / x / properties / value / description
        Previous value: -"Static: the number. Keyframed: the keys, in `set_param_track`'s key shape with layer-local `t_us`."New value: +"Number, or keys with generated IDs (omit id)."
      • addedInput schema / properties / position / properties / x / properties / value / items
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "continuity": {
        +      "description": "Defaults to Broken.",
        +      "enum": [
        +        "Smooth",
        +        "Broken"
        +      ],
        +      "type": "string"
        +    },
        +    "in": {
        +      "description": "Arriving {x,y,mode}; defaults to identity/Free.",
        +      "type": "object"
        +    },
        +    "out": {
        +      "description": "Leaving {x,y,mode}; defaults to identity/Free.",
        +      "type": "object"
        +    },
        +    "segment": {
        +      "description": "{kind,...} from set_param_track; defaults to Linear.",
        +      "type": "object"
        +    },
        +    "t_us": {
        +      "description": "Layer-local time, µs.",
        +      "type": "integer"
        +    },
        +    "value": {
        +      "description": "Scalar value.",
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "t_us",
        +    "value"
        +  ],
        +  "type": "object"
        +}
      • changedInput schema / properties / position / properties / y / properties / extrapolate / description
        Previous value: -"What the track does outside its keys, per side: Hold | Loop | PingPong | Offset | Continue (see set_extrapolation)."New value: +"Optional {before,after}: Hold/Loop/PingPong/Offset/Continue; Path progress allows the first three. Defaults to Hold/Hold."
      • removedInput schema / properties / position / properties / y / properties / extrapolate / properties
        Removed value: -{
        -  "after": {
        -    "description": "After the last key.",
        -    "enum": [
        -      "Hold",
        -      "Loop",
        -      "PingPong",
        -      "Offset",
        -      "Continue"
        -    ],
        -    "type": "string"
        -  },
        -  "before": {
        -    "description": "Before the first key.",
        -    "enum": [
        -      "Hold",
        -      "Loop",
        -      "PingPong",
        -      "Offset",
        -      "Continue"
        -    ],
        -    "type": "string"
        -  }
        -}
      • removedInput schema / properties / position / properties / y / properties / extrapolate / required
        Removed value: -[
        -  "before",
        -  "after"
        -]
      • changedInput schema / properties / position / properties / y / properties / mode / description
        Previous value: -"Static holds one number; Keyframed animates the key array."New value: +"Static number or animated keys."
      • changedInput schema / properties / position / properties / y / properties / value / description
        Previous value: -"Static: the number. Keyframed: the keys, in `set_param_track`'s key shape with layer-local `t_us`."New value: +"Number, or keys with generated IDs (omit id)."
      • addedInput schema / properties / position / properties / y / properties / value / items
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "continuity": {
        +      "description": "Defaults to Broken.",
        +      "enum": [
        +        "Smooth",
        +        "Broken"
        +      ],
        +      "type": "string"
        +    },
        +    "in": {
        +      "description": "Arriving {x,y,mode}; defaults to identity/Free.",
        +      "type": "object"
        +    },
        +    "out": {
        +      "description": "Leaving {x,y,mode}; defaults to identity/Free.",
        +      "type": "object"
        +    },
        +    "segment": {
        +      "description": "{kind,...} from set_param_track; defaults to Linear.",
        +      "type": "object"
        +    },
        +    "t_us": {
        +      "description": "Layer-local time, µs.",
        +      "type": "integer"
        +    },
        +    "value": {
        +      "description": "Scalar value.",
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "t_us",
        +    "value"
        +  ],
        +  "type": "object"
        +}
    • Changedsplit_layer5 fields changed
      • changedInput schema / properties / at_t_us / description
        Previous value: -"Cut point, timeline; strictly inside the layer, µs."New value: +"Interior timeline cuts, µs; snapped, sorted, deduplicated. Any invalid cut rejects all."
      • addedInput schema / properties / at_t_us / items
        Added value: +{
        +  "type": "integer"
        +}
      • addedInput schema / properties / at_t_us / minItems
        Added value: +1
      • changedInput schema / properties / at_t_us / type
        Previous value: -"integer"New value: +"array"
      • changedInput schema / required
        Previous value: -[
        -  "at_t_us",
        -  "layer_id"
        -]New value: +[
        +  "layer_id",
        +  "at_t_us"
        +]
    • Changedupdate_link1 field changed
      • removedInput schema / properties / label
        Removed value: -{
        -  "description": "New label; null clears it.",
        -  "type": [
        -    "string",
        -    "null"
        -  ]
        -}
  10. 120 tool updatesv0.1.9
    • Addedadd_audio_layer
    • Changedadd_color_layer14 fields changed
      • addedInput schema / properties / color / description
        Added value: +"Fill colour."
      • addedInput schema / properties / color / properties / a / description
        Added value: +"Alpha 0..255; 255 opaque."
      • addedInput schema / properties / color / properties / b / description
        Added value: +"Blue 0..255."
      • addedInput schema / properties / color / properties / g / description
        Added value: +"Green 0..255."
      • addedInput schema / properties / color / properties / r / description
        Added value: +"Red 0..255."
      • changedInput schema / properties / composition_id / description
        Previous value: -"Optional cross-check: the composition `track_id` must belong to (a Group's id from `project://compositions`). The track alone fixes the composition; omit unless you want the mismatch refused."New value: +"Optional cross-check: the composition `track_id` belongs to; refused on mismatch. The track alone fixes the composition."
      • changedInput schema / properties / composition_id / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • addedInput schema / properties / height / description
        Added value: +"Block height, px; default 1080."
      • changedInput schema / properties / height / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • addedInput schema / properties / t_end_us / description
        Added value: +"Timeline end (exclusive), µs."
      • addedInput schema / properties / t_start_us / description
        Added value: +"Timeline start, µs."
      • addedInput schema / properties / track_id / description
        Added value: +"Track id."
      • addedInput schema / properties / width / description
        Added value: +"Block width, px; default 1920."
      • changedInput schema / properties / width / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
    • Changedadd_effect3 fields changed
      • addedInput schema / properties / kind / description
        Added value: +"Catalog key: visual kinds on visual layers, audio.* on Audio layers."
      • addedInput schema / properties / kind / enum
        Added value: +[
        +  "blur",
        +  "chromakey",
        +  "brightness",
        +  "contrast",
        +  "saturation",
        +  "sharpen",
        +  "audio.denoise"
        +]
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
    • Changedadd_group_layer4 fields changed
      • changedInput schema / properties / composition_id / description
        Previous value: -"Optional cross-check: the composition `track_id` must belong to (a Group's id from `project://compositions`). The track alone fixes the composition; omit unless you want the mismatch refused."New value: +"Optional cross-check: the composition `track_id` belongs to; refused on mismatch. The track alone fixes the composition."
      • changedInput schema / properties / composition_id / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • addedInput schema / properties / t_start_us / description
        Added value: +"Timeline start, µs."
      • addedInput schema / properties / track_id / description
        Added value: +"Track id."
    • Addedadd_group_members
    • Changedadd_marker12 fields changed
      • changedInput schema / properties / anchor_layer_id / description
        Previous value: -"Clip the new marker should follow — a layer of the SAME composition carrying a source window (VideoClip, Audio, Group). The mark is born tied to the source instant `t_us` lands on, exactly as attach_marker would tie it afterwards, and is refused for the same three reasons; a refusal creates no marker at all. Omit for a marker fixed to the timeline."New value: +"Clip the marker should follow — a layer of the same composition with a source window (VideoClip, Audio, Group). Tied as `set_marker_anchor` would tie it, refused for the same reasons (no marker is created). Omit for a fixed marker."
      • changedInput schema / properties / anchor_layer_id / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • addedInput schema / properties / color / description
        Added value: +"Marker colour."
      • addedInput schema / properties / color / properties / a / description
        Added value: +"Alpha 0..255; 255 opaque."
      • addedInput schema / properties / color / properties / b / description
        Added value: +"Blue 0..255."
      • addedInput schema / properties / color / properties / g / description
        Added value: +"Green 0..255."
      • addedInput schema / properties / color / properties / r / description
        Added value: +"Red 0..255."
      • changedInput schema / properties / composition_id / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • addedInput schema / properties / end_t_us / description
        Added value: +"Region end, timeline; omit for a point marker, µs."
      • changedInput schema / properties / end_t_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • addedInput schema / properties / label / description
        Added value: +"Short name shown on the marker lane."
      • addedInput schema / properties / t_us / description
        Added value: +"Marker time, timeline, µs."
    • Removedadd_motif
    • Addedadd_motif_layer
    • Addedadd_text_layer
    • Changedadd_track2 fields changed
      • changedInput schema / properties / composition_id / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • changedInput schema / properties / label / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
    • Changedadd_transition6 fields changed
      • addedInput schema / properties / direction / description
        Added value: +"Motion direction. Required for Wipe / Slide, refused for Crossfade."
      • addedInput schema / properties / duration_us / description
        Added value: +"Transition length, µs."
      • addedInput schema / properties / from_layer_id / description
        Added value: +"Outgoing layer — the one that ends at the cut."
      • addedInput schema / properties / kind / description
        Added value: +"Default Crossfade."
      • changedInput schema / properties / placement / description
        Previous value: -"Where the overlap comes from. 'overlap' (default): the incoming layer moves left; both trimmed ranges preserved. 'extend': the outgoing layer borrows tail media; positions untouched."New value: +"'overlap' (default): the incoming layer moves left, trimmed ranges preserved. 'extend': the outgoing layer borrows tail media, positions untouched."
      • addedInput schema / properties / to_layer_id / description
        Added value: +"Incoming layer — the one that starts at the cut."
    • Changedadd_video_layer9 fields changed
      • changedInput schema / properties / composition_id / description
        Previous value: -"Optional cross-check: the composition `track_id` must belong to (a Group's id from `project://compositions`). The track alone fixes the composition; omit unless you want the mismatch refused."New value: +"Optional cross-check: the composition `track_id` belongs to; refused on mismatch. The track alone fixes the composition."
      • changedInput schema / properties / composition_id / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • addedInput schema / properties / media_id / description
        Added value: +"Media id."
      • addedInput schema / properties / src_in_us / description
        Added value: +"Source in point, µs. Required for Video; ignored for an Image."
      • addedInput schema / properties / src_out_us / description
        Added value: +"Source out point (exclusive), µs. Required for Video; ignored for an Image."
      • addedInput schema / properties / t_end_us / description
        Added value: +"Timeline end (exclusive), µs."
      • addedInput schema / properties / t_start_us / description
        Added value: +"Timeline start, µs."
      • addedInput schema / properties / track_id / description
        Added value: +"Track id."
      • changedInput schema / required
        Previous value: -[
        -  "media_id",
        -  "src_in_us",
        -  "src_out_us",
        -  "t_end_us",
        -  "t_start_us",
        -  "track_id"
        -]New value: +[
        +  "media_id",
        +  "t_end_us",
        +  "t_start_us",
        +  "track_id"
        +]
    • Changedanalyze_clip7 fields changed
      • removedInput schema / $schema
        Removed value: -"https://json-schema.org/draft/2020-12/schema"
      • removedInput schema / properties / min_shot_us / format
        Removed value: -"int64"
      • changedInput schema / properties / min_shot_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • changedInput schema / properties / passes / type
        Previous value: -[
        -  "array",
        -  "null"
        -]New value: +"array"
      • removedInput schema / properties / sensitivity / format
        Removed value: -"float"
      • changedInput schema / properties / sensitivity / type
        Previous value: -[
        -  "number",
        -  "null"
        -]New value: +"number"
      • removedInput schema / title
        Removed value: -"AnalyzeClipArgs"
    • Changedapply_subtitles7 fields changed
      • removedInput schema / $schema
        Removed value: -"https://json-schema.org/draft/2020-12/schema"
      • changedInput schema / properties / format / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • removedInput schema / properties / t_end_us
        Removed value: -{
        -  "description": "IGNORED — cue timings come from the body, not the timeline envelope.\nKept for wire-schema stability; do not remove.",
        -  "format": "int64",
        -  "type": "integer"
        -}
      • removedInput schema / properties / t_start_us
        Removed value: -{
        -  "description": "IGNORED — cue timings come from the body, not the timeline envelope.\nKept for wire-schema stability; do not remove.",
        -  "format": "int64",
        -  "type": [
        -    "integer",
        -    "null"
        -  ]
        -}
      • removedInput schema / properties / track_id
        Removed value: -{
        -  "description": "IGNORED — the lane is the packing's to pick: cues land on the caption\ntracks already there where they have room (ADR 0070). Kept for\nwire-schema stability; do not remove.",
        -  "type": [
        -    "string",
        -    "null"
        -  ]
        -}
      • changedInput schema / required
        Previous value: -[
        -  "body",
        -  "t_end_us"
        -]New value: +[
        +  "body"
        +]
      • removedInput schema / title
        Removed value: -"ApplySubtitlesArgs"
    • Addedapply_transcripts
    • Removedattach_marker
    • Changedauto_split_by_shot5 fields changed
      • addedInput schema / properties / drop_short / description
        Added value: +"Also delete segments shorter than min_shot_us, with the overlapping members of their link. Default false."
      • changedInput schema / properties / drop_short / type
        Previous value: -[
        -  "boolean",
        -  "null"
        -]New value: +"boolean"
      • addedInput schema / properties / layer_id / description
        Added value: +"The VideoClip to split."
      • addedInput schema / properties / min_shot_us / description
        Added value: +"Shortest shot to keep; default 500000, µs."
      • changedInput schema / properties / min_shot_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
    • Changedbegin_agent_session1 field changed
      • addedInput schema / properties / reason / description
        Added value: +"What this work session is for; shown to the user beside the busy badge."
    • Removedcheckpoint
    • Changedclear_keyframes6 fields changed
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / param_key / anyOf
        Added value: +[
        +  {
        +    "enum": [
        +      "x",
        +      "y",
        +      "path_progress",
        +      "scale_x",
        +      "scale_y",
        +      "rotation_deg",
        +      "anchor_x",
        +      "anchor_y",
        +      "opacity",
        +      "color",
        +      "gain_db",
        +      "pan"
        +    ]
        +  },
        +  {
        +    "pattern": "^effects\\[[0-9a-fA-F-]{36}\\]\\.params\\[[A-Za-z0-9_]+\\]$"
        +  }
        +]
      • addedInput schema / properties / param_key / description
        Added value: +"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."
      • changedInput schema / properties / value / description
        Previous value: -"Typed by `param_key`: a number for every scalar param (x, y, path_progress, scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity, gain_db, pan, effect params); an {r,g,b,a} colour (integers 0..255) for \"color\" — the Text and Color layers' colour. Path mode rejects independent x/y writes; use path_progress (a fraction, not a percentage); XY mode has no path_progress. A mismatch is refused naming the type the param takes."New value: +"The value to hold, typed by `param_key`; omit for the first keyframe's value."
      • removedInput schema / properties / value / oneOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "properties": {
        -      "a": {
        -        "type": "integer"
        -      },
        -      "b": {
        -        "type": "integer"
        -      },
        -      "g": {
        -        "type": "integer"
        -      },
        -      "r": {
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "r",
        -      "g",
        -      "b",
        -      "a"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • changedInput schema / properties / value / type
        Previous value: -[
        -  "number",
        -  "object",
        -  "null"
        -]New value: +[
        +  "number",
        +  "object"
        +]
    • Changedcompare_frames11 fields changed
      • removedInput schema / $defs
        Removed value: -{
        -  "FrameRef": {
        -    "description": "One side of a `compare_frames` pair. `#[schemars(skip)]` on the injected\n`layer` / `media` keeps each side's ADVERTISED schema exactly\n`{ layer_id, t_us }`; serde still deserializes the host-injected slice.",
        -    "properties": {
        -      "layer_id": {
        -        "description": "Target VideoClip layer id.",
        -        "type": "string"
        -      },
        -      "t_us": {
        -        "description": "SOURCE-ABSOLUTE timestamp (microseconds) of the frame to sample — the\nsame coordinate space as `media://{id}/frame/<t_us>` and the\n`keyframe_t_us` / `t_*_us` that `analyze_clip` returns, so a shot cover\nframe can be fed straight in.",
        -        "format": "int64",
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "layer_id",
        -      "t_us"
        -    ],
        -    "type": "object"
        -  }
        -}
      • removedInput schema / $schema
        Removed value: -"https://json-schema.org/draft/2020-12/schema"
      • removedInput schema / properties / a / $ref
        Removed value: -"#/$defs/FrameRef"
      • addedInput schema / properties / a / properties
        Added value: +{
        +  "layer_id": {
        +    "description": "Target VideoClip layer id.",
        +    "type": "string"
        +  },
        +  "t_us": {
        +    "description": "SOURCE-ABSOLUTE microseconds of the frame to sample (the space\n`analyze_clip`'s `keyframe_t_us` uses).",
        +    "type": "integer"
        +  }
        +}
      • addedInput schema / properties / a / required
        Added value: +[
        +  "layer_id",
        +  "t_us"
        +]
      • addedInput schema / properties / a / type
        Added value: +"object"
      • removedInput schema / properties / b / $ref
        Removed value: -"#/$defs/FrameRef"
      • addedInput schema / properties / b / properties
        Added value: +{
        +  "layer_id": {
        +    "description": "Target VideoClip layer id.",
        +    "type": "string"
        +  },
        +  "t_us": {
        +    "description": "SOURCE-ABSOLUTE microseconds of the frame to sample (the space\n`analyze_clip`'s `keyframe_t_us` uses).",
        +    "type": "integer"
        +  }
        +}
      • addedInput schema / properties / b / required
        Added value: +[
        +  "layer_id",
        +  "t_us"
        +]
      • addedInput schema / properties / b / type
        Added value: +"object"
      • removedInput schema / title
        Removed value: -"CompareFramesArgs"
    • Removedcompositions_delete
    • Addedcorrect_caption_text
    • Addedcreate_checkpoint
    • Addedcreate_group
    • Addedcreate_link
    • Addeddelete_checkpoint
    • Addeddelete_composition
    • Addeddelete_effect
    • Addeddelete_keyframe
    • Removeddelete_layer
    • Addeddelete_layers
    • Addeddelete_link
    • Addeddelete_marker
    • Addeddelete_media
    • Changeddelete_motif3 fields changed
      • removedInput schema / $schema
        Removed value: -"http://json-schema.org/draft-07/schema#"
      • removedInput schema / description
        Removed value: -"Shared single-id arg for `get_motif_source` + `delete_motif`."
      • removedInput schema / title
        Removed value: -"MotifIdArgs"
    • Addeddelete_track
    • Addeddelete_transition
    • Changeddescribe_clip21 fields changed
      • removedInput schema / $schema
        Removed value: -"https://json-schema.org/draft/2020-12/schema"
      • removedInput schema / properties / backend / default
        Removed value: -null
      • changedInput schema / properties / backend / description
        Previous value: -"Optional STRICT backend override: `\"qwen3_vl\"` | `\"minicpm_v\"` |\n`\"byo_endpoint\"`. When set, that engine serves the request or the call\nerrors naming its exact gap — it never substitutes another engine, so an\nexplicit local choice can never leak frames over the network.\nWhen omitted, selection is preference then availability. Unknown → rejected."New value: +"Strict engine override: `\"qwen3_vl\"` | `\"minicpm_v\"` | `\"byo_endpoint\"`.\nThat engine serves or the call errors; nothing is substituted. Omitted:\nthe user's preferred engine, then availability."
      • changedInput schema / properties / backend / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • removedInput schema / properties / focus / default
        Removed value: -null
      • changedInput schema / properties / focus / description
        Previous value: -"Prompt focus: `\"general\"` or `\"shot-type\"` (biases `tags` toward shot\ntype / camera). Defaults to the app's Video-understanding setting, which\nthe host injects when this is omitted; with no host, `\"general\"`. Part of\nthe cache key."New value: +"`\"general\"` or `\"shot-type\"` (biases `tags` toward shot type / camera).\nDefault: the app's setting, else `\"general\"`. Cache key."
      • changedInput schema / properties / focus / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • removedInput schema / properties / fps / default
        Removed value: -null
      • changedInput schema / properties / fps / description
        Previous value: -"Frames sampled per second across the window. Higher = finer temporal\ndetail at more cost; capped so the frame set fits the model's context.\nDefaults to the app's Video-understanding setting, which the host injects\nwhen this is omitted; with no host, 1.0. Part of the cache key."New value: +"Frames sampled per second (higher = finer, costlier; capped to the\nmodel's context). Default: the app's setting, else 1.0. Cache key."
      • removedInput schema / properties / fps / format
        Removed value: -"double"
      • changedInput schema / properties / fps / type
        Previous value: -[
        -  "number",
        -  "null"
        -]New value: +"number"
      • removedInput schema / properties / language / default
        Removed value: -null
      • changedInput schema / properties / language / description
        Previous value: -"Language the `text` and `tags` come back in, as a BCP-47 tag\n(`\"en-US\"`, `\"zh-CN\"`, `\"ja\"`, …). Defaults to the app's UI language,\nwhich the host injects when this is omitted; with no host, `\"en-US\"`.\nPart of the cache key — a description in another language is a different\ndescription, not a translation of this one."New value: +"BCP-47 tag the `text` and `tags` come back in (`\"en-US\"`, `\"zh-CN\"`,\n`\"ja\"`). Default: the app's UI language. Cache key."
      • changedInput schema / properties / language / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • removedInput schema / properties / t_end_us / default
        Removed value: -null
      • removedInput schema / properties / t_end_us / format
        Removed value: -"int64"
      • changedInput schema / properties / t_end_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • removedInput schema / properties / t_start_us / default
        Removed value: -null
      • removedInput schema / properties / t_start_us / format
        Removed value: -"int64"
      • changedInput schema / properties / t_start_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • removedInput schema / title
        Removed value: -"DescribeClipArgs"
    • Removeddetach_marker
    • Changeddetect_pauses9 fields changed
      • removedInput schema / $schema
        Removed value: -"https://json-schema.org/draft/2020-12/schema"
      • changedInput schema / properties / bridge_us / description
        Previous value: -"A loud run shorter than this INSIDE a quiet run does not end the pause,\nin microseconds. Default 80000 (80ms) — long enough to swallow a click,\na cough or lip noise, short enough that no syllable fits. Must be ≥ 0\nand strictly below `min_pause_us`."New value: +"A loud run shorter than this (µs) inside a quiet run does not end the\npause. Default 80000 (80ms). Must be ≥ 0 and below `min_pause_us`."
      • removedInput schema / properties / bridge_us / format
        Removed value: -"int64"
      • changedInput schema / properties / bridge_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • removedInput schema / properties / min_pause_us / format
        Removed value: -"int64"
      • changedInput schema / properties / min_pause_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • removedInput schema / properties / threshold_amp / format
        Removed value: -"float"
      • changedInput schema / properties / threshold_amp / type
        Previous value: -[
        -  "number",
        -  "null"
        -]New value: +"number"
      • removedInput schema / title
        Removed value: -"DetectPausesArgs"
    • Changeddry_run2 fields changed
      • addedInput schema / properties / operations / description
        Added value: +"The edits to rehearse, in order."
      • changedInput schema / properties / operations / items / description
        Previous value: -"OperationSpec: {\"kind\": \"add_color_layer\" | \"add_video_layer\" | \"update_layer\" | \"update_layer_params\" | \"move_layer\" | \"split_layer\" | \"delete_layer\" | \"add_transition\", ...that tool's snake_case args (add_transition: the transition kind rides as \"transition_kind\" since \"kind\" names the operation, and it also takes \"placement\": \"overlap\" | \"extend\")}."New value: +"{ kind: <one of the supported tool names>, ...that tool's args }. For add_transition the transition kind rides as `transition_kind` (plus optional `placement`)."
    • Removedduplicate_layer
    • Changedend_agent_session1 field changed
      • addedInput schema / properties / force
        Added value: +{
        +  "description": "End another connection's session too. Default false.",
        +  "type": "boolean"
        +}
    • Addedexport_captions
    • Changedextract_clip_audio8 fields changed
      • removedInput schema / $schema
        Removed value: -"https://json-schema.org/draft/2020-12/schema"
      • removedInput schema / properties / t_end_us / default
        Removed value: -null
      • removedInput schema / properties / t_end_us / format
        Removed value: -"int64"
      • changedInput schema / properties / t_end_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • removedInput schema / properties / t_start_us / default
        Removed value: -null
      • removedInput schema / properties / t_start_us / format
        Removed value: -"int64"
      • changedInput schema / properties / t_start_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • removedInput schema / title
        Removed value: -"ExtractClipAudioArgs"
    • Removedfit_composition_to_layers
    • Changedget_motif_source3 fields changed
      • removedInput schema / $schema
        Removed value: -"http://json-schema.org/draft-07/schema#"
      • removedInput schema / description
        Removed value: -"Shared single-id arg for `get_motif_source` + `delete_motif`."
      • removedInput schema / title
        Removed value: -"MotifIdArgs"
    • Changedget_param_track3 fields changed
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / param_key / anyOf
        Added value: +[
        +  {
        +    "enum": [
        +      "x",
        +      "y",
        +      "path_progress",
        +      "scale_x",
        +      "scale_y",
        +      "rotation_deg",
        +      "anchor_x",
        +      "anchor_y",
        +      "opacity",
        +      "color",
        +      "gain_db",
        +      "pan"
        +    ]
        +  },
        +  {
        +    "pattern": "^effects\\[[0-9a-fA-F-]{36}\\]\\.params\\[[A-Za-z0-9_]+\\]$"
        +  }
        +]
      • addedInput schema / properties / param_key / description
        Added value: +"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."
    • Removedgroups_add_members
    • Removedgroups_create
    • Removedgroups_rename
    • Removedgroups_ungroup
    • Changedimport_media2 fields changed
      • removedInput schema / $schema
        Removed value: -"https://json-schema.org/draft/2020-12/schema"
      • removedInput schema / title
        Removed value: -"ImportMediaArgs"
    • Changedinstall_motif5 fields changed
      • removedInput schema / $schema
        Removed value: -"http://json-schema.org/draft-07/schema#"
      • changedInput schema / properties / mode / description
        Previous value: -"\"new\" (publish under the draft's own id) or \"update\" (republish over the draft's recorded target; fails if the draft has no target)."New value: +"\"new\" (publish under the draft's own id) or \"update\" (republish over `target_id`, else the draft's recorded target)."
      • addedInput schema / properties / mode / enum
        Added value: +[
        +  "new",
        +  "update"
        +]
      • addedInput schema / properties / target_id
        Added value: +{
        +  "description": "For mode \"update\": the installed Motif to republish over. Omit to use the target the draft recorded (`write_motif_draft { from }`).",
        +  "type": "string"
        +}
      • removedInput schema / title
        Removed value: -"InstallMotifArgs"
    • Addedjump_to
    • Removedlinks_add_members
    • Removedlinks_create
    • Removedlinks_dissolve
    • Removedlinks_remove_members
    • Removedlinks_rename
    • Changedlist_motifs4 fields changed
      • removedInput schema / $schema
        Removed value: -"http://json-schema.org/draft-07/schema#"
      • removedInput schema / description
        Removed value: -"Empty arg shape for tools that take no parameters. The dispatch table deserializes `{}` (or any object) into this; `schemars` advertises it as an empty object schema."
      • addedInput schema / properties
        Added value: +{}
      • removedInput schema / title
        Removed value: -"EmptyArgs"
    • Removedlock_history
    • Addedmerge_captions
    • Changedmove_effect3 fields changed
      • addedInput schema / properties / effect_id / description
        Added value: +"Effect id."
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / new_index / description
        Added value: +"Target position in the chain; 0 is applied first."
    • Changedmove_layer5 fields changed
      • addedInput schema / properties / escape_link / description
        Added value: +"Act on this layer alone, leaving its link partners in place. Default false."
      • changedInput schema / properties / escape_link / type
        Previous value: -[
        -  "boolean",
        -  "null"
        -]New value: +"boolean"
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / new_t_start_us / description
        Added value: +"New timeline start, µs."
      • addedInput schema / properties / new_track_id / description
        Added value: +"Destination track; the current one to move in time only."
    • Changedmove_layers_to_composition2 fields changed
      • changedInput schema / properties / to_track_id / description
        Previous value: -"Destination lane: a lane id (a locked or occupied one REFUSES), \"spawn\" for a fresh lane at the top of the z-stack, or omit for the per-source-track preference, which bounces."New value: +"A lane id (locked or occupied REFUSES), \"spawn\" for a fresh top lane, or omit to bounce to the nearest free lane."
      • changedInput schema / properties / to_track_id / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
    • Changedmove_track2 fields changed
      • addedInput schema / properties / new_position / description
        Added value: +"Target index in the stack; 0 is the bottom."
      • addedInput schema / properties / track_id / description
        Added value: +"Track id."
    • Changedpaste_layers4 fields changed
      • addedInput schema / properties / t_offset_us
        Added value: +{
        +  "description": "Start of the seed's clone relative to the seed's own start, so `t_offset_us` shifts every clone by that much. Mutually exclusive with `t_start_us`.",
        +  "type": "integer"
        +}
      • changedInput schema / properties / t_start_us / description
        Previous value: -"Start time of the seed's clone; the other clones keep their offsets from it."New value: +"Absolute start time of the seed's clone; the other clones keep their offsets from it. Mutually exclusive with `t_offset_us`."
      • changedInput schema / properties / target_track_id / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • changedInput schema / required
        Previous value: -[
        -  "layer_ids",
        -  "t_start_us"
        -]New value: +[
        +  "layer_ids"
        +]
    • Changedping3 fields changed
      • removedInput schema / $schema
        Removed value: -"https://json-schema.org/draft/2020-12/schema"
      • removedInput schema / description
        Removed value: -"Empty arg shape for tools that take no parameters. The dispatch table\ndeserializes `{}` (or any object) into this; `schemars` advertises it as an\nempty object schema."
      • removedInput schema / title
        Removed value: -"EmptyArgs"
    • Changedpreview_motif_draft14 fields changed
      • removedInput schema / $schema
        Removed value: -"http://json-schema.org/draft-07/schema#"
      • changedInput schema / properties / height / description
        Previous value: -"Optional render height (default = the motif's manifest height)."New value: +"Render height; default the motif's manifest height."
      • removedInput schema / properties / height / format
        Removed value: -"uint32"
      • changedInput schema / properties / height / minimum
        Previous value: -0New value: +1
      • changedInput schema / properties / height / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • changedInput schema / properties / props / description
        Previous value: -"Props (JSON object); `{}` uses the manifest defaults."New value: +"Props; omitted or `{}` uses the manifest defaults."
      • changedInput schema / properties / t_sec / description
        Previous value: -"Content time in seconds to render (e.g. 0 = first frame)."New value: +"Content time in seconds to render (0 = first frame)."
      • removedInput schema / properties / t_sec / format
        Removed value: -"double"
      • changedInput schema / properties / width / description
        Previous value: -"Optional render width (default = the motif's manifest width)."New value: +"Render width; default the motif's manifest width."
      • removedInput schema / properties / width / format
        Removed value: -"uint32"
      • changedInput schema / properties / width / minimum
        Previous value: -0New value: +1
      • changedInput schema / properties / width / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • changedInput schema / required
        Previous value: -[
        -  "id",
        -  "props",
        -  "t_sec"
        -]New value: +[
        +  "id",
        +  "t_sec"
        +]
      • removedInput schema / title
        Removed value: -"PreviewMotifDraftArgs"
    • Addedread_project
    • Removedremove_effect
    • Removedremove_keyframe
    • Removedremove_marker
    • Removedremove_media
    • Changedremove_pauses6 fields changed
      • removedInput schema / properties / min_pause_us / format
        Removed value: -"int64"
      • changedInput schema / properties / min_pause_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • changedInput schema / properties / pad_us / description
        Previous value: -"How much of each pause to KEEP on EACH side, in microseconds. Default 100000 (0.1 s), which is what stops a cut from clipping soft word onsets; pass 0 to erase each pause whole. Must be >= 0, and 2 x pad_us must be strictly less than min_pause_us or nothing would be cut."New value: +"Microseconds of each pause KEPT on each side. Default 100000; 0 erases each pause whole. Must satisfy 2 * pad_us < min_pause_us."
      • removedInput schema / properties / pad_us / format
        Removed value: -"int64"
      • changedInput schema / properties / pad_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • changedInput schema / properties / threshold_amp / type
        Previous value: -[
        -  "number",
        -  "null"
        -]New value: +"number"
    • Removedremove_track
    • Removedremove_transition
    • Addedrename_composition
    • Changedrename_track1 field changed
      • addedInput schema / properties / track_id / description
        Added value: +"Track id."
    • Changedrestore_checkpoint1 field changed
      • addedInput schema / properties / checkpoint_id / description
        Added value: +"Checkpoint id."
    • Addedrestyle_captions
    • Removedretime_keyframe
    • Changedripple_delete_gap3 fields changed
      • addedInput schema / properties / end_us / description
        Added value: +"Gap end (exclusive), timeline, µs."
      • addedInput schema / properties / start_us / description
        Added value: +"Gap start, timeline, µs."
      • addedInput schema / properties / track_id / description
        Added value: +"The track the gap is on."
    • Removedripple_delete_layers
    • Addedseparate_audio_to_new_track
    • Removedset_composition
    • Changedset_extrapolation5 fields changed
      • changedInput schema / properties / after / description
        Previous value: -"Hold = the end value (the clamp); Loop = repeat the cycle from the first key (a visible jump when first ≠ last — nothing bridges it); PingPong = odd cycles run backwards; Offset = each cycle adds the last-minus-first delta; Continue = carry the last segment's end velocity on as a line (zero after a Hold or procedural segment)."New value: +"After the last key. Hold = the end value; Loop = repeat the cycle; PingPong = alternate cycles reversed; Offset = each cycle adds the last-minus-first delta; Continue = carry the end velocity on as a line."
      • changedInput schema / properties / before / description
        Previous value: -"Hold = the end value (the clamp); Loop = repeat the cycle from the first key (a visible jump when first ≠ last — nothing bridges it); PingPong = odd cycles run backwards; Offset = each cycle adds the last-minus-first delta; Continue = carry the last segment's end velocity on as a line (zero after a Hold or procedural segment)."New value: +"Before the first key. Hold = the end value; Loop = repeat the cycle; PingPong = alternate cycles reversed; Offset = each cycle adds the last-minus-first delta; Continue = carry the end velocity on as a line."
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / param_key / anyOf
        Added value: +[
        +  {
        +    "enum": [
        +      "x",
        +      "y",
        +      "path_progress",
        +      "scale_x",
        +      "scale_y",
        +      "rotation_deg",
        +      "anchor_x",
        +      "anchor_y",
        +      "opacity",
        +      "color",
        +      "gain_db",
        +      "pan"
        +    ]
        +  },
        +  {
        +    "pattern": "^effects\\[[0-9a-fA-F-]{36}\\]\\.params\\[[A-Za-z0-9_]+\\]$"
        +  }
        +]
      • addedInput schema / properties / param_key / description
        Added value: +"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."
    • Addedset_history_lock
    • Changedset_keyframe7 fields changed
      • addedInput schema / properties / interp / properties / kind / description
        Added value: +"Easing kind of the segment leaving the key."
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / param_key / anyOf
        Added value: +[
        +  {
        +    "enum": [
        +      "x",
        +      "y",
        +      "path_progress",
        +      "scale_x",
        +      "scale_y",
        +      "rotation_deg",
        +      "anchor_x",
        +      "anchor_y",
        +      "opacity",
        +      "color",
        +      "gain_db",
        +      "pan"
        +    ]
        +  },
        +  {
        +    "pattern": "^effects\\[[0-9a-fA-F-]{36}\\]\\.params\\[[A-Za-z0-9_]+\\]$"
        +  }
        +]
      • addedInput schema / properties / param_key / description
        Added value: +"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."
      • addedInput schema / properties / t_us / description
        Added value: +"Key time, timeline-absolute, µs."
      • changedInput schema / properties / value / description
        Previous value: -"Typed by `param_key`: a number for every scalar param (x, y, path_progress, scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity, gain_db, pan, effect params); an {r,g,b,a} colour (integers 0..255) for \"color\" — the Text and Color layers' colour. Path mode rejects independent x/y writes; use path_progress (a fraction, not a percentage); XY mode has no path_progress. A mismatch is refused naming the type the param takes."New value: +"Typed by `param_key`: a number for scalar params (x, y, path_progress, scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity, gain_db, pan, effect params), {r,g,b,a} (0..255) for \"color\". Path mode takes path_progress (a fraction) instead of x/y."
      • removedInput schema / properties / value / oneOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "properties": {
        -      "a": {
        -        "type": "integer"
        -      },
        -      "b": {
        -        "type": "integer"
        -      },
        -      "g": {
        -        "type": "integer"
        -      },
        -      "r": {
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "r",
        -      "g",
        -      "b",
        -      "a"
        -    ],
        -    "type": "object"
        -  }
        -]
    • Removedset_keyframe_easing
    • Removedset_keyframe_tangents
    • Changedset_layers_enabled2 fields changed
      • addedInput schema / properties / enabled / description
        Added value: +"true shows, false hides — preview and export alike."
      • addedInput schema / properties / layer_ids / description
        Added value: +"The layers to show or hide."
    • Addedset_marker_anchor
    • Changedset_param_track22 fields changed
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / param_key / anyOf
        Added value: +[
        +  {
        +    "enum": [
        +      "x",
        +      "y",
        +      "path_progress",
        +      "scale_x",
        +      "scale_y",
        +      "rotation_deg",
        +      "anchor_x",
        +      "anchor_y",
        +      "opacity",
        +      "color",
        +      "gain_db",
        +      "pan"
        +    ]
        +  },
        +  {
        +    "pattern": "^effects\\[[0-9a-fA-F-]{36}\\]\\.params\\[[A-Za-z0-9_]+\\]$"
        +  }
        +]
      • addedInput schema / properties / param_key / description
        Added value: +"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."
      • changedInput schema / properties / track / description
        Previous value: -"An animation track: {\"mode\":\"Static\",\"value\":v} or {\"mode\":\"Keyframed\",\"value\":[{id, t_us, value, in, out, continuity, segment}, ...],\"extrapolate\":{before, after}}. Values are typed by `param_key` — a number, or {r,g,b,a} (integers 0..255) for \"color\". A segment's easing is the LEFT key's segment + out and the RIGHT key's in; each side's x is within [0, 1]. `extrapolate` defaults to Hold/Hold when omitted."New value: +"An animation track: {\"mode\":\"Static\",\"value\":v} or {\"mode\":\"Keyframed\",\"value\":[keyframes],\"extrapolate\":{before, after}} (Hold/Hold when omitted). Values are typed by `param_key` — a number, or {r,g,b,a} (integers 0..255) for \"color\"."
      • changedInput schema / properties / track / properties / extrapolate / description
        Previous value: -"What the track does outside its key range, per side (before the first key / after the last). The period is last.t − first.t; a single-key track never extrapolates."New value: +"What the track does outside its keys, per side: Hold | Loop | PingPong | Offset | Continue (see set_extrapolation)."
      • changedInput schema / properties / track / properties / extrapolate / properties / after / description
        Previous value: -"Hold = the end value (the clamp); Loop = repeat the cycle from the first key (a visible jump when first ≠ last — nothing bridges it); PingPong = odd cycles run backwards; Offset = each cycle adds the last-minus-first delta; Continue = carry the last segment's end velocity on as a line (zero after a Hold or procedural segment)."New value: +"After the last key."
      • changedInput schema / properties / track / properties / extrapolate / properties / before / description
        Previous value: -"Hold = the end value (the clamp); Loop = repeat the cycle from the first key (a visible jump when first ≠ last — nothing bridges it); PingPong = odd cycles run backwards; Offset = each cycle adds the last-minus-first delta; Continue = carry the last segment's end velocity on as a line (zero after a Hold or procedural segment)."New value: +"Before the first key."
      • addedInput schema / properties / track / properties / mode / description
        Added value: +"Static holds one value; Keyframed animates the key array."
      • addedInput schema / properties / track / properties / value / items / properties / id / description
        Added value: +"Key id: an existing one updates that key, a fresh one adds."
      • changedInput schema / properties / track / properties / value / items / properties / in / description
        Previous value: -"One side of a key: a control point in the owning segment's unit square (x = fraction of the segment's time span, y = fraction of its value span). `in` is the arriving cubic's second control point as stored (un-mirrored). mode \"Auto\" = re-solved on every write (monotone, no overshoot), \"Free\" = authored."New value: +"Arriving tangent."
      • addedInput schema / properties / track / properties / value / items / properties / in / properties / mode / description
        Added value: +"Auto: solved on every write. Free: as authored."
      • addedInput schema / properties / track / properties / value / items / properties / in / properties / x / description
        Added value: +"Fraction of the segment's time span, 0..1."
      • addedInput schema / properties / track / properties / value / items / properties / in / properties / y / description
        Added value: +"Fraction of the segment's value span; may overshoot."
      • changedInput schema / properties / track / properties / value / items / properties / out / description
        Previous value: -"One side of a key: a control point in the owning segment's unit square (x = fraction of the segment's time span, y = fraction of its value span). `in` is the arriving cubic's second control point as stored (un-mirrored). mode \"Auto\" = re-solved on every write (monotone, no overshoot), \"Free\" = authored."New value: +"Leaving tangent."
      • addedInput schema / properties / track / properties / value / items / properties / out / properties / mode / description
        Added value: +"Auto: solved on every write. Free: as authored."
      • addedInput schema / properties / track / properties / value / items / properties / out / properties / x / description
        Added value: +"Fraction of the segment's time span, 0..1."
      • addedInput schema / properties / track / properties / value / items / properties / out / properties / y / description
        Added value: +"Fraction of the segment's value span; may overshoot."
      • changedInput schema / properties / track / properties / value / items / properties / segment / description
        Previous value: -"Class of the segment LEAVING a key: {\"kind\":\"Spline\"} (its cubic is this key's out and the next key's in) | {\"kind\":\"Hold\"} | {\"kind\":\"Linear\"} | {\"kind\":\"Elastic\",\"dir\",amplitude?,period?} | {\"kind\":\"Bounce\",\"dir\"}."New value: +"Class of the segment LEAVING the key: Spline (reads the tangents) | Hold | Linear | Elastic (dir, amplitude?, period?) | Bounce (dir)."
      • addedInput schema / properties / track / properties / value / items / properties / segment / properties / kind / description
        Added value: +"Class of the segment leaving the key; only Spline reads the tangents."
      • addedInput schema / properties / track / properties / value / items / properties / t_us / description
        Added value: +"Key time, timeline-absolute, µs."
      • changedInput schema / properties / track / properties / value / items / properties / value / description
        Previous value: -"Typed by `param_key`: a number for every scalar param (x, y, path_progress, scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity, gain_db, pan, effect params); an {r,g,b,a} colour (integers 0..255) for \"color\" — the Text and Color layers' colour. Path mode rejects independent x/y writes; use path_progress (a fraction, not a percentage); XY mode has no path_progress. A mismatch is refused naming the type the param takes."New value: +"Typed by `param_key`: a number for scalar params (x, y, path_progress, scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity, gain_db, pan, effect params), {r,g,b,a} (0..255) for \"color\". Path mode takes path_progress (a fraction) instead of x/y."
      • removedInput schema / properties / track / properties / value / items / properties / value / oneOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "properties": {
        -      "a": {
        -        "type": "integer"
        -      },
        -      "b": {
        -        "type": "integer"
        -      },
        -      "g": {
        -        "type": "integer"
        -      },
        -      "r": {
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "r",
        -      "g",
        -      "b",
        -      "a"
        -    ],
        -    "type": "object"
        -  }
        -]
    • Changedset_position4 fields changed
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • changedInput schema / properties / position / description
        Previous value: -"{mode:XY,x,y} or {mode:Path,path:{nodes:[{id,point:{x,y},inHandle:{x,y},outHandle:{x,y},segment:Line|Cubic,tangentMode:Corner|Smooth|Auto}]},progress:Animated<number>}; Auto spatial handles are resolved from neighboring nodes; Smooth aligns handles; Corner leaves them independent. Progress 0..1 means distance along path; only Hold/Loop/PingPong extrapolation."New value: +"XY: `x`/`y` tracks in composition px. Path: `path.nodes` plus a `progress` track, 0..1 = distance along the path (Hold/Loop/PingPong extrapolation only)."
      • addedInput schema / properties / position / properties
        Added value: +{
        +  "mode": {
        +    "description": "XY: two scalar tracks. Path: a route plus a progress track.",
        +    "enum": [
        +      "XY",
        +      "Path"
        +    ],
        +    "type": "string"
        +  },
        +  "path": {
        +    "description": "Path mode: the route.",
        +    "properties": {
        +      "nodes": {
        +        "description": "1..128 nodes in route order.",
        +        "items": {
        +          "description": "One node of the route.",
        +          "properties": {
        +            "id": {
        +              "description": "Node id, unique and non-empty (yours to mint).",
        +              "type": "string"
        +            },
        +            "in_handle": {
        +              "description": "Arriving Bezier handle as a vector RELATIVE to `point`, composition px; {0,0} on a Line node.",
        +              "properties": {
        +                "x": {
        +                  "description": "x, composition px.",
        +                  "type": "number"
        +                },
        +                "y": {
        +                  "description": "y, composition px.",
        +                  "type": "number"
        +                }
        +              },
        +              "required": [
        +                "x",
        +                "y"
        +              ],
        +              "type": "object"
        +            },
        +            "out_handle": {
        +              "description": "Leaving Bezier handle as a vector RELATIVE to `point`, composition px; {0,0} on a Line node.",
        +              "properties": {
        +                "x": {
        +                  "description": "x, composition px.",
        +                  "type": "number"
        +                },
        +                "y": {
        +                  "description": "y, composition px.",
        +                  "type": "number"
        +                }
        +              },
        +              "required": [
        +                "x",
        +                "y"
        +              ],
        +              "type": "object"
        +            },
        +            "point": {
        +              "description": "Anchor point, composition px.",
        +              "properties": {
        +                "x": {
        +                  "description": "x, composition px.",
        +                  "type": "number"
        +                },
        +                "y": {
        +                  "description": "y, composition px.",
        +                  "type": "number"
        +                }
        +              },
        +              "required": [
        +                "x",
        +                "y"
        +              ],
        +              "type": "object"
        +            },
        +            "segment": {
        +              "description": "Span LEAVING this node: Line, or Cubic (reads the handles).",
        +              "enum": [
        +                "Line",
        +                "Cubic"
        +              ],
        +              "type": "string"
        +            },
        +            "tangent_mode": {
        +              "description": "Corner: handles independent. Smooth: aligned directions, own lengths. Auto: solved from the neighbours on write.",
        +              "enum": [
        +                "Corner",
        +                "Smooth",
        +                "Auto"
        +              ],
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "id",
        +            "point",
        +            "in_handle",
        +            "out_handle",
        +            "segment",
        +            "tangent_mode"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "nodes"
        +    ],
        +    "type": "object"
        +  },
        +  "progress": {
        +    "description": "Path mode: distance along the route, 0..1 (Hold / Loop / PingPong extrapolation only).",
        +    "properties": {
        +      "extrapolate": {
        +        "description": "What the track does outside its keys, per side: Hold | Loop | PingPong | Offset | Continue (see set_extrapolation).",
        +        "properties": {
        +          "after": {
        +            "description": "After the last key.",
        +            "enum": [
        +              "Hold",
        +              "Loop",
        +              "PingPong",
        +              "Offset",
        +              "Continue"
        +            ],
        +            "type": "string"
        +          },
        +          "before": {
        +            "description": "Before the first key.",
        +            "enum": [
        +              "Hold",
        +              "Loop",
        +              "PingPong",
        +              "Offset",
        +              "Continue"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "before",
        +          "after"
        +        ],
        +        "type": "object"
        +      },
        +      "mode": {
        +        "description": "Static holds one number; Keyframed animates the key array.",
        +        "enum": [
        +          "Static",
        +          "Keyframed"
        +        ],
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "Static: the number. Keyframed: the keys, in `set_param_track`'s key shape with layer-local `t_us`.",
        +        "type": [
        +          "number",
        +          "array"
        +        ]
        +      }
        +    },
        +    "required": [
        +      "mode",
        +      "value"
        +    ],
        +    "type": "object"
        +  },
        +  "x": {
        +    "description": "XY mode: the x track, composition px.",
        +    "properties": {
        +      "extrapolate": {
        +        "description": "What the track does outside its keys, per side: Hold | Loop | PingPong | Offset | Continue (see set_extrapolation).",
        +        "properties": {
        +          "after": {
        +            "description": "After the last key.",
        +            "enum": [
        +              "Hold",
        +              "Loop",
        +              "PingPong",
        +              "Offset",
        +              "Continue"
        +            ],
        +            "type": "string"
        +          },
        +          "before": {
        +            "description": "Before the first key.",
        +            "enum": [
        +              "Hold",
        +              "Loop",
        +              "PingPong",
        +              "Offset",
        +              "Continue"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "before",
        +          "after"
        +        ],
        +        "type": "object"
        +      },
        +      "mode": {
        +        "description": "Static holds one number; Keyframed animates the key array.",
        +        "enum": [
        +          "Static",
        +          "Keyframed"
        +        ],
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "Static: the number. Keyframed: the keys, in `set_param_track`'s key shape with layer-local `t_us`.",
        +        "type": [
        +          "number",
        +          "array"
        +        ]
        +      }
        +    },
        +    "required": [
        +      "mode",
        +      "value"
        +    ],
        +    "type": "object"
        +  },
        +  "y": {
        +    "description": "XY mode: the y track, composition px.",
        +    "properties": {
        +      "extrapolate": {
        +        "description": "What the track does outside its keys, per side: Hold | Loop | PingPong | Offset | Continue (see set_extrapolation).",
        +        "properties": {
        +          "after": {
        +            "description": "After the last key.",
        +            "enum": [
        +              "Hold",
        +              "Loop",
        +              "PingPong",
        +              "Offset",
        +              "Continue"
        +            ],
        +            "type": "string"
        +          },
        +          "before": {
        +            "description": "Before the first key.",
        +            "enum": [
        +              "Hold",
        +              "Loop",
        +              "PingPong",
        +              "Offset",
        +              "Continue"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "before",
        +          "after"
        +        ],
        +        "type": "object"
        +      },
        +      "mode": {
        +        "description": "Static holds one number; Keyframed animates the key array.",
        +        "enum": [
        +          "Static",
        +          "Keyframed"
        +        ],
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "Static: the number. Keyframed: the keys, in `set_param_track`'s key shape with layer-local `t_us`.",
        +        "type": [
        +          "number",
        +          "array"
        +        ]
        +      }
        +    },
        +    "required": [
        +      "mode",
        +      "value"
        +    ],
        +    "type": "object"
        +  }
        +}
      • addedInput schema / properties / position / required
        Added value: +[
        +  "mode"
        +]
    • Addedset_project_settings
    • Changedset_role_flags5 fields changed
      • addedInput schema / properties / muted / description
        Added value: +"Silence the bus. Omitted leaves it alone."
      • changedInput schema / properties / muted / type
        Previous value: -[
        -  "boolean",
        -  "null"
        -]New value: +"boolean"
      • addedInput schema / properties / role / description
        Added value: +"The mixing bus."
      • addedInput schema / properties / solo / description
        Added value: +"Play this bus alone. Omitted leaves it alone."
      • changedInput schema / properties / solo / type
        Previous value: -[
        -  "boolean",
        -  "null"
        -]New value: +"boolean"
    • Changedset_role_gain2 fields changed
      • addedInput schema / properties / gain_db / description
        Added value: +"Bus gain, dB; 0 = unity."
      • addedInput schema / properties / role / description
        Added value: +"The mixing bus."
    • Changedset_scale_linked2 fields changed
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / linked / description
        Added value: +"true links scale_y to scale_x; false clears the flag only."
    • Addedset_track_flags
    • Addedshift_layers
    • Changedsmooth_keyframes5 fields changed
      • addedInput schema / properties / keyframe_id / description
        Added value: +"One key to smooth; omit for every key of the track."
      • changedInput schema / properties / keyframe_id / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / param_key / anyOf
        Added value: +[
        +  {
        +    "enum": [
        +      "x",
        +      "y",
        +      "path_progress",
        +      "scale_x",
        +      "scale_y",
        +      "rotation_deg",
        +      "anchor_x",
        +      "anchor_y",
        +      "opacity",
        +      "color",
        +      "gain_db",
        +      "pan"
        +    ]
        +  },
        +  {
        +    "pattern": "^effects\\[[0-9a-fA-F-]{36}\\]\\.params\\[[A-Za-z0-9_]+\\]$"
        +  }
        +]
      • addedInput schema / properties / param_key / description
        Added value: +"Animatable param: visual kinds x, y (path_progress in Path mode), scale_x, scale_y, rotation_deg, anchor_x, anchor_y, opacity; Text and Color color; Audio gain_db, pan; or an effect param as effects[<effect_id>].params[<key>]."
    • Changedsplit_layer4 fields changed
      • addedInput schema / properties / at_t_us / description
        Added value: +"Cut point, timeline; strictly inside the layer, µs."
      • addedInput schema / properties / escape_link / description
        Added value: +"Act on this layer alone, leaving its link partners in place. Default false."
      • changedInput schema / properties / escape_link / type
        Previous value: -[
        -  "boolean",
        -  "null"
        -]New value: +"boolean"
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
    • Changedsynthesize_speech10 fields changed
      • removedInput schema / $schema
        Removed value: -"https://json-schema.org/draft/2020-12/schema"
      • removedInput schema / properties / speed / default
        Removed value: -null
      • removedInput schema / properties / speed / format
        Removed value: -"float"
      • changedInput schema / properties / speed / type
        Previous value: -[
        -  "number",
        -  "null"
        -]New value: +"number"
      • removedInput schema / properties / t_start_us / default
        Removed value: -null
      • removedInput schema / properties / t_start_us / format
        Removed value: -"int64"
      • changedInput schema / properties / t_start_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • removedInput schema / properties / target_track_id / default
        Removed value: -null
      • changedInput schema / properties / target_track_id / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • removedInput schema / title
        Removed value: -"SynthesizeSpeechArgs"
    • Changedtranscribe_clip16 fields changed
      • removedInput schema / $schema
        Removed value: -"https://json-schema.org/draft/2020-12/schema"
      • removedInput schema / properties / backend / default
        Removed value: -null
      • changedInput schema / properties / backend / description
        Previous value: -"Optional STRICT backend override: `\"openai\"` | `\"whisper_cpp\"` |\n`\"funasr\"`. When set, that engine serves the request or the call errors\nnaming its exact gap (missing key / binary / model) — it never\nsubstitutes another engine, so an explicit local choice can never leak\naudio to a cloud provider. When omitted, the resolver walks the user's\npreference then availability. An unknown value is rejected."New value: +"Strict engine override: `\"openai\"` | `\"whisper_cpp\"` | `\"funasr\"`.\nThat engine serves or the call errors; nothing is substituted. Omitted:\nthe user's preferred engine, then availability."
      • changedInput schema / properties / backend / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • removedInput schema / properties / language / default
        Removed value: -null
      • changedInput schema / properties / language / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • removedInput schema / properties / t_end_us / default
        Removed value: -null
      • removedInput schema / properties / t_end_us / format
        Removed value: -"int64"
      • changedInput schema / properties / t_end_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • removedInput schema / properties / t_start_us / default
        Removed value: -null
      • removedInput schema / properties / t_start_us / format
        Removed value: -"int64"
      • changedInput schema / properties / t_start_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • removedInput schema / properties / word_timestamps / default
        Removed value: -null
      • changedInput schema / properties / word_timestamps / description
        Previous value: -"Request exact per-word timestamps when the chosen backend can emit them\n(whisper.cpp → `-ojf`). Defaults to `true` — the backend's best\nprecision, at no extra engine cost; pass `false` to force the SRT-style\n(interpolated) output instead. OpenAI Whisper is SRT-only and ignores\nit either way; check `word_timing` in the result for what you got."New value: +"Ask for exact per-word times where the engine can emit them. Default\ntrue; `false` forces SRT-style interpolated words. The result's\n`word_timing` reports what you got."
      • changedInput schema / properties / word_timestamps / type
        Previous value: -[
        -  "boolean",
        -  "null"
        -]New value: +"boolean"
      • removedInput schema / title
        Removed value: -"TranscribeClipArgs"
    • Changedtranslate_path3 fields changed
      • addedInput schema / properties / dx / description
        Added value: +"Shift in x, composition px."
      • addedInput schema / properties / dy / description
        Added value: +"Shift in y, composition px."
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
    • Changedtrim_layer6 fields changed
      • addedInput schema / properties / edge / description
        Added value: +"Which edge moves: in = t_start_us, out = t_end_us."
      • addedInput schema / properties / edge / enum
        Added value: +[
        +  "in",
        +  "out"
        +]
      • addedInput schema / properties / escape_link / description
        Added value: +"Act on this layer alone, leaving its link partners in place. Default false."
      • changedInput schema / properties / escape_link / type
        Previous value: -[
        -  "boolean",
        -  "null"
        -]New value: +"boolean"
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / new_t_us / description
        Added value: +"Where the edge lands, timeline, µs."
    • Addedungroup_layer
    • Removedunlock_history
    • Addedupdate_composition
    • Changedupdate_effect7 fields changed
      • addedInput schema / properties / effect_id / description
        Added value: +"Effect id."
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / patch / properties / enabled / description
        Added value: +"false bypasses the effect, true applies it."
      • changedInput schema / properties / patch / properties / enabled / type
        Previous value: -[
        -  "boolean",
        -  "null"
        -]New value: +"boolean"
      • removedInput schema / properties / patch / properties / params / additionalProperties / anyOf
        Removed value: -[
        -  {
        -    "description": "An animation track: {\"mode\":\"Static\",\"value\":v} or {\"mode\":\"Keyframed\",\"value\":[{id, t_us, value, in, out, continuity, segment}, ...],\"extrapolate\":{before, after}}. Values are numbers. A segment's easing is the LEFT key's segment + out and the RIGHT key's in; each side's x is within [0, 1]. `extrapolate` defaults to Hold/Hold when omitted.",
        -    "properties": {
        -      "extrapolate": {
        -        "description": "What the track does outside its key range, per side (before the first key / after the last). The period is last.t − first.t; a single-key track never extrapolates.",
        -        "properties": {
        -          "after": {
        -            "description": "Hold = the end value (the clamp); Loop = repeat the cycle from the first key (a visible jump when first ≠ last — nothing bridges it); PingPong = odd cycles run backwards; Offset = each cycle adds the last-minus-first delta; Continue = carry the last segment's end velocity on as a line (zero after a Hold or procedural segment).",
        -            "enum": [
        -              "Hold",
        -              "Loop",
        -              "PingPong",
        -              "Offset",
        -              "Continue"
        -            ],
        -            "type": "string"
        -          },
        -          "before": {
        -            "description": "Hold = the end value (the clamp); Loop = repeat the cycle from the first key (a visible jump when first ≠ last — nothing bridges it); PingPong = odd cycles run backwards; Offset = each cycle adds the last-minus-first delta; Continue = carry the last segment's end velocity on as a line (zero after a Hold or procedural segment).",
        -            "enum": [
        -              "Hold",
        -              "Loop",
        -              "PingPong",
        -              "Offset",
        -              "Continue"
        -            ],
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "before",
        -          "after"
        -        ],
        -        "type": "object"
        -      },
        -      "mode": {
        -        "enum": [
        -          "Static",
        -          "Keyframed"
        -        ],
        -        "type": "string"
        -      },
        -      "value": {
        -        "description": "Static: the held value (numbers). Keyframed: the keyframe array.",
        -        "items": {
        -          "properties": {
        -            "continuity": {
        -              "description": "With both sides Free: Smooth keeps their slopes locked equal on write, Broken lets them differ.",
        -              "enum": [
        -                "Smooth",
        -                "Broken"
        -              ],
        -              "type": "string"
        -            },
        -            "id": {
        -              "type": "string"
        -            },
        -            "in": {
        -              "description": "One side of a key: a control point in the owning segment's unit square (x = fraction of the segment's time span, y = fraction of its value span). `in` is the arriving cubic's second control point as stored (un-mirrored). mode \"Auto\" = re-solved on every write (monotone, no overshoot), \"Free\" = authored.",
        -              "properties": {
        -                "mode": {
        -                  "enum": [
        -                    "Auto",
        -                    "Free"
        -                  ],
        -                  "type": "string"
        -                },
        -                "x": {
        -                  "type": "number"
        -                },
        -                "y": {
        -                  "type": "number"
        -                }
        -              },
        -              "required": [
        -                "x",
        -                "y",
        -                "mode"
        -              ],
        -              "type": "object"
        -            },
        -            "out": {
        -              "description": "One side of a key: a control point in the owning segment's unit square (x = fraction of the segment's time span, y = fraction of its value span). `in` is the arriving cubic's second control point as stored (un-mirrored). mode \"Auto\" = re-solved on every write (monotone, no overshoot), \"Free\" = authored.",
        -              "properties": {
        -                "mode": {
        -                  "enum": [
        -                    "Auto",
        -                    "Free"
        -                  ],
        -                  "type": "string"
        -                },
        -                "x": {
        -                  "type": "number"
        -                },
        -                "y": {
        -                  "type": "number"
        -                }
        -              },
        -              "required": [
        -                "x",
        -                "y",
        -                "mode"
        -              ],
        -              "type": "object"
        -            },
        -            "segment": {
        -              "description": "Class of the segment LEAVING a key: {\"kind\":\"Spline\"} (its cubic is this key's out and the next key's in) | {\"kind\":\"Hold\"} | {\"kind\":\"Linear\"} | {\"kind\":\"Elastic\",\"dir\",amplitude?,period?} | {\"kind\":\"Bounce\",\"dir\"}.",
        -              "properties": {
        -                "amplitude": {
        -                  "description": "Elastic only: overshoot amplitude, >= 1. Omit for the default 1.",
        -                  "type": "number"
        -                },
        -                "dir": {
        -                  "description": "Elastic/Bounce only: easing direction.",
        -                  "enum": [
        -                    "In",
        -                    "Out",
        -                    "InOut"
        -                  ],
        -                  "type": "string"
        -                },
        -                "kind": {
        -                  "enum": [
        -                    "Spline",
        -                    "Hold",
        -                    "Linear",
        -                    "Elastic",
        -                    "Bounce"
        -                  ],
        -                  "type": "string"
        -                },
        -                "period": {
        -                  "description": "Elastic only: oscillation period, > 0. Omit for the default 0.3.",
        -                  "type": "number"
        -                }
        -              },
        -              "required": [
        -                "kind"
        -              ],
        -              "type": "object"
        -            },
        -            "t_us": {
        -              "type": "integer"
        -            },
        -            "value": {
        -              "type": "number"
        -            }
        -          },
        -          "required": [
        -            "id",
        -            "t_us",
        -            "value",
        -            "in",
        -            "out",
        -            "continuity",
        -            "segment"
        -          ],
        -          "type": "object"
        -        },
        -        "type": [
        -          "number",
        -          "array"
        -        ]
        -      }
        -    },
        -    "required": [
        -      "mode",
        -      "value"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedInput schema / properties / patch / properties / params / additionalProperties / description
        Added value: +"An AnimTrack — {\"mode\":\"Static\",\"value\":<number>} for a v1 param — or null to unset the key. Keyframe a visual effect param through set_keyframe instead."
      • addedInput schema / properties / patch / properties / params / additionalProperties / type
        Added value: +[
        +  "object",
        +  "null"
        +]
    • Addedupdate_keyframe
    • Changedupdate_layer7 fields changed
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • addedInput schema / properties / patch / description
        Added value: +"Envelope patch; only the fields you set apply."
      • removedInput schema / properties / patch / properties / enabled
        Removed value: -{
        -  "type": "boolean"
        -}
      • addedInput schema / properties / patch / properties / label / description
        Added value: +"Display name; null clears it."
      • addedInput schema / properties / patch / properties / locked / description
        Added value: +"Refuse edits to this layer."
      • addedInput schema / properties / patch / properties / t_end_us / description
        Added value: +"New timeline end (exclusive), µs (snapped and echoed)."
      • addedInput schema / properties / patch / properties / t_start_us / description
        Added value: +"New timeline start, µs (snapped to the grid and echoed)."
    • Changedupdate_layer_params36 fields changed
      • addedInput schema / properties / layer_id / description
        Added value: +"Layer id."
      • changedInput schema / properties / patch / description
        Previous value: -"Kind-tagged params patch. Must include `kind` matching the layer's kind ('Text' | 'VideoClip' | 'ImageOverlay' | 'Color' | 'Audio'). Only fields you include are applied."New value: +"Kind-tagged patch: `kind` must match the layer's, and only that kind's fields are accepted (one variant per kind); a key outside the set is refused naming it."
      • addedInput schema / properties / patch / oneOf
        Added value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "align": {
        +        "description": "Horizontal alignment inside the box.",
        +        "enum": [
        +          "Left",
        +          "Center",
        +          "Right"
        +        ],
        +        "type": "string"
        +      },
        +      "anchor_x": {
        +        "description": "Pivot x, fraction of the width (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Pivot y, fraction of the height (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "box_h": {
        +        "description": "Layout box height, composition px, local (before `scale`). null = auto height. Refused when the layer has no box_w and the patch supplies none.",
        +        "exclusiveMinimum": 0,
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "box_w": {
        +        "description": "Layout box width, composition px, local (before `scale`). null = auto width.",
        +        "exclusiveMinimum": 0,
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "color": {
        +        "description": "Fill colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "content": {
        +        "description": "The text; newlines are honoured.",
        +        "type": "string"
        +      },
        +      "font_family": {
        +        "description": "Font family name.",
        +        "type": "string"
        +      },
        +      "font_size_px": {
        +        "description": "Font size, composition px.",
        +        "type": "number"
        +      },
        +      "font_weight": {
        +        "description": "CSS weight 100..900; 400 regular, 700 bold.",
        +        "type": "integer"
        +      },
        +      "italic": {
        +        "description": "Italic face.",
        +        "type": "boolean"
        +      },
        +      "kind": {
        +        "const": "Text",
        +        "description": "Fields of a Text layer."
        +      },
        +      "letter_spacing": {
        +        "description": "Letter spacing, px.",
        +        "type": "number"
        +      },
        +      "line_height": {
        +        "description": "Line height, px; 0 = the font metrics.",
        +        "type": "number"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "outline_color": {
        +        "description": "Stroke colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "outline_width": {
        +        "description": "Stroke width, composition px; 0 removes the outline.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "shadow": {
        +        "description": "Drop shadow, or null for none.",
        +        "properties": {
        +          "blur": {
        +            "description": "Blur radius, composition px; 0 is hard-edged.",
        +            "minimum": 0,
        +            "type": "number"
        +          },
        +          "color": {
        +            "description": "Shadow colour.",
        +            "properties": {
        +              "a": {
        +                "description": "Alpha 0..255; 255 opaque.",
        +                "type": "integer"
        +              },
        +              "b": {
        +                "description": "Blue 0..255.",
        +                "type": "integer"
        +              },
        +              "g": {
        +                "description": "Green 0..255.",
        +                "type": "integer"
        +              },
        +              "r": {
        +                "description": "Red 0..255.",
        +                "type": "integer"
        +              }
        +            },
        +            "required": [
        +              "r",
        +              "g",
        +              "b",
        +              "a"
        +            ],
        +            "type": "object"
        +          },
        +          "offset_x": {
        +            "description": "Horizontal offset, composition px.",
        +            "type": "number"
        +          },
        +          "offset_y": {
        +            "description": "Vertical offset, composition px.",
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "color",
        +          "offset_x",
        +          "offset_y",
        +          "blur"
        +        ],
        +        "type": [
        +          "object",
        +          "null"
        +        ]
        +      },
        +      "valign": {
        +        "description": "Vertical alignment inside the box.",
        +        "enum": [
        +          "Top",
        +          "Middle",
        +          "Bottom"
        +        ],
        +        "type": "string"
        +      },
        +      "x": {
        +        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "Anchor y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Pivot x, fraction of the width (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Pivot y, fraction of the height (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "flip_h": {
        +        "description": "Mirror horizontally.",
        +        "type": "boolean"
        +      },
        +      "flip_v": {
        +        "description": "Mirror vertically.",
        +        "type": "boolean"
        +      },
        +      "kind": {
        +        "const": "VideoClip",
        +        "description": "Fields of a VideoClip layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "speed": {
        +        "description": "Playback rate; 1 = normal.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "src_out_us": {
        +        "description": "Source out point (exclusive), µs.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "Anchor y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Pivot x, fraction of the width (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Pivot y, fraction of the height (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "kind": {
        +        "const": "ImageOverlay",
        +        "description": "Fields of a ImageOverlay layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "x": {
        +        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "Anchor y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Pivot x, fraction of the width (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Pivot y, fraction of the height (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "kind": {
        +        "const": "Motif",
        +        "description": "Fields of a Motif layer."
        +      },
        +      "motif_id": {
        +        "description": "Motif id from list_motifs.",
        +        "type": "string"
        +      },
        +      "motif_version": {
        +        "description": "Motif version to bind.",
        +        "type": "integer"
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "props": {
        +        "description": "Motif props, matched against its props_schema.",
        +        "type": "object"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "Anchor y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "color": {
        +        "description": "Fill colour.",
        +        "properties": {
        +          "a": {
        +            "description": "Alpha 0..255; 255 opaque.",
        +            "type": "integer"
        +          },
        +          "b": {
        +            "description": "Blue 0..255.",
        +            "type": "integer"
        +          },
        +          "g": {
        +            "description": "Green 0..255.",
        +            "type": "integer"
        +          },
        +          "r": {
        +            "description": "Red 0..255.",
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "r",
        +          "g",
        +          "b",
        +          "a"
        +        ],
        +        "type": "object"
        +      },
        +      "height": {
        +        "description": "Colour block height, px.",
        +        "type": "integer"
        +      },
        +      "kind": {
        +        "const": "Color",
        +        "description": "Fields of a Color layer."
        +      },
        +      "width": {
        +        "description": "Colour block width, px.",
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "fade_in_us": {
        +        "description": "Fade-in length, µs.",
        +        "type": "integer"
        +      },
        +      "fade_out_us": {
        +        "description": "Fade-out length, µs.",
        +        "type": "integer"
        +      },
        +      "gain_db": {
        +        "description": "Gain, dB; written Static, replacing any keyframes.",
        +        "type": "number"
        +      },
        +      "kind": {
        +        "const": "Audio",
        +        "description": "Fields of a Audio layer."
        +      },
        +      "mute": {
        +        "description": "Silence the clip.",
        +        "type": "boolean"
        +      },
        +      "pan": {
        +        "description": "Stereo pan, -1 (left) .. 1 (right); written Static.",
        +        "type": "number"
        +      },
        +      "role": {
        +        "description": "Mixing bus.",
        +        "enum": [
        +          "dialogue",
        +          "music",
        +          "sfx",
        +          "voiceover"
        +        ],
        +        "type": "string"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "src_out_us": {
        +        "description": "Source out point (exclusive), µs.",
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "anchor_x": {
        +        "description": "Pivot x, fraction of the width (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "anchor_y": {
        +        "description": "Pivot y, fraction of the height (0.5 = centre).",
        +        "type": "number"
        +      },
        +      "blend_mode": {
        +        "description": "How the Group composites over what lies below.",
        +        "enum": [
        +          "Normal",
        +          "Multiply",
        +          "Screen",
        +          "Overlay",
        +          "Darken",
        +          "Lighten",
        +          "Add",
        +          "Difference"
        +        ],
        +        "type": "string"
        +      },
        +      "kind": {
        +        "const": "CompositionRef",
        +        "description": "Fields of a CompositionRef layer."
        +      },
        +      "opacity": {
        +        "description": "Opacity 0..1.",
        +        "type": "number"
        +      },
        +      "rotation_deg": {
        +        "description": "Rotation, degrees clockwise.",
        +        "type": "number"
        +      },
        +      "scale_x": {
        +        "description": "Horizontal scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "scale_y": {
        +        "description": "Vertical scale factor; 1 = native size.",
        +        "type": "number"
        +      },
        +      "src_in_us": {
        +        "description": "Source in point, µs.",
        +        "type": "integer"
        +      },
        +      "src_out_us": {
        +        "description": "Source out point (exclusive), µs.",
        +        "type": "integer"
        +      },
        +      "x": {
        +        "description": "Anchor x, composition px (refused in Path mode: set_position / translate_path).",
        +        "type": "number"
        +      },
        +      "y": {
        +        "description": "Anchor y, composition px (refused in Path mode).",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "kind"
        +    ]
        +  }
        +]
      • removedInput schema / properties / patch / properties / align
        Removed value: -{
        -  "enum": [
        -    "Left",
        -    "Center",
        -    "Right"
        -  ],
        -  "type": "string"
        -}
      • removedInput schema / properties / patch / properties / box_h
        Removed value: -{
        -  "description": "Layout box height in composition px, local (before `scale`). null = auto height. Refused when the layer has no box_w and the patch does not supply one.",
        -  "exclusiveMinimum": 0,
        -  "type": [
        -    "number",
        -    "null"
        -  ]
        -}
      • removedInput schema / properties / patch / properties / box_w
        Removed value: -{
        -  "description": "Layout box width in composition px, local (before `scale`). null = auto width.",
        -  "exclusiveMinimum": 0,
        -  "type": [
        -    "number",
        -    "null"
        -  ]
        -}
      • removedInput schema / properties / patch / properties / color
        Removed value: -{
        -  "properties": {
        -    "a": {
        -      "type": "integer"
        -    },
        -    "b": {
        -      "type": "integer"
        -    },
        -    "g": {
        -      "type": "integer"
        -    },
        -    "r": {
        -      "type": "integer"
        -    }
        -  },
        -  "required": [
        -    "r",
        -    "g",
        -    "b",
        -    "a"
        -  ],
        -  "type": "object"
        -}
      • removedInput schema / properties / patch / properties / content
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / patch / properties / fade_in_us
        Removed value: -{
        -  "type": "integer"
        -}
      • removedInput schema / properties / patch / properties / fade_out_us
        Removed value: -{
        -  "type": "integer"
        -}
      • removedInput schema / properties / patch / properties / flip_h
        Removed value: -{
        -  "type": "boolean"
        -}
      • removedInput schema / properties / patch / properties / flip_v
        Removed value: -{
        -  "type": "boolean"
        -}
      • removedInput schema / properties / patch / properties / font_family
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / patch / properties / font_size_px
        Removed value: -{
        -  "type": "number"
        -}
      • removedInput schema / properties / patch / properties / gain_db
        Removed value: -{
        -  "type": "number"
        -}
      • removedInput schema / properties / patch / properties / height
        Removed value: -{
        -  "type": "integer"
        -}
      • addedInput schema / properties / patch / properties / kind / description
        Added value: +"The layer's params.kind, as project://tracks reports it."
      • changedInput schema / properties / patch / properties / kind / enum
        Previous value: -[
        -  "Text",
        -  "VideoClip",
        -  "ImageOverlay",
        -  "Color",
        -  "Audio"
        -]New value: +[
        +  "Text",
        +  "VideoClip",
        +  "ImageOverlay",
        +  "Motif",
        +  "Color",
        +  "Audio",
        +  "CompositionRef"
        +]
      • removedInput schema / properties / patch / properties / letter_spacing
        Removed value: -{
        -  "type": "number"
        -}
      • removedInput schema / properties / patch / properties / line_height
        Removed value: -{
        -  "type": "number"
        -}
      • removedInput schema / properties / patch / properties / motif_id
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / patch / properties / motif_version
        Removed value: -{
        -  "type": "integer"
        -}
      • removedInput schema / properties / patch / properties / mute
        Removed value: -{
        -  "type": "boolean"
        -}
      • removedInput schema / properties / patch / properties / opacity
        Removed value: -{
        -  "type": "number"
        -}
      • removedInput schema / properties / patch / properties / pan
        Removed value: -{
        -  "type": "number"
        -}
      • removedInput schema / properties / patch / properties / props
        Removed value: -{
        -  "type": "object"
        -}
      • removedInput schema / properties / patch / properties / role
        Removed value: -{
        -  "enum": [
        -    "dialogue",
        -    "music",
        -    "sfx",
        -    "voiceover"
        -  ],
        -  "type": "string"
        -}
      • removedInput schema / properties / patch / properties / scale_x
        Removed value: -{
        -  "type": "number"
        -}
      • removedInput schema / properties / patch / properties / scale_y
        Removed value: -{
        -  "type": "number"
        -}
      • removedInput schema / properties / patch / properties / speed
        Removed value: -{
        -  "type": "number"
        -}
      • removedInput schema / properties / patch / properties / src_in_us
        Removed value: -{
        -  "type": "integer"
        -}
      • removedInput schema / properties / patch / properties / src_out_us
        Removed value: -{
        -  "type": "integer"
        -}
      • removedInput schema / properties / patch / properties / valign
        Removed value: -{
        -  "enum": [
        -    "Top",
        -    "Middle",
        -    "Bottom"
        -  ],
        -  "type": "string"
        -}
      • removedInput schema / properties / patch / properties / width
        Removed value: -{
        -  "type": "integer"
        -}
      • removedInput schema / properties / patch / properties / x
        Removed value: -{
        -  "type": "number"
        -}
      • removedInput schema / properties / patch / properties / y
        Removed value: -{
        -  "type": "number"
        -}
    • Addedupdate_link
    • Changedupdate_marker11 fields changed
      • addedInput schema / properties / marker_id / description
        Added value: +"Marker id."
      • changedInput schema / properties / patch / description
        Previous value: -"Marker patch; only fields you set are applied. `end_t_us` can be set, never cleared (clear = remove + re-add). A marker's anchor is not patchable here — attach_marker and detach_marker set and clear it, and add_marker can create a marker already carrying one. Read `anchor_layer` on a marker to see whether it follows one."New value: +"Marker patch; only fields you set apply. `end_t_us` can be set, never cleared (remove + re-add). The anchor is `set_marker_anchor`'s, not patchable here."
      • addedInput schema / properties / patch / properties / color / description
        Added value: +"Marker colour."
      • addedInput schema / properties / patch / properties / color / properties / a / description
        Added value: +"Alpha 0..255; 255 opaque."
      • addedInput schema / properties / patch / properties / color / properties / b / description
        Added value: +"Blue 0..255."
      • addedInput schema / properties / patch / properties / color / properties / g / description
        Added value: +"Green 0..255."
      • addedInput schema / properties / patch / properties / color / properties / r / description
        Added value: +"Red 0..255."
      • addedInput schema / properties / patch / properties / end_t_us / description
        Added value: +"Region end, timeline; turns a point marker into a region, µs."
      • changedInput schema / properties / patch / properties / end_t_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
      • addedInput schema / properties / patch / properties / t_us / description
        Added value: +"New time, timeline, µs."
      • changedInput schema / properties / patch / properties / t_us / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +"integer"
    • Changedupdate_transition5 fields changed
      • addedInput schema / properties / direction / description
        Added value: +"Motion direction; rides with `kind` (Wipe / Slide need it, Crossfade refuses it)."
      • addedInput schema / properties / duration_us / description
        Added value: +"New transition length, µs."
      • changedInput schema / properties / extended_us / description
        Previous value: -"Explicit borrowed-tail target in µs, at most duration_us. Omit to keep trimmed ranges sacred: growth never borrows, shrink returns the borrow first. Negative = deliberate tail trim of the outgoing layer: all borrow returns, then its real content is trimmed by the remainder (the exit frame moves left; stored value becomes 0)."New value: +"Borrowed-tail target in µs, at most duration_us. Omit to preserve trimmed ranges; negative = deliberate tail trim of real content."
      • addedInput schema / properties / kind / description
        Added value: +"New kind; send `direction` with Wipe / Slide."
      • addedInput schema / properties / transition_id / description
        Added value: +"Transition id."
    • Changedwrite_motif_draft4 fields changed
      • removedInput schema / $schema
        Removed value: -"http://json-schema.org/draft-07/schema#"
      • changedInput schema / properties / from / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • changedInput schema / properties / manifest / description
        Previous value: -"The manifest as a JSON object (its `id`/`version` are ignored — app-assigned). Shape: `{ name, size:[w,h], default_duration_s, props_schema, ... }` — inspect a built-in via `get_motif_source` for an exact example. Rejected if malformed."New value: +"The manifest object (`id`/`version` are app-assigned and ignored): `{ name, size: [w, h], default_duration_s, props_schema, ... }` — copy a built-in's from `get_motif_source`."
      • removedInput schema / title
        Removed value: -"WriteMotifDraftArgs"
  11. 91 tool updatesv0.1.8
    • First observedadd_color_layer
    • First observedadd_effect
    • First observedadd_group_layer
    • First observedadd_marker
    • First observedadd_motif
    • First observedadd_track
    • First observedadd_transition
    • First observedadd_video_layer
    • First observedanalyze_clip
    • First observedapply_subtitles
    • First observedattach_marker
    • First observedauto_split_by_shot
    • First observedbegin_agent_session
    • First observedcheckpoint
    • First observedclear_keyframes
    • First observedcompare_frames
    • First observedcompositions_delete
    • First observeddelete_layer
    • First observeddelete_motif
    • First observeddescribe_clip
    • First observeddetach_marker
    • First observeddetect_pauses
    • First observeddry_run
    • First observedduplicate_layer
    • First observedend_agent_session
    • First observedextract_clip_audio
    • First observedfit_composition_to_layers
    • First observedget_motif_source
    • First observedget_param_track
    • First observedgroups_add_members
    • First observedgroups_create
    • First observedgroups_rename
    • First observedgroups_ungroup
    • First observedimport_media
    • First observedinstall_motif
    • First observedlaunch_weftcut
    • First observedlinks_add_members
    • First observedlinks_create
    • First observedlinks_dissolve
    • First observedlinks_remove_members
    • First observedlinks_rename
    • First observedlist_checkpoints
    • First observedlist_motifs
    • First observedlock_history
    • First observedmove_effect
    • First observedmove_layer
    • First observedmove_layers_to_composition
    • First observedmove_track
    • First observedpaste_layers
    • First observedping
    • First observedpreview_motif_draft
    • First observedredo
    • First observedremove_effect
    • First observedremove_keyframe
    • First observedremove_marker
    • First observedremove_media
    • First observedremove_pauses
    • First observedremove_track
    • First observedremove_transition
    • First observedrename_track
    • First observedrestack_layer
    • First observedrestore_checkpoint
    • First observedretime_keyframe
    • First observedripple_delete_gap
    • First observedripple_delete_layers
    • First observedset_composition
    • First observedset_extrapolation
    • First observedset_keyframe
    • First observedset_keyframe_easing
    • First observedset_keyframe_tangents
    • First observedset_layers_enabled
    • First observedset_param_track
    • First observedset_position
    • First observedset_role_flags
    • First observedset_role_gain
    • First observedset_scale_linked
    • First observedsmooth_keyframes
    • First observedsplit_layer
    • First observedsynthesize_speech
    • First observedtranscribe_clip
    • First observedtranslate_path
    • First observedtrim_layer
    • First observedundo
    • First observedunlock_history
    • First observedupdate_effect
    • First observedupdate_layer
    • First observedupdate_layer_params
    • First observedupdate_marker
    • First observedupdate_transition
    • First observedweftcut_status
    • First observedwrite_motif_draft

TDQS

B3.4/5.0

Scored across 100 tools

Disambiguation3/5

The descriptions are unusually detailed and draw many fine distinctions, but with 100 tools there are real clusters that an agent can misselect: move_layers vs shift_layers vs move_layers_to_composition vs restack_layer, and set_position vs translate_position vs update_layer_params. The tool set is mostly separable, but the sheer number of similar-sounding edit operations makes selection error-prone.

Naming Consistency4/5

Most names follow a clear snake_case verb_noun pattern (add_track, delete_layer, set_layer_flags, update_effect). A few outliers such as weftcut_status, undo, redo, jump_to, and auto_split_by_shot deviate from the pattern, but the overall convention is readable and predictable.

Tool Count1/5

100 tools is far beyond what an agent can comfortably navigate as one coherent set; the surface spans editing, media, captions, effects, keyframes, motifs, exports, history, sessions, and review. Even if each tool earns its place in a full video editor API, the count is an extreme mismatch for an MCP tool set.

Completeness5/5

Coverage is extremely comprehensive: project/media lifecycle, timeline layers, tracks, links, groups, transitions, effects, keyframes, captions, transcription, audio analysis, motifs, export presets/jobs, history, checkpoints, sessions, and review tacks. Almost every operation has corresponding read, create, update, and delete paths or a documented workaround via read_project views.

Maintenance

ActivityActive
ResponsivenessUsually handled

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Web-based video editing platform that provides direct editing functionality through a Model Context Protocol server, supporting media file management, timeline editing, and advanced transformation effects.
    7
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP server that enables LLM agents to control the OpenCut classic video editor's timeline through a Playwright-controlled browser, allowing automated video editing tasks like adding media, inserting clips, splitting, trimming, and exporting.
    8
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents and MCP clients to programmatically edit video projects on a local desktop editor, with 119 tools for multitrack editing, effects, captions, audio, and batch auto-editing, producing reviewable and reversible real timeline edits.
    AGPL 3.0