Clueso
Server Details
Make videos and docs with your AI agent — describe what you need, every output stays editable.
- Status
- Healthy
- Uptime
- 100.0% over 42 days
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
- Repository
- clueso-ai/clueso-mcp
- GitHub Stars
- 6
- Server Listing
- Clueso MCP
TDQS
Scored across 44 tools
Most tools have clearly distinct purposes — the CRUD verbs (add/update/get/remove) map cleanly onto distinct resources (clip, element, audio, article, clueprint, project). The one genuine overlap is remove_elements vs. remove_from_project(target='element'), which both delete elements by id; the latter is a multi-target convenience wrapper. Related pairs (add_sync_point vs. auto_sync, add_audio vs. add_clips with audio mime) are explicitly disambiguated within their descriptions.
The verb_noun pattern is applied consistently across the entire surface: add_*, update_*, get_*, remove_*, create_*, duplicate_*, split_clip, reorder_elements, export_project. Specialized actions follow the same convention (analyze_audio, generate_media, set_voice, upload_file, switch_workspace). The only minor deviations are bare 'find' (generic search) and remove_from_project (verb_preposition_noun), both of which remain predictable.
44 tools is heavy, but the server genuinely spans a broad domain — project management, clip editing, element placement, audio mixing, voiceover, articles, clueprints, comments, media search, an embedded scripting runtime, and workspace management. Most tools earn their place, though there is measurable redundancy (remove_elements vs. remove_from_project, check_uploads + upload_file's nested modes, add_sync_point + auto_sync could be unified). The count is justified by scope rather than bloat, but it sits well past what is lean.
Core lifecycles are well covered: elements (add/update/remove/reorder), clips (add/get/update/remove/split/duplicate), audio (add/update/remove), articles (get/update + media). Obvious gaps: there is no delete_project or delete_clueprint, so projects and templates have create/read/update but no removal path. Voiceover deletion is intentionally mapped to muting (documented), and article deletion via markdown is documented, but the missing delete verbs for top-level resources will force agents into workarounds.
Available Tools
44 toolsadd_article_mediaAdd article media (image or GIF)AInspect
Add a screenshot or GIF to the article. Returns a screenshot_id to place in the article via update_article using <SCREENSHOT screenshot_id>.
kind="image": pass
timestampto capture a frame from the project's base video, OR passmcp_upload_id(from the upload tool) to attach an uploaded image. One of the two is required.kind="gif": pass
timestamp(start) andduration(seconds). Captures a short GIF clip from the base video. Requires the project to have a video clip.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | Yes | 'image' or 'gif'. | |
| duration | No | kind='gif' only: GIF duration in seconds. | |
| timestamp | No | kind='image': capture frame at this timestamp (seconds). kind='gif': GIF start time. | |
| project_id | Yes | Project ID. | |
| mcp_upload_id | No | kind='image' only: attach an uploaded image (mcp_upload_id from the upload tool) instead of capturing from video. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses the mutating 'add' behavior, the capture/attach mechanics, the GIF video-clip prerequisite, and the returned screenshot_id, all of which add context beyond the annotations. It does not state whether timestamp and mcp_upload_id are mutually exclusive or what error occurs on invalid combinations, but annotations already cover the non-destructive, non-read-only profile.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: purpose and output usage appear first, followed by tight bullets for each kind. Every sentence contributes necessary information, with no filler or repetition of schema details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers both modes, required parameter combinations, the video prerequisite for GIFs, the return contract, and downstream integration with update_article. Minor gaps remain: it does not explicitly say whether adopting timestamp for an image also requires a video clip, and it does not address exclusivity of timestamp versus mcp_upload_id or error behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although the schema describes each parameter in isolation, the description adds essential conditional semantics: kind=image requires one of timestamp or mcp_upload_id, while kind=gif requires timestamp plus duration alert. It also explains where mcp_upload_id comes from and what the successful result is, enabling correct parameter selection beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-resource pair: "Add a screenshot or GIF to the article." It further clarifies the artifact returned (a screenshot_id used in update_article), which distinguishes this add operation from related siblings like update_article_media and upload_file.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to choose this tool versus alternatives such as update_article_media, add_audio, add_elements, or generate_media. The only usage conditions are internal to the tool (image vs. GIF modes), not tool-selection criteria; no when-not-to-use or alternative routing is given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_audioAdd audio trackAInspect
Add a music track or sound effect that plays as a project-level audio layer over all clips. Does NOT consume a clip slot. Use this for background music or a soundtrack that should play under the existing timeline. (For inserting an audio file as its own sequential clip with auto-transcription, use add_clips(kind='video') with an audio mime_type instead.)
type="music": requires src, name, source_duration.
srcis either thesrcfrom a find(type='music') result, or an mcp_upload_id (prefixedmup_) from upload_file — upload ids resolve to a presigned URL server-side. For a Freesound result thesrcis an opaque handle; pass it through unchanged and Clueso downloads + hosts the original server-side (do not try to fetch it yourself). Getsource_durationfrom the find result, or from analyze_audio mode='features' (data.duration_ms / 1000). Optional: guide_start_time, guide_end_time, music_start_time, music_end_time (trim the source track), volume, loop, fade_in, fade_out.type="sfx": pass the
src,name, andsource_durationfrom a find(type='sfx') result, plus guide_start_time (Freesoundsrcis an opaque handle, resolved server-side just like music). Optional: volume. (Legacy: a fixed-librarysfx_keylike 'whoosh' still works instead of src.)
Concurrency: whole-project mutation (conflict domain: the entire project) — serialize; do not run in parallel with ANY other mutation on the same project_id (including element/voiceover edits). Size your clips BEFORE calling add_audio, or pass guide_end_time explicitly — the default ('end of project') is captured at call time and will NOT auto-extend if clips are added or resized afterwards.
| Name | Required | Description | Default |
|---|---|---|---|
| src | No | Audio source. For type='music' (required) or a stock type='sfx': the `src` from a find(type='music'|'sfx') result (may be an opaque Freesound handle — pass as-is), or an mcp_upload_id (prefixed 'mup_') from upload_file. Not needed for legacy fixed-library sfx (use sfx_key). | |
| loop | No | Loop the track if project is longer than the source. Music only. (default: false) | |
| name | No | Track/effect name. From the find result, or any descriptive label when using mcp_upload_id. Required for type='music' and for stock type='sfx' (passed via src). | |
| type | Yes | Audio type: 'music' or 'sfx' | |
| volume | No | Volume as percent (0–100). Default: 50 for music, 80 for sfx. | |
| fade_in | No | Fade-in duration in seconds. Music only. (default: 0.5) | |
| sfx_key | No | LEGACY fixed-library SFX key (e.g. 'whoosh', 'pop', 'click'). Optional alternative to src for type='sfx'. Prefer the src/name/source_duration from a find(type='sfx') result. | |
| fade_out | No | Fade-out duration in seconds. Music only. (default: 0.5) | |
| project_id | Yes | The project ID | |
| guide_end_time | No | When to stop playing (seconds). Music only. Default = end of project AT CALL TIME — captured once at insert and NOT recomputed when clips are later added or resized. Pass an explicit value (e.g. the intended final project duration) when adding audio before clips are sized. | |
| music_end_time | No | Out-point within the SOURCE track (seconds) — trims where playback ends in the music file. Music only. Default = source_duration. | |
| source_duration | No | Source duration in seconds. From the find result, or analyze_audio mode='features' (data.duration_ms / 1000). Required for type='music' and for stock type='sfx' (passed via src). | |
| guide_start_time | No | When to start playing in the guide timeline (seconds). Required for type='sfx', optional for music (default 0). | |
| music_start_time | No | In-point within the SOURCE track (seconds) — trims where playback begins in the music file. Music only. Default 0 (start of source). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Richly discloses behavior beyond annotations: src resolution (mcp_upload_id, opaque Freesound handle), server-side hosting, guide_end_time captured at call time and not auto-extending, and the entire-project conflict domain. No contradiction with readOnlyHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Long but well-structured with clear sections (purpose, music, sfx, concurrency) and front-loaded key differentiators. Every sentence adds value; no fluff despite the length justified by 14 parameters and complex behaviors.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Complete for a complex mutation tool: covers parameter sourcing, field requirements per type, timing pitfalls, and concurrency domain. No output schema needed for a mutation, and all critical calling details are present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema covers all parameters, the description adds substantial meaning: where to obtain src/source_duration (find, upload, analyze_audio), opaque handle handling, type-specific required fields, and subtle timing defaults (guide_end_time capture). Greatly exceeds schema baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states it adds a music track or sound effect as a project-level audio layer, explicitly distinguishing from add_clips by noting it does not consume a clip slot. Provides specific use case (background music/soundtrack) and excludes sequential clip insertion.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells when to use (background music under timeline) and when not (sequential clips use add_clips). Also gives concurrency guidance (serialize, no parallel mutations) and sequencing advice (size clips before or pass guide_end_time).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_clipsAdd clips to projectAInspect
Create new clips on a project. One tool, three sources:
kind="blank": empty slide clips you'll populate with add_elements / generate_media. Pass
clips: [{title?, duration?}, ...]. Note: create_project already creates clip 0; calling with N blank entries gives N+1 clips total.kind="pptx": extract slides from an uploaded .ppt/.pptx. Pass
mcp_upload_id(from upload_file), optionalslide_indices. Each slide becomes a slide_clip with native text/image/shape elements pre-populated.kind="video": cut clips from an uploaded video/audio. Pass
mcp_upload_idand optionallymime_type(default video/mp4),title,voiceover_text,cuts: [{start_seconds, end_seconds, heading?}],auto_elements. Withoutcutsthe whole upload becomes one clip. Pipeline (download → transcribe → insert) runs in the background; subsequent calls on the same upload hit a 24h cache and return synchronously. (To overlay a video ONTO an existing clip — picture-in-picture, b-roll, background loop — rather than insert it as its own clip, use add_elements(element_type='video') instead.)
All variants accept after_clip_id to control insertion position; appends at end if omitted.
Concurrency: whole-project mutation (conflict domain: the entire project) — serialize. Do not run it in parallel with ANY other mutation on the same project_id, including element/voiceover edits; run them one at a time. (Mutations to different projects run in parallel freely.)
| Name | Required | Description | Default |
|---|---|---|---|
| cuts | No | kind='video' only: per-clip cuts. Each entry becomes one inserted clip. Omit to insert the full upload as a single clip. | |
| kind | Yes | Source for the new clips: 'blank' | 'pptx' | 'video'. | |
| clips | No | kind='blank' only: one entry per blank clip. Optionally set background_color/background + transition per clip at creation — no follow-up update_clips needed. | |
| title | No | kind='video' only: clip title (default 'Video'). | |
| mime_type | No | kind='video' only: MIME type (default 'video/mp4'). Audio MIME types insert the file as a sequential clip with auto-TTS; for background music, use add_audio instead. | |
| project_id | Yes | Project (guide) ID. | |
| after_clip_id | No | Insert after this clip ID; appends at end if omitted. | |
| auto_elements | No | kind='video' only: when true, run auto-element detection (zooms, spotlights, blurs). Default false. Only meaningful on cache miss; cache hits clone the originating run's auto-elements. | |
| mcp_upload_id | No | kind='pptx' or 'video': mcp_upload_id from the upload_file tool. | |
| slide_indices | No | kind='pptx' only: 0-based slide indices to insert. Omit to insert all slides. | |
| voiceover_text | No | kind='video' only: post-AI voiceover script (saved as v2). Original audio is always retained as the base transcript. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations (readOnly=false, destructive=false), the description discloses the background processing pipeline, 24-hour cache behavior, the N+1 blank-clip side effect of create_project, and the whole-project serialization requirement. There is no contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The long description is justified by three modes and 11 parameters; it is front-loaded with the core purpose and organized into scannable bullets. Every sentence adds operational value, from mode-specific payloads to concurrency constraints.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, absence of an output schema, and minimal annotations, the description covers mode selection, parameter combinations, alternatives, side effects, and concurrency. It is sufficiently complete for an agent to call the tool correctly without further inference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description adds cross-parameter meaning the schema cannot express: which parameters apply to each kind, defaults like video/mp4, cache-hit semantics for auto_elements, and the no-cuts whole-upload behavior. It also warns about the N+1 blank clip count and notes that background/transition can be set at creation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a concrete verb and object ('Create new clips on a project') and immediately disambiguates the three source modes (blank, pptx, video). It also names the specific alternative tool (add_elements) for the video-overlay case, making it easy to distinguish from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance per kind, including exact parameters to pass and when to choose alternatives ('use add_elements(element_type='video') instead', 'use add_audio instead'). The concurrency directive tells the agent what not to run in parallel with this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_commentAdd commentAInspect
Post a review comment on a project, attributed to "Clueso AI".
Use this to leave feedback, suggestions, or notes — either at the project level (no clip_id) or pinned to a specific clip with an optional timestamp inside that clip.
Pass parent_comment_id to REPLY to an existing comment rather than open a new thread. Read what is already there with get_comments first: answering a reviewer in their own thread is what makes the note resolvable, where a fresh top-level comment just adds noise.
| Name | Required | Description | Default |
|---|---|---|---|
| clip_id | No | Optional clip ID to pin the comment to. Omit for a project-level comment. | |
| project_id | Yes | The project (guide) ID | |
| comment_text | Yes | Comment text to post | |
| clip_timestamp | No | Optional timestamp within the clip (seconds). Only used when clip_id is provided. | |
| parent_comment_id | No | Reply to this comment instead of starting a new thread. Take the id from get_comments. Replying is how you answer feedback you have acted on — the clip pin and timestamp come from the parent, so leave clip_id/clip_timestamp off. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes beyond annotations by disclosing that the comment is attributed to "Clueso AI" (a behavioral trait), and explains the threading behavior: replying makes the note resolvable, while a fresh top-level comment adds noise. It also states that when replying, the clip pin and timestamp come from the parent, so clip_id/clip_timestamp should be omitted. Annotations only provide readOnly/destructive hints, so this added context is valuable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise (about 120 words), front-loaded with the core action, and organized into logical sections: main purpose, use cases (project vs. clip), and reply guidance. No filler or repetition; every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (5 parameters, no output schema), the description covers the key usage patterns, parameter relationships, and workflow prerequisites (reading with get_comments). It does not describe response/return values or error behavior, which is a minor gap, but overall an agent has enough context to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
While the schema already documents all parameters (100% coverage), the description adds crucial inter-parameter semantics: it explains clip_id is omitted for project-level comments, clip_timestamp is only used when clip_id is provided, and parent_comment_id should be taken from get_comments and implies leaving clip_id/clip_timestamp off when replying. This is more actionable than the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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: "Post a review comment on a project, attributed to 'Clueso AI'." It immediately distinguishes from related tools like get_comments by stating its write purpose and clarifying project-level vs. clip-pinned comments.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says when to use the tool ("Use this to leave feedback, suggestions, or notes"), and provides clear guidance on when to reply vs. start a new thread: "Pass parent_comment_id to REPLY to an existing comment rather than open a new thread." It also directs the agent to read existing comments with get_comments first and warns against adding noise, which is a clear alternative/usage boundary.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_elementsAdd elements to clipsAInspect
Add many elements across one or more clips in a single tool call. Replaces the per-element tool — always batch.
SEND LESS. Most batches repeat themselves — the same clip_index, element_type, font_setting, alignment or gradientSetting on every item. Hoist those into defaults and send them once; each item then carries only what differs, and overrides any key it sets (type_data merges one level). On a 20-30 element batch this typically cuts the call by a quarter to a half. returning shapes the response the way select shapes a get_clip read.
defaults: { clip_index: 2, element_type: 'text', type_data: { font_setting: { font: 'Inter', weight: '600' }, alignment: 'center' } } elements: [ { name: 'headline', x: 960, y: 400, type_data: { text: 'Hello', fontSize: 120 } }, ... ]
Use after calling get_element_schema to confirm the type_data shape per element_type. Items within one call are applied in order; returns one result entry per input item so partial success is fine.
Reuse instead of rebuilding: an item may pass component_id INSTEAD of element_type/type_data to insert a saved component from this workspace exactly as stored — no generation, instant — returning every new element_id plus its parameter_schema; set its content afterwards with update_elements(type_data.parameter_values). Find them with find(type='element_components'). Use base_component_id (with element_type='animation' and a prompt) only when you want a NEW variant rather than that component.
Z-order: list position IS z-index — later renders on top — and a new element goes on top by default. Pass insert_at: 'back' to put it behind what's already there, or insert_at: {before: id} / {after: id} to land next to a specific element — that also puts the new element in THAT node's group, which is the only way to place inside one. reorder_elements rewrites the whole order in one call, grouped clips included.
group + insert_at: {before|after} together: what the reference is relative to decides what gets positioned. Point at a node INSIDE the group and the ELEMENT takes that slot among its new siblings. Point at one OUTSIDE it and the GROUP takes that slot, with the element inside — which is how you put a backdrop pattern of N elements at a chosen depth as one hideable unit: hoist both into defaults and the first item seats the group, the rest just join it. The one refusal left is naming a reference outside a group that already exists somewhere else, since moving an established group is not what adding one element to it should do; seat the group where you want it in the call that CREATES it, because there is no reposition afterwards. front/back with a group follow the same principle: they address the GROUP only while the element is alone in it — the call that creates it — and once the group has other members they address the ELEMENT within the group's interior, so they will not move an established group either.
Grouping: pass group: "<name>" to keep a unit together (a card and its label, a stat and its caption) so the user can move or hide it as one thing. Items in one call sharing a name land in the same group, and a later call with that name adds to it. Grouping never changes coordinates. It does affect z-order: a group's members render contiguously at the group's slot, and a NEW group takes the slot of its first member, so grouping already-adjacent elements keeps their z-position while grouping scattered ones pulls them together at the lowest member's slot.
Concurrency: within ONE call every element lands in a single save. Across calls the conflict domain is the CLIP's element list, not the individual element, so you can fan this tool out across parallel subagents targeting DIFFERENT clips. Two concurrent add_elements calls on the SAME clip are NOT safe: every add claims that clip's element list, so the later call is REJECTED ('changed since this edit was based on') and nothing it sent is written — batch all of a clip's elements into ONE call instead. A rejection is not last-write-wins: re-read and re-apply. Do NOT run it concurrently with a whole-clip or whole-project mutation on the same guide (update_clips on that clip, add_clips/remove_clip/split_clip/duplicate_clip, add_audio, update_project) — those rewrite a larger scope and would clobber the element.
Element-type quirks (handled per-item): • zoom → x/y/width/height are ignored; use centerX/centerY in type_data • image → provide x/y/width/height (the clip is located by clip_index; the clip_id input is accepted but unused) • animation → x/y/width/height default to the full canvas if omitted (the clip is located by clip_index) For everything else, x/y/width/height are required.
Animation: pass a top-level keyframes array (sibling of x/y/type_data, NOT inside type_data) — entries are { timestamp, positionX?, positionY?, width?, height?, interpolation? } in canvas pixels. positionX/Y use the SAME alignment-aware origin as the element's x/y. Text caveat: width/height are not keyframable on text — animate its size with fontSize (letterSpacing/lineHeight/padding* are also keyframable).
Position origin: for TEXT y is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top; x is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.
To centre a label in a row, pill, chip, card or beside an icon: pass the container's centre line as y with y_anchor:'center'. The server centres the measured text in it, so it is one number and it holds for wrapped text. Add type_data.fit{max_height} whenever the text could wrap, so the box stays inside the space you gave it. y_anchor is a directive for computing the stored y, not a property that sticks — repeat it on any later call that moves the same label.
| Name | Required | Description | Default |
|---|---|---|---|
| defaults | No | Values shared by every item, sent once rather than repeated. Items win per key; type_data merges one level. E.g. defaults:{clip_index:1, element_type:'text', type_data:{font_setting:{font:'Inter',weight:'600'}, alignment:'center'}} then items carry only what differs. | |
| elements | Yes | Elements to add — at least one entry. | |
| returning | No | Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). A text element measured on a fallback face is listed in top-level `font_warnings` whichever you choose. ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write. | |
| project_id | Yes | Project ID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite annotations being minimal, the description thoroughly discloses behavioral traits: single-save semantics per call, sequential application of items, partial-success behavior, rejection semantics ('nothing it sent is written'), and the full concurrency conflict domain. It also clarifies non-obvious behaviors like z-order list position, grouping depth, and that a rejection is not last-write-wins.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but front-loaded with purpose and batched usage, and every paragraph addresses a distinct decision an agent must make: defaults, components, z-order, grouping, concurrency, quirks, animation, and y_anchor. It earns most of its length given the tool's complexity, though it is verbose enough that tighter editing would improve scannability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is complete for a complex mutation tool with no output schema. It covers return shaping via `returning`, per-item result behavior and partial success, failure/rejection modes, element-type-specific coordinate rules, keyframe placement, grouping semantics, and the y_anchor directive — leaving no major decision an agent needs to make undocumented.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description adds crucial meaning beyond it: defaults merge one level, keyframes must be top-level and not inside type_data, zoom ignores x/y/width/height, clip_id is accepted but unused, and text width/height behave differently than other element types. These distinctions are essential for correct invocation and are not inferable from the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence states exactly what the tool does: 'Add many elements across one or more clips in a single tool call.' It also differentiates from sibling and predecessor tools by saying 'Replaces the per-element tool — always batch,' making the batched scope explicit and preventing confusion with add_clips or add_audio.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance: 'Use after calling get_element_schema to confirm the type_data shape per element_type.' It also names alternatives for related operations (update_elements for content, reorder_elements for z-order, find for components) and states a clear exclusion: concurrent calls on the same clip are unsafe and whole-clip mutations should not run simultaneously.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
add_sync_pointAdd a sync point at a word + timestampAInspect
Insert one sync marker on a clip's transcript.
Use this when:
The user is explicit about WHERE the camera should pause / cut (e.g. "sync the word 'submit' to 4.2s of the demo").
auto_syncran but missed a step you care about.
How matching works:
word: case-insensitive, punctuation-stripped. The first match in the transcript is used unlessoccurrence > 1.occurrence: 1-indexed — pass 2 to target the SECOND time that word appears, 3 for the third, etc. Required when the word repeats.timestamp_seconds: clip-relative seconds. When the clip has run TTS already (generated_timestampspresent), the server inverse-maps this to original-recording seconds automatically.
Constraints: the clip MUST be a video clip with a source recording (otherwise the frame thumbnail can't be extracted). The transcript must already contain the word — if not, you'll get word_not_found with a 200-char excerpt of the transcript to help you retry.
| Name | Required | Description | Default |
|---|---|---|---|
| word | Yes | Target word (case-insensitive; trailing punctuation is stripped). | |
| clip_id | No | Clip ID (preferred). If omitted, clip_index is used. | |
| clip_index | No | Zero-based clip index. Ignored if clip_id is provided. | |
| occurrence | No | 1-indexed match number when the word repeats. Defaults to 1 (first occurrence). | |
| project_id | Yes | Project ID. | |
| sync_point_name | No | Optional label (e.g. 'Click submit'). Defaults to 'Sync point N' using the next order number. | |
| timestamp_seconds | Yes | Clip-relative timestamp in seconds. Auto-mapped to original-recording seconds when the clip has generated_timestamps. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the minimal annotations, the description discloses matching behavior (case-insensitive, punctuation-stripped, first match by default), occurrence indexing semantics, timestamp mapping when generated_timestamps exist, and the word_not_found error with an excerpt. This gives the agent a strong mental model of tool behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is organized into clear sections: use cases, matching behavior, and constraints. Every sentence carries useful information, and the most important purpose and usage guidance appear first. Despite its length, nothing feels redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 7 parameters, no output schema, and minimal annotations, the description covers prerequisites, matching rules, timestamp handling, and error recovery. The only minor omission is the success return shape, but that is not necessary to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description adds meaningful semantics: occurrence is 1-indexed and required for repeated words, timestamp_seconds is clip-relative and auto-inverse-mapped, and clip_id vs clip_index selection behavior is clarified. This goes well beyond the schema's field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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: 'Insert one sync marker on a clip's transcript.' This clearly distinguishes it from the sibling auto_sync, which performs automatic sync, and from other clip-editing tools like split_clip.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use conditions: the user is explicit about where to pause/cut, or auto_sync missed a step. It also states the key constraint that the clip must be a video clip with a source recording, and warns when the word is not found, which effectively tells the agent when not to proceed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
analyze_audioAnalyze audioARead-onlyInspect
Analyze an audio file. Modes:
transcript: Speech-to-text with word-level timestamps — returns
{language, full_text, words}where each word is{word, start_ms, end_ms, punctuated_word}. ⚠ MILLISECONDS here; get_clip'svoiceover_wordsgives the same words in SECONDS as{word, start, end}. Use for caption timing, script editing, or word-level visual sync. Works on narration and on sung lyrics: the provider is picked from the content, and if it returns nothing the other one is tried automatically. So an emptywordsmeans the audio genuinely has no intelligible speech, not that the wrong engine ran.silences: returns
{silences, total_silence_ms}, each span{start_ms, end_ms, peak_db}. Use for auto-trim, smart-split, or pause-aware editing.beats: returns
{tempo_bpm, beats_ms}— beats_ms is an array of MILLISECOND positions. Empty for non-music. Use to align animations/zooms to a beat.features: returns
{duration_ms, peak_db, rms_db, lufs, has_music, has_speech}— loudness plus two INDEPENDENT hints —has_music(beats hold a steady period) andhas_speech(there is audible content above a loudness floor; it is not a speech detector). Both can be true at once, e.g. narration over a music bed. Cheap dispatcher — call once to pick a mode, or for duration_ms to pass as add_audio's source_duration. When the words matter, trust transcript rather than these flags.
Source: provide exactly one of mcp_upload_id (from upload tool) or file_url (already-public URL, e.g. a find(type='music') result or Clueso CDN file). Optional time range: range_start_ms / range_end_ms crops the analysis window.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | Yes | Which analysis to run. | |
| file_url | No | Public http(s) URL to the audio. Use when the file is already accessible (e.g. find(type='music') result, Clueso CDN). Validated against private/loopback ranges. | |
| range_end_ms | No | End of analysis window in milliseconds. Default: whole file. | |
| mcp_upload_id | No | MCP upload ID from the upload_file tool. Use this OR file_url, not both. | |
| range_start_ms | No | Start of analysis window in milliseconds. Default 0 (beginning). | |
| silences_options | No | Options for mode='silences'. | |
| transcript_options | No | Options for mode='transcript'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint=true and destructiveHint=false, the description adds substantial behavioral context: the unit warning (ms vs seconds vs get_clip's voiceover_words), the automatic provider fallback for transcript, the independence of has_music/has_speech flags, and the meaning of an empty words array. These details go far beyond the annotations and prevent misinterpretation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long, but the complexity of the tool (4 modes, 7 params, nested options) justifies the length. It is well structured with bolded mode names, bullet-like formatting, and warnings placed prominently. A slight deduction for density—some agents might be overwhelmed, but every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity and the absence of an output schema, the description is remarkably complete. It details all return structures, unit conventions, fallback behavior, and usage scenarios, and even cross-references sibling tools (get_clip, add_audio). An agent can invoke it correctly with no further information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description clarifies how each parameter behaves in practice: mode meaning and return shapes, source exclusivity, the effect of range_start_ms/range_end_ms on the analysis window, and the purpose of silences_options and transcript_options. It also explains the unit conversions and fallback logic, adding meaning that the schema alone does not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Analyze an audio file') and enumerates four distinct modes with concrete use cases, distinguishing it clearly from sibling tools like add_audio (which adds rather than reads) and get_clip (which returns clip metadata, not analysis). The mode list and return-formats leave no ambiguity about what the tool accomplishes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use guidance for each mode: transcript for caption timing/script editing, silences for auto-trim, beats for alignment, features for a cheap dispatcher or duration retrieval. It also tells the agent when to trust transcript over the feature flags and how to choose the source parameter. No exclusions are needed since this is a specialized analysis tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
auto_syncAuto-generate sync pointsADestructiveInspect
Run the agentic auto-sync pipeline against a clip with a source recording. Detects natural sync points (UI state changes, narrated steps) and inserts sync-marker nodes into the clip's transcript.
Async: returns immediately with a status enum from the pre-flight; sync-marker nodes appear in the transcript a few seconds later. Poll get_clip if you need to verify.
Capacity: capped at 3 concurrent runs platform-wide. Returning status='success' means the job was accepted, not that it finished.
Sync points are required input for voiceover TTS on video clips — without them, the TTS has no per-step pacing reference. (See resource clueso://docs/sync-points for the full model.)
| Name | Required | Description | Default |
|---|---|---|---|
| clip_id | Yes | Clip ID to auto-sync. | |
| project_id | Yes | Project ID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even with annotations already marking this as not read-only and destructive, the description adds substantial behavioral detail: the operation is asynchronous, returns a pre-flight status enum, mutates the transcript after a delay, is capped at 3 concurrent runs, and 'success' only means accepted, not finished. This is exactly the kind of extra context an agent needs for a state-changing async tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every paragraph earns its place: the first states the operation, the second explains async behavior and how to verify, the third warns about capacity, and the fourth gives the domain motivation. It is front-loaded with the core function before the caveats, and nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schemached and async side effects, the description covers return semantics, polling verification, concurrency limits, and the downstream use case for TTS. It links to fuller documentation for the sync-point model)Skip nothing needed for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameters are already documented as 'Clip ID to auto-sync' and 'Project ID.' The description adds no additional parameter-level semantics beyond this, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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: 'Run the agentic auto-sync pipeline against a clip with a source recording.' It clarifies the outcome by naming exactly what gets inserted ('sync-marker nodes into the clip's transcript'), which differentiates it from the sibling add_sync_point for manual insertion.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when this is needed: 'Sync points are required input for voiceover TTS on video clips' and explains the consequence of not having them. It does not explicitly name an alternative like add_sync_point, but the automatic-vs-manual distinction is strongly implied and the prerequisite ('a source recording') is stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_uploadsCheck upload statusARead-onlyInspect
Fetch all files the user uploaded via the hosted upload page. Returns one mcp_upload_id per file — pass each to the appropriate tool (add_clips, add_article_media, etc.). Call this once after the user confirms they are done uploading; the token covers all files they dropped on the page.
| Name | Required | Description | Default |
|---|---|---|---|
| upload_token | Yes | The upload_token returned by upload_file(request_hosted_upload: true) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already carry the safety profile (readOnlyHint=true, destructiveHint=false), so the description builds on that with the return contract ("Returns one mcp_upload_id per file"), the batch scope of the token ("the token covers all files they dropped on the page"), and recommended call timing. It adds real behavioral context beyond annotations, though it stops short of specifying container format or pagination. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences (~48 words) with zero filler. The first sentence states the core purpose, and each subsequent sentence earns its place: return shape, routing to consumers, call timing, and token scope. Nothing repeats annotations or schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a low-complexity signature (1 param, no output schema), the description covers the trigger condition, the required token, the key return value (one mcp_upload_id per file), and the downstream handoff. The minor gap is the absent output schema: the exact return container shape and the criteria for choosing "the appropriate tool" are left unspecified, creating slight routing ambiguity. Annotations covering safety keep this close to complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already explains where the token comes from (upload_file request_hosted_upload: true). The description adds meaning the schema lacks: "the token covers all files they dropped on the page" clarifies that a single token maps to multiple files, which is essential semantic context for using the parameter correctly. This raises the score above the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource: "Fetch all files the user uploaded via the hosted upload page," naming both the action and the exact scope. It clearly differentiates itself from siblings by framing the tool as the retrieval step of an upload workflow, distinct from the add_* consumers it explicitly names.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Call this once after the user confirms they are done uploading" is an explicit trigger condition with a frequency hint ("once"). "Pass each to the appropriate tool (add_clips, add_article_media, etc.)" explicitly names the downstream alternatives, telling the agent what to do with the result and when to use those siblings instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_clueprintCreate clueprintAInspect
Create a new clueprint (reusable video template). A clueprint is a structured file directory with design notes, composition rules, and screenshots that can be used to generate videos.
Use human-readable folder categories: design/ (colors, typography, backgrounds, animation), rules/ (composition, voiceover, editing), screenshots/ (rendered clip previews). See the "Creating Clueprints" section in the system instructions for the full structure.
If source_guide_ids are provided, guide data is automatically extracted clip-by-clip into the clueprint as reference material.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Name of the clueprint | |
| visibility | Yes | 'private' = only you, 'workspace' = everyone in your workspace | |
| description | No | Description of what this clueprint does | |
| source_guide_ids | No | IDs of existing projects to extract template data from |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate not read-only (readOnlyHint=false) and not destructive (destructiveHint=false). The description adds meaningful side-effect context: when source_guide_ids are provided, guide data is automatically extracted clip-by-clip into the clueprint. This goes beyond the annotations and informs the agent of automatic behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three dense sentences that are front-loaded with the core purpose. The folder categories (design/, rules/, screenshots/) are specific and useful, and the pointer to system instructions avoids unnecessary duplication. No fluff or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the created artifact (directory structure), the side effect of source_guide_ids, and points to system instructions for full detail. It omits return value or error behavior, but given no output schema and the tool's straightforward create-once nature, this is a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 value for source_guide_ids by explaining the auto-extraction behavior, and it provides domain context for folder categories that relates to the overall purpose, enriching the meaning of the parameters beyond their schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as creating a clueprint, defined as a 'reusable video template', and distinguishes it from project creation (create_project). It also specifies the internal directory structure, leaving no ambiguity about what the tool produces.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description establishes the use case (creating reusable templates) and explains the folder categories and optional source_guide_ids behavior. However, it does not explicitly contrast with sibling tools like create_project or state when not to use this tool, so it lacks explicit exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_projectCreate projectAInspect
Create a new blank Clueso project. Returns the projectId and initialClipId — the project starts with one blank clip already at index 0 (default short duration). Use update_clips to resize/retitle clip 0, add_clips(kind='blank') to append more clips, add_elements to place content, and add_audio to attach a project-level music track.
Optionally place the project inside a folder (use find(type='folders') to find folder IDs) and set a description at creation time.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Project title | |
| folder_id | No | Optional folder ID to nest the project under. Use find(type='folders') to discover IDs. Omit to create at workspace root. | |
| description | No | Optional project description (max ~500 chars) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate this is a write operation (readOnlyHint=false) and not destructive. The description adds valuable behavioral details: it returns projectId and initialClipId, and the project starts with a blank clip at index 0 with a default short duration. This goes beyond annotations and clarifies side effects and return values, though it does not mention error conditions or prerequisites.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured. It front-loads the primary purpose and return info, then gives practical follow-up instructions and optional parameter guidance in a second sentence. There is no fluff; every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that there is no output schema, the description explains the return values (projectId, initialClipId) and the initial state (blank clip at index 0). It covers optional folder placement and description. It does not explicitly state whether title is required, but this is a minor gap given the tool's simplicity and the schema's lack of a required field. Overall, it is sufficiently complete for an agent to call correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so parameters are already documented. The description adds extra value by advising to use find(type='folders') to discover folder IDs for the folder_id parameter, which is context not present in the schema. It does not add much for title or description beyond the schema, but the added guidance for folder_id justifies a score above the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool creates a new blank Clueso project and mentions the returned IDs, making the purpose unambiguous. It distinguishes from update and duplicate tools by focusing on the initial creation, but it does not explicitly name sibling tools for contrast, so it doesn't fully achieve a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context on when to use this tool (to start a project) and provides explicit next steps (use update_clips, add_clips, add_elements, add_audio) and guidance for optional parameters (use find for folder IDs). However, it does not explicitly state when not to use it or name alternative creation tools like duplicate_project, so it lacks full exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
duplicate_clipDuplicate a clipAInspect
Clone one clip — within the same project, or from another project — into a target project.
Same project: pass
target_project_idandsource_clip_id(omitsource_project_id).Cross-project: pass
target_project_id,source_project_id,source_clip_id. The source clip's S3 assets (voiceover audio, original video footage, generated video, etc.) are re-hosted into the target guide's S3 namespace, so the new clip is independent of the source — deleting the source project later won't break it.
Insertion: pass after_clip_id to place immediately after a specific clip in the target. Omit to append at end.
Returns the new clip_id and its final index. Concurrency: whole-project mutation (conflict domain: the entire target project) — serialize; do not run in parallel with any other mutation on the same target_project_id.
| Name | Required | Description | Default |
|---|---|---|---|
| after_clip_id | No | Insert after this clip ID in the target. Appends at end if omitted. | |
| source_clip_id | Yes | ID of the clip to duplicate. | |
| source_project_id | No | Cross-project mode: ID of the project the source clip lives in. Omit for same-project duplication. | |
| target_project_id | Yes | Project (guide) ID to insert the duplicate into. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, destructiveHint=false), the description discloses meaningful behavioral traits: S3 assets are re-hosted into the target namespace, the duplicate is independent of the source, deleting the source project later won't break it, the conflict domain is the entire target project, and it returns the new clip_id and final index. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with bullet points, front-loads the core purpose, and every sentence serves a clear function (modes, insertion, output, concurrency). It is informative without being bloated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with cross-project side effects and concurrency constraints, the description covers all necessary operational aspects: mode selection, asset re-hosting, insertion position, return value, and serialization requirement. An agent has enough context to invoke the tool correctly without an output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and each parameter is already described in the schema. The description restates the same-project vs cross-project combinations and after_clip_id behavior, which adds some clarity about parameter relationships but does not introduce meaning beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Clone'), a specific resource ('one clip'), and the destination ('target project'), and distinguishes same-project from cross-project duplication. This clearly separates it from siblings like duplicate_project (whole project) and add_clips (adding new clips).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit parameter combinations for same-project vs cross-project use and explains insertion behavior with after_clip_id. It also includes a strong concurrency warning. However, it does not explicitly name alternative tools or state when not to use this tool, so it misses the highest bar for exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
duplicate_projectDuplicate projectAInspect
Clone an entire project — every clip, voiceover, asset, and metadata field — into a fresh project. The copy has its own S3 namespace, so changes or deletions to the source never affect the duplicate.
Defaults:
new_title omitted → "{source title} (copy)" when no folder_id is given (or it's empty) and the source stays in the same org; pass an explicit non-empty folder_id and the title is preserved.
folder_id omitted → copy lives in the same folder as the source.
Returns the new project's id and title. Concurrency: whole-project read+create — serialize against other mutations on the same source_project_id; do not run them in parallel.
| Name | Required | Description | Default |
|---|---|---|---|
| folder_id | No | Place the duplicate in this folder. Omit to keep the same folder as the source. Pass '' (empty string) to move to workspace root. | |
| new_title | No | Override the title of the duplicate. | |
| source_project_id | Yes | Project (guide) ID to duplicate. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, destructiveHint=false), the description discloses the key behavioral trait that the duplicate has its own S3 namespace and is therefore independent of the source. It also states return values and warns about concurrency, which is exactly the kind of context an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact, front-loaded with the core purpose, and uses a short bulleted 'Defaults' section to organize conditional behaviors. The concurrency warning is a single necessary sentence. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schema, the description correctly states what is returned (new project's id and title). It covers source selection, folder targeting, title defaults, copy independence, and concurrency safety, leaving no crucial operational gap for invoking the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema covers 100% of parameters, so a baseline of 3 applies. The description adds meaningful nuance beyond the schema: the conditional title behavior when new_title is omitted, the distinction between omitting folder_id and passing an empty string, and the effect of an explicit non-empty folder_id.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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 — 'Clone an entire project' — and enumerates what is copied: every clip, voiceover, asset, and metadata field. It clearly differentiates from the sibling duplicate_clip by emphasizing the whole-project scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear operational guidance: default title behavior, folder placement behavior, and an explicit concurrency constraint to serialize against other mutations on the same source_project_id. It does not explicitly name alternatives like create_project or duplicate_clip, but the scope statement makes the intended use apparent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
estimate_durationEstimate clip durationARead-onlyInspect
Estimate voiceover duration for one or many clips at once (~150 words/minute). Pass an array of voiceover texts — one per clip. Returns durations in the same order, ready for add_clips.
| Name | Required | Description | Default |
|---|---|---|---|
| texts | Yes | Array of voiceover texts to estimate — one string per clip. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as read-only and non-destructive. The description adds the estimation rule (~150 words/minute), supports batch input, and promises output in the same order, which is useful behavioral information beyond 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences, with the main purpose and estimation rate front-loaded and no redundant elaboration. Every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-parameter read-only tool, this is nearly complete: it covers batch use, return ordering, and downstream use with add_clips. The only minor gap is that the units of the returned durations are not stated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the schema already describes 'texts' as an array of voiceover texts with one string per clip. The description reinforces this but does not add new parameter-level meaning; the rate and ordering are output/behavior details rather than parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Estimate voiceover duration') and resource ('clips'), and clarifies it handles one or many voiceover texts at once. This clearly distinguishes it from siblings like add_clips, which would consume the estimated durations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear context: pass texts when you need voiceover duration estimates, and the result is 'ready for add_clips.' It does not explicitly name exclusions or alternative tools, but the workflow context is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_projectExport projectAInspect
Kick off a video export of the project. Returns immediately with an export_id; the export pipeline runs in the background. The user can find the rendered video in the Exports tab in the editor.
Defaults: 1080p / 30fps / no captions / English. Pass overrides only when needed.
| Name | Required | Description | Default |
|---|---|---|---|
| fps | No | Frames per second (default 30) | |
| captions | No | Burn subtitles into the video (default false) | |
| project_id | Yes | The project ID to export | |
| resolution | No | Output resolution (default 1080p) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
It explicitly discloses async behavior ('Returns immediately with an export_id; the export pipeline runs in the background') and tells the user where to find the result ('Exports tab in the editor'). This goes well beyond the annotations, which only state read/write/destructive/open-world hints. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: the first sentence states the action and the key behavioral facts, and the second paragraph summarizes defaults. Every sentence carries useful information without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a kickoff tool with no output schema, the description covers the essential context: what happens on call, what the caller receives, where the final artifact appears, and what the default parameters are. Nothing critical for invoking it successfully is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents all four parameters with descriptions and defaults, so the baseline is 3. The description adds value by consolidating the defaults ('1080p / 30fps / no captions / English') and advising that overrides should only be passed when needed, which helps the agent call with minimal required arguments.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific action and resource: 'Kick off a video export of the project.' It clearly identifies what the tool does and distinguishes it from the sibling update/create tools by focusing on export. It doesn't name a sibling alternative, but no direct export sibling exists in the list, so no further differentiation is needed.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when to invoke the tool: whenever a video export of the project is needed, and it instructs callers to pass overrides only when needed. It does not spell out when-not-to-use or alternative tools, but the sibling list contains no competing export tool, so the omission is minor.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
findFind resourcesARead-onlyInspect
Find any resource in Clueso by type, optionally filtered by name or exact id. One tool for listing and searching across the workspace.
type:
• projects | folders | clueprints | workspaces
• backgrounds | voices | fonts | image_gen_style_packs | element_components
(voices carry gender, tags, accent, preview_url and — where one has been written — a free-text description of tone and pace, which is the field actually worth choosing on. tags is a small closed vocabulary, so it groups voices rather than telling them apart. Choose deliberately: voiceover is the film's clock, and regenerating speech later rescales the clip and every element time and keyframe with it.)
• images | videos | music | sfx — media; each result carries a source ('org' = your saved-media library, 'stock' = a stock/curated provider). Scope with source, pick the library with provider (see below). Stock results are a short described shortlist — pick the best fit and use its src. Stock video results also carry safe_src and a video_files tier list with one entry marked recommended — use safe_src (or the recommended tier) in add_elements; tiers above 1080p can exceed its ~200MB source cap and fail. For a Freesound music/sfx result, src is an OPAQUE handle (not a playable URL) — pass it straight to add_audio and the original is fetched + hosted by Clueso server-side; a preview_url is included only so you can tell what it sounds like.
(fonts = the typefaces THIS WORKSPACE has uploaded as brand fonts, each with id, name and src. Pass a returned name as a text element's font_setting.font — that is the whole contract; you never pass the url. This list is the ONLY way to know which non-Google families actually exist here: a font_setting naming a family in neither this list nor Google Fonts silently renders Inter, with no error and a confident-looking layout.text_width_px measured against the wrong face. Check here before building a layout on a brand typeface.)
(image_gen_style_packs = generation style presets for generate_media kind='image' style_id; element_components = saved components (e.g. animations) from THIS WORKSPACE only — there is no community library for components (unlike clueprints); each reports param_keys. Insert one AS-IS with add_elements(component_id=...), or generate a variant from it with base_component_id.)
Filters (all optional): • query — for stock media it's the search phrase (real semantic search for provider='clueso'; provider keyword search otherwise). For clueprints a query runs a relevance-ranked search across your workspace + the global community library (search_summary, relevance_reason, tags, is_community, fork_count). For everything else it's a case-insensitive name substring. • provider — which stock library to search (ONE call, no merging). Choose by strength: images → 'pexels' (default; realistic photography) or 'pixabay' (illustrations, vectors, icons, clip-art — set image_type) videos → 'pexels' (default; real-world footage) or 'pixabay' (motion graphics — set video_type='animation') music → 'clueso' (default; our curated, brand-safe library with the best descriptions/search — try this FIRST) or 'freesound' (niche/genre tracks) sfx → 'freesound' (default; vast sound-effect library) or 'clueso' (curated sfx) • image_type — images + provider='pixabay': 'photo' | 'illustration' | 'vector' • video_type — videos + provider='pixabay': 'film' | 'animation' • id — exact id; returns just that one record (any type) • source — media only: 'org' | 'stock' | 'all' (default = org + stock). Under 'all', stock is appended only when a query is given. sfx is stock only. • folder_id — projects + saved media (images/videos/music): restrict to a folder • engine / language — voices only • creator_id / mine_only — clueprints only • orientation — stock images/videos: 'landscape' | 'portrait' | 'square' • color — stock images: a color name/hex, e.g. 'blue' • size — stock videos: 'large' | 'medium' | 'small' • min_duration / max_duration — stock videos + freesound audio: length bounds in seconds • page / limit — paging for large sets (projects, components, clueprints — a clueprint list is sliced to the limit with no marker when more exist, so page through rather than assuming the first page is everything); stock media ignores these (fixed shortlist)
Returns { type, count, items: [{ id, name, type, ... }] }. Feed the returned id straight into the consuming tool (set_voice, update_clips background, generate_media style_id, add_audio src, use_clueprint, etc.). Any duration on a returned item is in SECONDS — pass it straight to add_audio's source_duration.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Exact id — returns just that record. | |
| page | No | Page (default 1) — projects/element_components/clueprints. | |
| size | No | stock videos only: minimum resolution bucket. | |
| type | Yes | Resource type to find. | |
| color | No | stock images only: color name or hex, e.g. 'blue'. | |
| limit | No | Page size (default 50; voices default 5 — a '_more' item flags further pages). | |
| query | No | Case-insensitive substring match on name. | |
| engine | No | voices only: 'eleven' | 'cartesia' | 'google'. | |
| source | No | media types (images/videos/music/sfx) only: where to search — 'org' (your saved workspace media), 'stock' (stock library — images/videos via Pexels, music from Clueso's catalog), 'all' (both; default). sfx is stock-only. | |
| language | No | voices only: e.g. 'en'. | |
| provider | No | stock media: which library to search (exactly one). images/videos: 'pexels' (default — polished real-world photos & footage) | 'pixabay' (illustrations, vectors, clip-art, icons + more variety; pair with image_type/video_type). music/sfx: 'clueso' (default for music — our curated, brand-safe, well-described library, best semantic search) | 'freesound' (huge community library; best for niche music and sound effects — default for sfx). | |
| folder_id | No | projects/images/videos/music only: restrict to a folder. | |
| mine_only | No | clueprints only: only ones I created. | |
| creator_id | No | clueprints only: filter by creator id. | |
| image_type | No | stock images + provider='pixabay' only: 'photo' | 'illustration' | 'vector' (flat/drawn graphics, icons, clip-art). Use illustration/vector for graphic looks; photo (or Pexels) for realism. | |
| video_type | No | stock videos + provider='pixabay' only: 'film' (live footage) | 'animation' (motion graphics). | |
| orientation | No | stock images/videos only: result orientation. | |
| max_duration | No | stock videos + freesound audio: maximum clip length in seconds. | |
| min_duration | No | stock videos only: minimum clip length in seconds. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description discloses critical behavioral nuances: stock results are a shortlist, Freesound src is an opaque handle (not a URL), fonts are only from the workspace list and passing an unknown family silently renders Inter, clueprint lists are sliced without a marker requiring paging, and durations are in seconds. These go well beyond the annotation and materially change how the tool is used.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but appropriately so given 19 parameters and 13 types. It is front-loaded with the type list and filters, and every section carries unique value—from the font contract to the paging quirk. It could be tightened (some parentheticals are dense), but the structure (type list, then filter semantics) makes it navigable for an agent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
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 must explain return shape, and it does: '{ type, count, items: [...] }' plus how to feed ids into consuming tools. It covers edge cases like the Freesound opaque handle, font rendering fallback, and paging behavior for clueprints, leaving no gap for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description adds substantial meaning: provider-specific guidance (e.g., pexels vs pixabay for images), image_type/video_type pairing with pixabay, source behavior for 'all', the fact that stock media ignores paging, and the exact unit for duration. It enriches every parameter beyond the schema's terse descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Find any resource in Clueso by type' and enumerates all 13 types, clearly marking this as the single listing/search tool. It distinguishes itself from siblings by positioning it as the one tool for listing and searching across the workspace, with no ambiguity about what it does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance for each type and provider, including recommendations like 'try this FIRST' for clueso music and detailed provider strengths (e.g., pexels for realism, pixabay for illustrations). It also explains when to use 'all' vs 'stock' and how filters interact, leaving no doubt about selection criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_mediaGenerate AI media (image or animation)AInspect
Generate an AI image or canvas-code-based animation directly into a clip.
kind="image": text-to-image. Pass
prompt. Optional:animation_setting(entry/exit — set it HERE, see below),style_id(from find type='image_gen_style_packs'),reference_image_urlormcp_upload_idfor image-to-image grounding.kind="animation": canvas-code animation rendered from a prompt. Pass
prompt. Optional:voiceover_text(drives timing),base_component_id(reuse a saved animation as the starting point),reference_image_urlormcp_upload_idfor visual grounding.
Generation is asynchronous: the element is created immediately with a stable element_id and rendered in the background. Poll get_clip(select:['busy']) — an EMPTY busy means the render has landed. (This previously said to watch the phantom flag; phantom has never been a key get_clip returns, so there was nothing to poll.)
Set presentation up front. animation_setting is applied to the element as it is created, so the image enters correctly the first time it renders. Doing it afterwards with update_elements means writing to the element that is still generating, which is the write most likely to be refused while the generation holds it.
group is NOT accepted here, unlike add_elements: a generated element is built in the background, and the grouping would be overwritten when the render lands. Add it ungrouped, then call update_elements with group once it appears.
Tip: use this tool whenever the user asks for a "generated", "AI", or "create me a" visual. For uploaded photos / logos / icons / GIFs, use add_elements with element_type='image' and a src or mcp_upload_id instead.
| Name | Required | Description | Default |
|---|---|---|---|
| x | Yes | Top-left X in canvas pixels. | |
| y | Yes | Top-left Y in canvas pixels. | |
| kind | Yes | 'image' = AI text-to-image; 'animation' = canvas-code-based motion graphic. | |
| model | No | Image only. Which image model renders it. Default `gemini-3-pro-image-preview` (Nano Banana Pro), a strong general choice — leave it off unless you want one of the specifics below. `gemini-3.1-flash-image-preview` (Nano Banana 2) and `gemini-2.5-flash-image` are faster and cheaper. `gpt-image-2.5-flare` is OpenAI's fast one, `gpt-image-2.5-sunburst` its most precise editor, and `gpt-image-2` is the one to reach for when the image must carry legible text or follow several reference images. `gpt-image-1` / `gpt-image-1.5` are the older pair and only accept square-ish framing — a wide box is snapped to 4:3 rather than honoured, so do not pick them for a banner. An unlisted value is rejected here rather than silently swapped for the default, which is what the backend does with one. | |
| width | Yes | Width in pixels. | |
| height | Yes | Height in pixels. | |
| prompt | Yes | Generation prompt. For animations, be SPECIFIC: name the UI elements, interaction sequence, timing feel, and visual style. Vague prompts produce bad output. | |
| clip_id | Yes | Clip ID to place the generated element into. | |
| end_time | No | Disappear at (seconds). | |
| style_id | No | Image only. Style preset ID from find(type='image_gen_style_packs'). See resource clueso://docs/generation-styles. | |
| background | No | Image only, and only honoured by `gpt-image-2.5-flare`, `gpt-image-2.5-sunburst`, `gpt-image-1` and `gpt-image-1.5` — every other model is always opaque and ignores this. Pass `false` for a cut-out with no background: icons, logos, stickers, anything meant to sit ON the composition rather than behind it. You MUST set `model` to one of those four in the same call; `gpt-image-2.5-flare` is the one to default to, since the older pair cannot frame wide. Asking for transparency in the PROMPT instead does not work — the model paints a grey-and-white checkerboard as real pixels. | |
| project_id | Yes | Project ID. | |
| start_time | No | Appear at (seconds). | |
| aspect_ratio | No | Image only. Overrides the ratio inferred from width/height. Leave it off and the box decides, which is usually what you want — set it when the box is a placeholder and you know the shape you need. Still clamped to what the model accepts: gpt-image-1/1.5 only do 1:1, 4:3 and 3:4; the gpt-image-2.5 pair adds 16:9 and 9:16; gpt-image-2 has no 3:2 or 2:3, so those become 4:3 and 3:4. The response does not report the ratio used. | |
| mcp_upload_id | No | mcp_upload_id from the upload flow. Resolved server-side to a presigned URL before generation. | |
| voiceover_text | No | Animation only. Paces the motion to the spoken script — and as a side effect sets this clip's voiceover text and triggers speech generation for the clip. | |
| animation_setting | No | Image only. Entry/exit animation, same shape as add_elements' type_data.animation_setting. The design guide asks AI images to enter with `masked_reveal` or a slow fade, so set it here rather than following up with update_elements — that follow-up targets the element while it is still generating. Ignored for kind='animation', which animates through its generated code. | |
| base_component_id | No | Animation only. Reuse a saved animation component as the starting point (from find(type='element_components')). To re-skin its tunable parameters, set parameter_values via update_elements after it renders. | |
| reference_image_url | No | Public URL of a reference image. Mutually exclusive with mcp_upload_id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description clearly discloses that generation is asynchronous, that the element is created immediately with a stable element_id, and that the caller should poll get_clip(select:['busy']) until it is empty. It also warns that writes via update_elements are likely to be refused while generation is still in progress and that group would be overwritten when the render lands, none of which is available 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long because the tool is complex, but it is front-loaded, uses bullets for kind-specific guidance, and keeps warnings and corrections close to the behaviors they affect. Even the 'phantom' correction earns its place by preventing a known polling mistake.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 19-parameter async tool with no output schema and minimal annotations, the description covers the lifecycle, polling contract, caveats around writes and grouping, and the correct sibling tool for uploaded media. An agent has everything needed to invoke it safely and know what to expect.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description still adds significant meaning beyond the schema: it partitions optional parameters by kind, explains that animation_setting must be set at creation time, clarifies that group is not accepted, and points to find for style_id. This materially improves the agent's ability to construct correct calls.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence uses a specific verb and resource: 'Generate an AI image or canvas-code-based animation directly into a clip.' It names the two kinds explicitly and the tip at the end differentiates it from add_elements, so an agent can tell exactly what this tool is for.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives an explicit decision rule: use this tool for 'generated', 'AI', or 'create me a' visuals, and use add_elements for uploaded photos/logos/icons/GIFs. It also tells the agent when not to follow up with update_elements and explains that group is deliberately unsupported here, replacing it with a concrete two-step alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_articleGet articleARead-onlyInspect
Get the article content as markdown. Screenshots appear as <SCREENSHOT {id}> placeholders. Returns the markdown text and a list of screenshot IDs.
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | Yes | Project ID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, and the description adds useful behavioral detail: screenshots are rendered as <SCREENSHOT {id}> placeholders and the tool returns both the markdown text and screenshot ID list. It does not discuss error cases or authentication, but for a read-only getter this is adequate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three short sentences, front-loaded with the primary purpose, then a placeholder convention, then the return value. Every sentence adds necessary information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter, read-only tool with no output schema, the description sufficiently explains what is returned (markdown text plus screenshot IDs) and the placeholder behavior. An agent has enough information to invoke the tool and interpret its result correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is only one parameter, project_id, and the schema description ('Project ID') provides 100% coverage. The tool description adds no extra meaning about the project_id format or how to obtain it, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource ('Get the article content as markdown') and clearly distinguishes this getter from siblings like get_project, get_clip, and get_comments. The output format is stated up front, so an agent can tell exactly what this tool retrieves.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance about when to use this tool versus alternatives such as get_project or get_clueprint, nor any mention of prerequisites or exclusions. The description simply states the operation without situating it among sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_clipGet clip detailsARead-onlyInspect
Read one clip: its elements (positions/sizes in canvas pixels), voiceover (text, voice, duration, voiceover_volume), background and transition. Pass render to also get a PNG of the frame.
ASK FOR WHAT YOU NEED. A full read is large — on a dense clip the per-word voiceover array and the element type_data blobs dominate it, and repeated full reads are the main way a long session runs out of context. select returns exactly the parts you name:
select: ['elements.x','elements.y','elements.width','elements.height'] → geometry only, to fix a layout select: ['elements.name','elements.start_time','elements.end_time'] → a timing pass select: ['voiceover_words'] → word timings only, to sync visuals to narration select: ['elements.textdata','voiceover_words'] → rewrite copy against the VO select: ['elements'] → whole element rows, no words select: ['groups'] → group rows only, to get a group_id for update_groups select: [] → no JSON at all (pair with render for the PNG alone — smallest read) (omit select) → everything; fine for a first look, expensive to repeat
render is the other output, and it is separate from select: select shapes the JSON, render produces a PNG.
render: {} → the frame at t=0 render: { timestamps: 2.5 } → the frame 2.5s into the clip render: { timestamps: [0.5, 2, 4] } → those three moments as ONE labelled grid render: { timestamps: [...], layout:'separate'} → the same moments as full-size images (~4x the tokens) render: { save: true } → also uploads the frame and returns presigned_url render: { max_width: 1280 } → a sharper frame when you must read small print select: [], render: {} → the PNG alone, no JSON select: ['elements'], render: {} → element rows AND the frame
A single frame renders 960px wide by default — legible for this design system and about half the tokens of a 1280 frame. A GRID defaults to 1280, because that is the width of the whole grid and a third of 960 would leave each cell unreadable. Either way max_width caps the image you get back; raise it only to read genuinely small print.
Omitting render renders nothing. timestamps, layout and save live inside it because they only mean anything for a render — there is no way to ask for them without asking for the image.
element_ids is the other axis: it picks WHICH element rows come back, independently of select. Combine them for the leanest read — e.g. element_ids: ['el_9'], select: ['elements.x','elements.y'].
Element shape: universal wrapper fields (id, element_type, name, x, y, width, height, start_time, end_time, rotation) plus type-specific data (textdata/shapedata/imagedata/videodata/zoomdata) plus an optional keyframes array when animated. Keyframes come back in the same flat wire shape add_elements takes — { timestamp, positionX?, positionY?, width?, height?, interpolation? } in canvas pixels — so you can round-trip read → edit → update_elements without reshaping.
Clip-level fields include transition (the current transition object — sibling of the update_clips transition arg; null if none) and voiceover_words (per-word timestamps, {word, start, end, punctuated_word} with start/end in SECONDS; null on clips with no transcription).
| Name | Required | Description | Default |
|---|---|---|---|
| render | No | Render the clip as an image. Presence of this object IS the request to render — omit it and nothing is rendered. `{}` renders at t=0. Independent of `select`, which only shapes the JSON: pair `select: []` with `render: {}` for the PNG alone (smallest read). CHECKING YOUR WORK: pass `timestamps` with SEVERAL mid-clip moments, not the t=0 default — text and image elements have entry animations (a ~0.4s slide/fade by default), so at t=0 they have not arrived yet and a correct edit renders as an empty frame, while shapes have no entry animation and do show at t=0. That mix is what makes a single t=0 render actively misleading: some elements appear and others don't. A list comes back as one grid for about a quarter of the tokens of the same frames separately, so checking several moments is the cheap option, not the expensive one. `animations: false` draws everything settled if you would rather not pick moments at all. | |
| select | No | Ask for exactly the JSON you want, GraphQL-style. Omit for everything; pass [] for none. Sections: 'elements' (whole element rows), 'voiceover_words' (per-word VO timings; returns the key of the same name, holding `{word, start, end, punctuated_word}` with start/end in SECONDS — null on a clip with no transcription), 'groups' (group rows: id, name, parent_id, bounds_px, anchor_px, keyframes), 'busy' (generations still writing to this clip, as `[{entity_path, job_type}]` — EMPTY means nothing is pending, which is how you know a voiceover or AI image has landed; it is the same lock that would refuse your write, so a non-empty list also tells you what not to touch yet). Each section returns the key it is named after. Rendering is `render`, not a value here. Per-key: 'elements.<key>' projects element rows to just those keys (id is always kept). Keys: name, element_type, x, y, width, height, start_time, end_time, rotation, keyframes, textdata, shapedata, imagedata, videodata, zoomdata, codedata, parent_id, dropShadows. y_top is text-only and present ONLY when alignment is 'center' — the unambiguous TOP edge, which is exactly the case where `y` is NOT the top but the vertical CENTRE. To put that position back, send it as `y` with y_anchor:'top'. Examples: ['elements.x','elements.y','elements.width','elements.height'] to read geometry; ['elements.name','elements.start_time','elements.end_time'] for a timing pass; ['voiceover_words'] to sync visuals to narration; ['groups'] to resolve a group id for update_groups; [] with render:{} returns the PNG with no JSON (smallest read); ['elements.textdata','voiceover_words'] to rewrite copy against the VO. Mixing 'elements' with 'elements.<key>' returns whole rows. Use element_ids to choose WHICH rows — that is independent of this. | |
| clip_index | Yes | Zero-based clip index | |
| project_id | Yes | The project ID | |
| element_ids | No | WHICH element rows to return — all others are dropped. Independent of `select`, which chooses the sections/keys. Use it to re-inspect just what you added or updated; most add_elements/update_elements already echo the element's resolved layout, so often you don't need this at all. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint and destructiveHint annotations, the description discloses critical behavioral details: full reads are large and can exhaust context, render and select are independent, a t=0 render can be misleading due to entry animations, default image widths and token costs, and exactly what shape the returned data takes. This is exceptionally transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long, but the tool is genuinely complex and the length is earned. It is front-loaded with the purpose and a context-cost warning, and uses well-organized code examples. There is some redundancy with input-schema descriptions, particularly around render and animations, but overall it is structured and readable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description fully covers what the tool returns, including element shape, voiceover_words null semantics, groups, busy, element_ids, render defaults, and cost implications. Since there is no output schema, this narrative carries the full burden, and it does so comprehensively.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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, but the description adds meaningful usage semantics: element_ids is an independent axis, select projections are demonstrated with concrete results, render flags are explained, and keyframes round-trip without reshaping. Some of this duplicates the already-rich schema descriptions, which keeps it from a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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: 'Read one clip' and enumerates exactly what is returned (elements, voiceover, background, transition). It makes the tool's scope unambiguous, though it does not explicitly name or contrast a sibling tool such as get_project or get_clueprint.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when to use different select/render modes, with task-oriented examples like 'to fix a layout', 'a timing pass', and 'to sync visuals to narration'. It also warns that an omitted select is fine for a first look but expensive to repeat. It does not explicitly state when not to use this tool versus sibling get_* tools, but the intended usage is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_clueprintGet clueprintARead-onlyInspect
Fetch clueprint data. Use include to control how much you pull back:
include="metadata": just the clueprint's name/description/tags/visibility/thumbnail.
include="tree": metadata + the full file tree (path, mime_type, and size per entry). Call this first when exploring an unfamiliar clueprint.
include="files": the contents of the files listed in
file_paths(no metadata — call include='tree' first if you also need metadata). Text inline, binary as presigned GET URLs.include="all": metadata + the file tree + the contents of every file in the clueprint (use sparingly on large clueprints).
Calling this also logs the clueprint as "used" (fire-and-forget) so the workspace's recents list stays accurate — no follow-up use_clueprint call needed.
| Name | Required | Description | Default |
|---|---|---|---|
| include | No | What to return: 'metadata' | 'tree' | 'files' | 'all'. Defaults to 'tree'. | tree |
| file_paths | No | include='files' only: relative paths to read (e.g. ['design/colors.md', 'rules/voice.md']). Ignored for other modes. | |
| clueprint_id | Yes | ID of the clueprint. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description discloses a real behavioral side effect: calling this tool logs the clueprint as 'used' in a fire-and-forget manner. It also explains return behavior clearly — text inline, binary as presigned GET URLs — which is essential since there is no output schema to cover this.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is organized as a scannable bulleted list with the opening summary first. Each bullet adds distinct information — mode semantics, ordering advice, return-format details, and side effects — with no redundant or filler content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and an enum whose values drastically change return shape, the description carries the full burden and succeeds. It specifies what comes back in every mode, how file contents are represented, when file_paths is used, and what side effect occurs, so an agent has everything needed to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents all three parameters, but the description adds substantial meaning: what each include value actually returns, that file_paths is only honored in 'files' mode, the relative-path example, and the default value of 'tree'. This goes well beyond the baseline schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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 — 'Fetch clueprint data' — and then expands into four distinct include modes that make the tool's exact behavior clear. It is plainly distinguishable from create_clueprint and update_clueprint siblings, which are mutations rather than fetches.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit guidance for each include mode: use 'tree' first when exploring, call 'tree' before 'files' if metadata is needed, and use 'all' sparingly on large clueprints. It even tells the agent that no separate use_clueprint follow-up is required, resolving a potential ambiguity about how usage is recorded.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_commentsGet commentsARead-onlyInspect
Read the review comments on a project — the other half of add_comment, which could post but never read.
Comments are how a human reviewer tells you what is wrong with a video: a note pinned to a clip and a moment inside it. Read them before an editing pass so you act on what was actually asked for, and read them again after a build if a reviewer has seen it.
Threads come back nested: each top-level comment carries its replies. Reply into a thread with add_comment(parent_comment_id=...) rather than posting a new top-level note — a reviewer reading their own thread is how they see that their point was handled.
Resolved threads are hidden by default, so a plain read is "what still needs attention".
| Name | Required | Description | Default |
|---|---|---|---|
| clip_id | No | Only comments pinned to this clip. Omit for every comment on the project, project-level ones included. | |
| project_id | Yes | The project (guide) ID | |
| include_resolved | No | Include threads already marked resolved (default false). Turn it on to see history; leave it off to see the work outstanding. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as readOnly and non-destructive, and the description adds meaningful behavior beyond that: comments come back nested with replies, resolved threads are hidden by default, and a plain read represents outstanding work. This gives the agent accurate expectations about response shape and filtering behavior with 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: the opener defines the tool, the middle sentences give usage context, and the closing sentence clarifies default behavior. It is front-loaded with the core purpose and contains no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
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 burden of explaining the return shape; it states that threads are nested with replies and that resolved threads are hidden by default. Combined with full parameter documentation and clear annotations, an agent has sufficient context to invoke this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 adds value beyond the schema by explaining the practical meaning of include_resolved: history versus outstanding work, and by clarifying that omitted clip_id means project-level comments are included. project_id is not further enriched, but the additional context for the other parameters justifies the higher score.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: "Read the review comments on a project." It also explicitly distinguishes itself from add_comment, naming it as the sibling that posts but never reads. An agent can immediately determine what this tool does and how it differs from nearby tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance: read before an editing pass, and again after a build if a reviewer has seen it. It also names the alternative action for replying to a thread, add_comment(parent_comment_id=...), and warns against creating a new top-level note.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_design_guideGet design guideARead-onlyInspect
Clueso's house style for composing video clips — how to think about concept, typography, color, composition, motion, and pacing. Read it before composing or editing a clip's visuals when you're NOT following a clueprint, or to fill gaps a clueprint leaves silent. General craft, not clueprint-specific.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds no additional behavioral traits (e.g., output format or length of the guide), but since it's a simple read operation, this is acceptable and matches the calibration for read-only tools.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long, with the core purpose stated first, followed by usage guidance. There is no wasted language, and every phrase adds value, making it efficient and front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no parameters, no output schema, and simple annotations, the description is complete. It tells the agent exactly what the guide covers, when to use it, and how it relates to clueprints, leaving no ambiguity about when to call this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there is no schema to add meaning. The baseline is 4, and the description does not need to explain any parameters; it correctly focuses on when to use the guide.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool provides Clueso's house style for video composition, covering specific aspects like concept, typography, color, composition, motion, and pacing. This is a specific resource (design guide) with a clear purpose, distinct from any sibling tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use the tool: before composing or editing a clip's visuals when NOT following a clueprint, or to fill gaps a clueprint leaves silent. It also explicitly says the guide is general craft, not clueprint-specific, so agents know when it's not the right tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_element_schemaGet element schemaARead-onlyInspect
Return the schema for an element type's type_data, as TypeScript declarations. Call this before add_elements / update_elements when you don't already know the field shape for the element_type you're placing.
Pass element_type='group' for the GROUP surface instead — what a group is, how its pivot works, and the nine properties it can animate.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | 'add' returns required + optional fields; 'update' returns all-optional. | add |
| fields | No | Return only these fields, with their prose — text is 15KB whole, ~300 bytes for two. Omit while learning the type: only the full schema carries the keyframable list and the keyframe rules. | |
| format | No | Defaults to 'declarations' — TypeScript-style, which is the better READ. Inside run_script it defaults to 'json' instead, because a script indexes into the structure and the declaration text would arrive newline-escaped. Set it explicitly to override either default. | |
| element_type | Yes | One of: text, callout, rectangle, arrow, blur, spotlight, zoom, image, video, animation, group |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds output-format context and the GROUP special case but does not disclose additional runtime behaviors such as auth, rate limits, or side effects; it stays at the baseline with annotations present.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short paragraphs with the core purpose front-loaded in the first sentence, followed by the usage trigger and the one special case. No filler or repetition of schema contents.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only schema lookup, the description plus fully documented input schema covers trigger, output format, parameter semantics, and the group special case. No output schema is needed because the tool's output is the schema itself and its representation is stated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 goes beyond the enum by explaining that element_type='group' is the GROUP surface and specifies what that returns, adding meaning the schema's one-line enum description lacks.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Return the schema for an element type's type_data, as TypeScript declarations.' It also distinguishes itself from sibling mutation tools by naming add_elements/update_elements and the GROUP special case, so an agent can tell exactly what it is for.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger: call before add_elements/update_elements when the field shape is unknown. It also gives an explicit alternative path for element_type='group' and implies the exclusion of calling when you already know the field shape.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_projectGet project dataARead-onlyInspect
Get a summary of a project: canvas dimensions, per-clip summary (ids, indices, durations, element counts, voiceover_volume), and audio_tracks — every music/SFX entry on the project flattened to the same wire shape add_audio accepts (id, src, name, source_duration, guide_start_time/end_time, music_start_time/end_time, volume, loop, fade_in, fade_out). To copy an audio track to another project: read it from audio_tracks here and feed the same fields to add_audio on the target project. Call this to understand what's in the project before making changes.
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | Yes | The project ID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds value by detailing that audio_tracks are flattened to the add_audio wire shape and that this is a summary rather than the full project, giving agents insight into data shape and compatibility beyond 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but well-organized: it front-loads the purpose, then specifies output structure, then gives a concrete usage workflow. Every sentence earns its place, though the field list makes it longer than minimal.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the single parameter, read-only annotations, and absence of an output schema, the description provides substantial context: the shape of per-clip data, the audio_tracks wire format, the copy workflow, and the recommended call timing. Minor unanswered details like error cases or formatting are not critical here.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with project_id described as 'The project ID.' The description does not add further parameter-level detail, but the schema fully documents the only parameter, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource ('Get a summary of a project') and enumerates the exact contents (canvas dimensions, per-clip summary, audio_tracks). This clearly distinguishes it from sibling tools like get_clip or get_article.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to call it: 'Call this to understand what's in the project before making changes.' It also gives a concrete workflow for copying audio tracks via add_audio. It does not name alternative getters it should not be used for, but the usage context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_script_jobGet a script job's resultARead-onlyInspect
Fetch the outcome of a run_script that did not finish inline. Waits for it rather than returning immediately, so one call is usually enough — set wait_seconds to how long you are willing to hold.
Returns { job_id, status, result?, error? }. status is processing, completed or failed; result carries the same { ok, result, stdout, ops } the inline reply would have. The script runs to completion whether or not you poll.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | From the run_script reply. | |
| wait_seconds | No | How long to wait for completion before answering, default 45s. Pass 0 for an immediate status check. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the operation as read-only and non-destructive, and the description adds meaningful behavioral detail: it waits rather than returning immediately, returns a well-defined status shape, and notes that the underlying script runs to completion whether or not it is polled. This goes beyond what the annotations provide and helps the agent set expectations correctly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: the core purpose appears in the first sentence, followed by behavioral and return-shape details. Every sentence earns its place, and there is no filler or redundant restatement of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
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 compensates by specifying the exact return object, the possible status values, and the shape of result. Combined with full parameter schema coverage and read-only annotations, an agent has everything needed to call the tool correctly and interpret its response.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with both job_id and wait_seconds already documented including defaults and semantics. The description restates the wait_seconds idea but does not add significant meaning beyond the schema. Baseline 3 is appropriate because the schema carries the parameter documentation burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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: 'Fetch the outcome of a run_script that did not finish inline.' This clearly identifies what the tool does and distinguishes it from run_script, the sibling that starts the job. The title and description align, and an agent can understand the tool's role 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear usage condition: use this when run_script did not finish inline, and one call is usually enough. It also explains how to tune wait_seconds for the desired blocking behavior. It does not explicitly name alternatives or state when not to use the tool, but the inline-completion condition implies the boundary.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_screenRecord screenAInspect
Create a screen-recording clip in a project. Creates blank placeholder clips, registers job entities, and sends the job to AVS.
The blank clips this tool creates are placeholders; they become video clips when processing completes, so removing one loses that scene. Article placeholders are also inserted automatically into plainDoc.
Requires the Auto-Recording add-on and per-workspace sign-in credentials for the product being recorded. Workspaces without it get back the manual path instead (upload_file, then add_clips(kind='video')) rather than a failure.
| Name | Required | Description | Default |
|---|---|---|---|
| scenes | Yes | REQUIRED — the recording to make, as a list of scenes. This is the ONLY way to specify what to record. A normal single recording is exactly ONE scene; a code-wizard multi-scene / marketing video is N scenes (one clip per scene, and ALL cuts of one video go in a SINGLE record_screen call). A narrated scene REQUIRES a non-empty narration_script; a b-roll scene is silent (no narration, no article). A cut that starts somewhere disconnected is just a scene with entry.mode "fresh". Cleopatra orgs accept exactly ONE narrated scene. Do not set scene_id — it is assigned server-side. | |
| chat_id | Yes | Conversation context ID | |
| guide_id | Yes | Target guide ID | |
| language | No | Language code for the recording (default: en) | en |
| edit_scene_ids | No | The clip id(s) this edit replaces. Only used when recording_session_id is set; scenes you do not name are not re-filmed. Set preceding_clip_id to the clip you are replacing — an edit naming a clip that is not in the guide is refused rather than appended to the end. | |
| video_intention | No | One-line intent shared across all scenes of a multi-scene recording (e.g. "punchy 30s launch teaser for feature X"). Ignored for single-scene recordings. | |
| preceding_clip_id | Yes | Clip ID after which to insert the new clip | |
| video_script_mode | No | How the narration is treated. 'exact': the user's narration is final and is read word for word; steps the script does not mention play silently. 'near_exact': keep the user's narration word for word, but briefly narrate steps the recording must take that the script does not mention (for example opening a settings dialog to reach something) — use this when the user gives a finished script and did not ask for strictly exact wording. 'rewrite': the narration is a draft and may be reworded to match what was recorded — use this when there is no user script or it is rough. Overrides exact_video_script when both are set. | |
| exact_video_script | No | Legacy flag — prefer video_script_mode instead. Set to true when the video narration must be used exactly as written — the agent that does the recording will not reword, rephrase, or rewrite video_script at all. Default false. | |
| article_script_mode | No | 'exact': the article is used word for word. 'rewrite': the article may be reworded to match the recording. Overrides exact_article_script when both are set. | |
| custom_instructions | No | Optional per-recording instructions (e.g. "select project X", "add rectangle 200x100"). Not related to mocking. | |
| exact_article_script | No | Legacy flag — prefer article_script_mode instead. Set to true when the article must be used exactly as written — the agent that does the recording will not reword, rephrase, or rewrite article_script at all. Default false. | |
| recording_session_id | No | EDIT an existing recording instead of shooting a new one. Pass the recording_session_id from the record_screen that made it, or read it off get_clip. The recorder restores that take's code, notes and click script and changes only what you ask for, which is far faster and cheaper than re-recording. Omit for a fresh recording. Only code-wizard recordings are editable; get_clip omits the field for any clip that is not. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, destructiveHint=false, and openWorldHint=true, so the description's job is to add context beyond those flags. It does: it discloses that blank placeholder clips are created and become real video clips only when processing completes, that removing one loses that scene, that article placeholders are inserted into plainDoc, and that the tool requires the Auto-Recording add-on and credentials. This is meaningful behavioral context beyond the annotations. It doesn't fully describe failure modes or processing lifecycle, but it covers the most important side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core action and side effects, then moves to requirements and fallback. It is somewhat long, but every sentence earns its place: the placeholder behavior, the article insertion, the add-on requirement, and the manual fallback are all non-obvious facts an agent needs. The scenes parameter description is verbose but contains critical usage rules (single vs multi-scene, narrated vs b-roll, Cleopatra orgs).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex 13-parameter tool with no output schema, the description covers the key behavioral context: what the tool does, what side effects it has, when it is available, and what the fallback is. It doesn't describe the return value or how to check job status, but the sibling get_script_job and get_clip exist for that, and the schema covers parameters. The main gap is that the description doesn't explicitly state what the response contains (e.g., recording_session_id), though the schema's recording_session_id parameter hints at it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 13 parameters thoroughly. The description adds value by explaining the scenes array is the ONLY way to specify what to record, clarifying single vs multi-scene semantics, and noting that scene_id is assigned server-side. It also explains the edit path via recording_session_id and the fallback behavior for edits. This goes beyond the schema's per-field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Create a screen-recording clip in a project') and immediately distinguishes the tool's behavior from a simple upload: it creates blank placeholder clips, registers job entities, and sends the job to AVS. This clearly separates it from siblings like upload_file and add_clips.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use this tool (Auto-Recording add-on present, per-workspace credentials available) and names the fallback path (upload_file, then add_clips(kind='video')) for workspaces without it. It also explains the multi-scene vs single-scene usage in the scenes parameter description, which is strong usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_clipRemove clipADestructiveInspect
Remove a clip from the project by index. Cannot remove the last remaining clip.
After removal, all clips with index > clip_index shift down by 1. When removing multiple clips by index, remove from highest index to lowest (or capture clip_ids first and re-derive indices between calls). Concurrency: whole-project mutation (conflict domain: the entire project) — serialize. Do not run it in parallel with ANY other mutation on the same project_id, including element/voiceover edits; run them one at a time. (Mutations to different projects run in parallel freely.)
| Name | Required | Description | Default |
|---|---|---|---|
| clip_index | Yes | Zero-based clip index to remove | |
| project_id | Yes | The project ID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only indicate destructiveHint=true, but the description discloses much more: higher-index clips shift down by 1 after removal, the last remaining clip cannot be removed, the mutation conflicts with all other mutations on the same project, and different projects can run in parallel. This is substantial behavioral context beyond what the annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: the core operation, the last-clip constraint, index-shift behavior, multi-removal ordering, and concurrency rules. The description is front-loaded with the primary action and then expands into necessary edge cases without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive two-parameter mutation with positional side effects, the description is effectively complete. It covers the main action, edge case, post-conditions, multi-call strategy, and concurrency semantics. The lack of an output schema is not a significant gap because the description focuses on the behaviors needed to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 adds value by explaining that clip_index changes meaning as clips shift down, and by advising a specific removal order when multiple indices are involved. This goes beyond the schema's simple 'zero-based clip index to remove.'
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear verb and resource: 'Remove a clip from the project by index,' and adds a meaningful invariant ('Cannot remove the last remaining clip'). It does not explicitly compare itself to sibling tools like remove_from_project or remove_elements, but the index-based target makes the operation specific and identifiable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives strong procedural guidance: remove from highest index to lowest when deleting multiple clips, and serialize with any other mutation on the same project_id. It does not explicitly name alternative tools or state when to prefer another tool, but it clearly conveys when and how to use this one safely.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_elementsRemove elements from clipsADestructiveInspect
Remove many elements across one or more clips in a single tool call. One entry per element ({clip_index, element_id}).
Concurrency: parallel-safe (conflict domain: the individual element) — same as update_elements. Each removal is a granular element_remove patch scoped to that element id, and the whole batch lands in ONE save. Fan out across subagents as long as they touch DIFFERENT element ids. Two concurrent edits to the SAME element id do not last-write-win — the later one is REJECTED and nothing is written; re-read and re-apply. Do NOT run concurrently with whole-clip/whole-project mutations on the same guide (update_clips on that clip, structural clip ops, add_audio, update_project). To remove an audio track (not an element), use remove_from_project(target='audio').
| Name | Required | Description | Default |
|---|---|---|---|
| removals | Yes | Elements to remove — at least one entry. | |
| project_id | Yes | Project ID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavioral context beyond the annotations: the whole batch lands in one save, conflicting simultaneous edits are rejected rather than last-write-win, and the tool is safe to parallelize only under specific conditions. It also clarifies scope boundaries with sibling operations, making the destructive behavior well understood.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every sentence earns its place: purpose, entry shape, concurrency model, conflict behavior, and sibling tool routing. It is front-loaded with the core action and packs dense, non-redundant guidance without filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, concurrency-sensitive batch tool, the description covers what is removed, how conflicts are resolved, when fan-out is safe, which operations must not run concurrently, and how audio tracks should be handled instead. No critical operational detail appears to be missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents project_id, removals, clip_index, and element_id fully. The description reinforces the one-entry-per-element shape, but does not add meaningful parameter-level details beyond what the schema already provides, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific operation: removing many elements across one or more clips in a single call, with one entry per {clip_index, element_id}. It clearly distinguishes element-level removal from audio-track removal and from whole-clip mutations, so an agent can tell it apart from remove_clip and remove_from_project.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit concurrency guidance: it is parallel-safe within a conflict domain, fan-out is allowed for different element ids, same-id concurrent edits are rejected, and it must not run concurrently with whole-clip/whole-project mutations. It also names the alternative tool path for audio tracks, remove_from_project(target='audio').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_from_projectRemove element, group or audio trackADestructiveInspect
Remove an element, a group or an audio track from a project.
target="element": removes an element (requires element_id, or element_ids for several). clip_index is optional — the element is located by id; pass it only as a hint
target="group": removes a GROUP node (requires clip_index + group_id). By default its children survive — they rise to the removed group's own parent, which for a top-level group is the clip root. Pass keep_children=false to delete the whole subtree instead, every nested group and every element inside it.
target="audio": removes a music/SFX track (requires music_id — returned by add_audio)
Concurrency: target='element' is element-scoped (conflict domain: the individual element) — parallel-safe with other element edits on different elements, same as remove_elements. target='audio' is a whole-project mutation — serialize it against any other mutation on the same project_id. (Mutations to different projects run in parallel freely.)
| Name | Required | Description | Default |
|---|---|---|---|
| target | Yes | What to remove: 'element', 'group' or 'audio' | |
| group_id | No | Group ID to remove (required for target='group') | |
| music_id | No | Music/SFX track ID to remove (required for target='audio') | |
| clip_index | No | Zero-based clip index. Required for target='group'; for target='element' an optional hint — the element is found by id either way | |
| element_id | No | Element ID to remove (target='element'; or use element_ids) | |
| project_id | Yes | The project ID | |
| element_ids | No | Several element IDs to remove (target='element'). Removed one at a time, so a failure part-way leaves the earlier ones removed; retrying the same list is safe — ids already gone come back as already_absent. For a large batch prefer remove_elements, which lands in one save | |
| keep_children | No | target='group' only. Omit/true ungroups: children rise to the removed group's own parent. false deletes the whole subtree. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even though destructiveHint=true already signals mutation, the description adds rich behavioral context: grouping children survive by default, keep_children=false deletes the whole subtree, element_ids are removed one at a time with safe retries, and audio removal is a whole-project mutation. This goes far beyond 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured with bullet-like target sections and a concurrency paragraph. It is dense but not bloated; every sentence carries meaningful operational or safety information. The upfront summary is immediately followed by mode-specific details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers all three removal modes, required and optional parameters, default behavior, failure semantics, concurrency constraints, and when to prefer a sibling tool. Given there is no output schema, the lack of return-value detail is not a completeness gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so a baseline of 3 applies. The description still adds meaning by clarifying the role of clip_index as an optional hint for element, a requirement for group, and explaining the default behavior of keep_children. It also frames element_ids versus element_id usage clearly, though much is repeated from the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear, specific statement: 'Remove an element, a group or an audio track from a project.' It identifies the exact verb, resource types, and scope. It further differentiates from the sibling tool remove_elements by recommending it for large batches.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance per target mode, listing required parameters for each. It also names an alternative tool (remove_elements) for large batches and gives concurrency rules for when parallel use is safe versus serialized.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reorder_elementsReorder elements within a clipAInspect
Reorder the elements inside a clip. List position IS the z-index — later entries in ordered_element_ids render on top of earlier ones.
You MUST pass the full set of element IDs currently in the clip. The handler rejects partial lists so a reorder can never silently drop an element. Get the current list via get_clip — the order it returns is exactly the order this takes.
Works on grouped clips. Elements keep their group; moving a group's members together moves the whole group relative to everything else. The one thing a group cannot do is render in two pieces, so an order that puts a non-member BETWEEN two members of the same group is rejected and names the group — put the group's elements next to each other, or take the element out of the group first with update_elements(group).
| Name | Required | Description | Default |
|---|---|---|---|
| clip_index | Yes | Zero-based clip index. | |
| project_id | Yes | Project ID. | |
| ordered_element_ids | Yes | All element IDs currently in the clip, in the new order. Position N = z-index N (later = on top). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses several important behaviors beyond annotations: the rejection of partial lists to prevent silent drops, the z-index rendering rule, grouped-clip behavior, and the specific rejection of orders that split a group with a non-member between its members. This gives an agent accurate expectations for validation and failure modes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the essential z-index rule, followed by input requirements and group caveats. Every sentence carries meaningful operational information, and the structure guides the agent from general behavior to specific constraints without wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with three required parameters and no output schema, the description is complete: it explains what the tool does, how to source the required list, what order semantics are, and how the handler handles invalid or group-splitting inputs. No critical calling information is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the ordered_element_ids schema already explains position and z-index. The description adds value by requiring the full current list, directing the agent to get_clip for the exact order, and explaining group-related constraints on the order. This is more than the baseline but not a large semantic leap beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence uses a specific verb and resource: 'Reorder the elements inside a clip,' and immediately defines the core semantic (list position is z-index, later entries render on top). This clearly distinguishes reorder_elements from siblings like add_elements, remove_elements, and update_elements.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage conditions: callers must pass the full set of element IDs currently in the clip, partial lists are rejected, and get_clip is named as the correct way to obtain the current order. It also names an alternative action, update_elements(group), for removing an element from a group before reordering.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_scriptRun a script that calls these toolsADestructiveInspect
Write a JavaScript program that calls this server's other tools. You have the whole language: loops, arithmetic, functions, conditionals, and values carried from one call into the next — all running next to the tools instead of across the conversation. Use it whenever code says the thing more directly than a sequence of separate calls would, which is often.
COMPUTE, don't hand-write. Anything you would otherwise work out in your head and type as literals is better computed here — eased keyframe tracks, staggered start times, grid coordinates, derived palettes, positions from measured text widths. This is usually what makes motion look right: sample a curve at ten points and emit the values, rather than guessing four.
DON'T COMMENT THE SCRIPT. Nobody reads it — it runs once and is gone. Comments, blank lines and explanatory names are pure cost here. Write it dense.
The one thing to remember: inside a script you see only what you return or log, so a tool's own rich output (layout measurements, layout_qa, new ids) has to be surfaced deliberately. That also makes a single-call script worthwhile when a read is fat — find takes no projection argument, so logging the 200 characters you need is a real saving.
A fat read is usually better narrowed at the source than filtered here: get_clip takes select, and get_element_schema takes fields (name what you're setting and a 15KB schema becomes ~200 bytes). get_element_schema returns TEXT by default, which you cannot index into — pass format: 'json' when you want to compute over the schema rather than log it.
CALLING TOOLS Every tool except run_script and get_script_job is a global function taking exactly the arguments it takes normally, and returning its parsed result (those two are excluded so a script cannot recurse into itself or poll its own job). Calls are synchronous — do NOT use async/await, and there are no imports.
sleep(ms) waits, synchronously like everything else here. Use it to poll a generation: generate_media and voiceover_batch return before their work lands, and get_clip(select:['busy']) says what is still being written. A sleep longer than the script's remaining time FAILS the run with a budget error rather than overrunning it or returning early (a run that hands off to a background job gets the job budget, and a sleep already waiting picks that up) — and it holds one of the few concurrent script slots while it waits, so poll on the order of seconds, not milliseconds.
const p = create_project({ title: "Launch" }); const made = add_clips({ project_id: p.projectId, kind: "blank", clips: [{ duration: 4 }] });
Use the BARE tool name. If your client shows these tools under a prefix, the prefixed form works too — mcp__clueso_connect__add_elements and clueso__add_elements both resolve to add_elements. tools() lists every callable name; call(name, args) invokes one by a name computed at runtime.
WHY IT IS CHEAPER What you construct never passes through the conversation. Build an array in a loop and send it in ONE batched call — a 24x24 dot grid is six lines here versus 576 elements of JSON:
const els = []; for (let r = 0; r < 24; r++) for (let c = 0; c < 24; c++) els.push({ x: c * 60, y: r * 60, width: 8, height: 8, type_data: { backgroundColor: "#C462F5" } }); add_elements({ project_id, defaults: { clip_index: 0, element_type: "rectangle" }, elements: els });
READ, THEN WRITE — this is how you edit in bulk:
const clip = get_clip({ project_id, clip_index: 0, select: ["elements.name", "elements.y"] }); const captions = clip.elements.filter(e => e.name.startsWith("caption")); update_elements({ project_id, defaults: { clip_index: 0 }, updates: captions.map(e => ({ element_id: e.id, y: e.y + 40 })) });
WHAT COMES BACK
return a value to hand it back, and console.log anything you want to see — that output is all you pay for, so log summaries, not payloads. print_json(obj, maxBytes) logs an object and truncates it for you, which is safer than hand-rolling JSON.stringify(...).slice(...) at every call site.
You get { ok, calls, writes_applied, result, stdout }. writes_applied matters because a script is NOT a transaction: if it throws on call nine, the first eight writes already landed, and that count is how you tell.
A FAILED TOOL CALL THROWS. It does not return an error object, so a failure stops the script instead of letting it run on against bad state. Wrap a call in try/catch only when you genuinely intend to continue.
You get every tool's normal result, so succeeded/failed counts, per-element layout (font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits plus adjusted when your height was replaced — widen to natural_width_px, not text_width_px) and layout_qa findings are all readable in the script. Check them and react.
NO IMAGES are returned inside a script — a render in a loop would flood the reply. But you are not blind: get_clip({..., render: { save: true }}) gives the script a presigned_url and s3_key for the rendered frame, so it can render many frames, keep the URLs, and hand them on (update_clueprint takes one as source_url). _images_omitted counts the frames withheld; when the reply would be a bare array it arrives as {items, _images_omitted}. Call get_clip yourself, outside a script, when YOU need to look at one.
FINISHING
Fast scripts return their result here. If one is still running after wait_seconds (default 45s) you get { job_id, status: "processing" } and it keeps running — poll get_script_job. Set idempotency_key on anything that builds, so a retry cannot run it twice — a key that already ran is never re-executed, failed runs included.
LIMITS: 200 tool calls, 45s of run time inline and 5 minutes once it hands off to a job, 16KB each of logged output and returned value. dry_run runs reads for real and only records writes. Anything costing credits errors as it normally would.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | JavaScript. Tools are globals called synchronously — no async/await, no imports, no network or filesystem. `return` a value to hand it back. | |
| dry_run | No | Read-only tools still run; anything that writes is recorded and skipped. Use it to check what a script would do before it does it. | |
| wait_seconds | No | How long to hold this call open waiting for the script, default 45s. If it finishes in time you get the result here; if not you get a job_id to poll with get_script_job, and the script keeps running either way. | |
| idempotency_key | No | Pass a unique string so a retry cannot run the same build twice. If a script with this key already ran in this workspace, its job is returned and nothing executes again — including when that run FAILED, because a script is not a transaction and the writes it made before failing are still there. To act after a failure, read the project, repair what landed, and use a NEW key. Worth setting for anything that builds. | |
| timeout_seconds | No | Wall-clock budget for the SCRIPT — separate from wait_seconds, which is only how long this call stays open. By default a script gets 45s while you are waiting on it, and is raised to 5 minutes the moment it outlives the wait and becomes a job you poll with get_script_job. Set this only to override BOTH with one fixed budget. Watch the slow tools: analyze_audio in 'transcript' or 'beats' mode, export_project and auto_sync take tens of seconds each and will eat a budget fast. analyze_audio in 'features' mode is ~1s and is fine to loop over. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint annotation, the description discloses critical behaviors: scripts are not transactions and partial writes persist; failed tool calls throw; execution is synchronous with no async/await; images are omitted inside scripts and replaced with `_images_omitted`; there are explicit budget/timeout limits; and idempotency applies even to failed runs. None of this contradicts 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-organized with clear section headings and illustrative examples. The length is largely justified by the tool's complexity, and the key guidance is front-loaded. A slight deduction because some constraints (no async/await, no imports) appear in both the description and the schema, and the overall word count verges on over-explaining.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that there is no output schema, the description fully compensates by explaining the return shape (`{ ok, calls, writes_applied, result, stdout }`), the job-handoff mechanism, error behavior, limits, and what the script can observe (layout metrics, layout_qa). The agent has everything needed to call this tool correctly across the common and edge cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Even though schema coverage is 100%, the description adds substantial operational meaning: `code` gets global-call restrictions, `dry_run` is clarified as executing reads for real while recording writes, `wait_seconds` vs `timeout_seconds` are sharply distinguished (wait time vs wall-clock script budget), and `idempotency_key` is explained with its failure-mode semantics. This goes well beyond the schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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: "Write a JavaScript program that calls this server's other tools." It clearly differentiates this tool from its siblings by framing it as an orchestration layer that composes the other tools programmatically, rather than being another domain-specific operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use guidance: "Use it whenever code says the thing more directly than a sequence of separate calls would." It also names exclusions and alternatives, such as narrowing reads with get_clip's `select` and get_element_schema's `fields`, and telling the agent to "Call get_clip yourself, outside a script, when YOU need to look at one."
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_voiceSet voiceAInspect
Set the voiceover voice for every clip in a project.
Use this to apply a clueprint's voice (read voiceover.voice.name and voiceover.voice.engine from the clueprint source data), or to switch all clips to a specific voice in one call. The voice is looked up by name + engine; lookup is case-insensitive on the name.
Common engines: 'eleven' (ElevenLabs), 'cartesia', 'google'.
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | Yes | The project (guide) ID | |
| voice_name | Yes | Voice name as stored in the voices table (e.g. 'Alex', 'Sofia') | |
| voice_engine | Yes | Voice engine — 'eleven', 'cartesia', 'google', etc. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish mutation and non-destructiveness, and the description adds useful behavioral details: lookup is by name+engine, name matching is case-insensitive, and common engine values are listed. It does not cover failure/error behavior, but that is not essential for invoking this tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short, substantive paragraphs with the core purpose front-loaded. Every sentence adds either scope, a use case, or lookup semantics; there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple three-parameter mutation with no output schema, the description supplies everything an agent needs to call it correctly: the scope, the source of values, matching behavior, and accepted engines. No critical information is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter is already described with examples. The description goes beyond schema by explaining how the parameters combine for lookup, the case-insensitivity of the name, and where to read source values from a clueprint.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence names a specific action ('Set'), the resource ('voiceover voice'), and the scope ('every clip in a project'). The later 'switch all clips' phrasing further disambiguates it from per-clip update tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states two intended use cases: applying a clueprint's voice and switching all clips in one call. It does not name alternatives or say when not to use it, but the 'every clip/all clips' scope makes the context clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
split_clipSplit clipAInspect
Split a video clip into two clips at the given timestamp. The left clip keeps the original clip ID; the right clip gets a new ID and is inserted immediately after. Elements spanning the split point are duplicated into both clips with adjusted timing. Voiceover transcript and transcribed words are split proportionally.
Concurrency: whole-project mutation (conflict domain: the entire project) — serialize. Do not run it in parallel with ANY other mutation on the same project_id, including element/voiceover edits; run them one at a time. (Mutations to different projects run in parallel freely.)
| Name | Required | Description | Default |
|---|---|---|---|
| clip_index | Yes | Index of the clip to split | |
| project_id | Yes | The project ID | |
| split_time | Yes | Time in seconds within the clip where to split (clip-relative, not timeline-relative). Must be > 0.1s and < clip_duration − 0.1s; values outside this range are rejected. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description explains important side effects beyond the annotations: the left clip retains the original ID while the right gets a new ID, elements spanning the split are duplicated with adjusted timing, and voiceover transcript/words are split proportionally. It also discloses the broader project-level conflict domain, which the annotations do 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: the first paragraph covers the core operation and its effects, and the second covers concurrency. Every sentence adds necessary information without redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema, the description provides sufficient context: behavior, ID handling, element duplication, voiceover division, and concurrency requirements. An agent has what it needs to invoke the tool correctly and understand the consequences.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already describes all three parameters fully (100% schema coverage), including split_time semantics and constraints. The description does not add much parameter-level meaning beyond the schema, so a baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource: 'Split a video clip into two clips at the given timestamp.' It clearly differentiates this from sibling tools like duplicate_clip or remove_clip by describing a precise split behavior and its consequences.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit concurrency guidance: it is a whole-project mutation and must not run in parallel with any other mutation on the same project_id. It does not explicitly contrast this tool with alternatives like duplicate_clip, but the usage restrictions are clear and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
switch_workspaceSwitch active workspaceAInspect
Switch the active workspace. The choice sticks for this client until you change it again — including across reconnects — so every later call operates in the new workspace. Use find(type='workspaces') to see available options.
| Name | Required | Description | Default |
|---|---|---|---|
| workspaceId | Yes | Workspace ID to switch to |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses the key behavioral trait: the workspace choice persists for the client 'across reconnects' until changed. This is essential context for an agent deciding whether and when to call this stateful tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences: the action, the persistence behavior, and the lookup mechanism. All information is front-loaded and every sentence contributes meaning with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter state-switching tool with no output schema, this description fully covers what an agent needs to know: the action, the persistence semantics, and how to find valid values. There are no significant gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents workspaceId as 'Workspace ID to switch to' with 100% coverage. The description adds practical value by telling the agent to use find(type='workspaces') to see available options, which clarifies where a valid workspaceId comes from.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Switch') and a clear resource ('active workspace'), and immediately clarifies the state-changing nature of the operation. It is easily distinguished from all sibling tools, none of which perform workspace switching.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains that this should be used when you want 'every later call' to operate in the new workspace, which is clear contextual guidance. It also points to find(type='workspaces') for discovering options, though it does not list explicit exclusions because no direct alternative exists.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_articleUpdate articleBInspect
Update article text content from markdown. Use <SCREENSHOT {id}> placeholders to position screenshots. Screenshots in the markdown are kept. Screenshots removed from markdown are deleted. Order in markdown defines final order. Get the current article first with get_article, modify the markdown, then call this.
| Name | Required | Description | Default |
|---|---|---|---|
| markdown | Yes | Updated article content as markdown with <SCREENSHOT {id}> placeholders | |
| project_id | Yes | Project ID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses important behavioral details like screenshots in markdown being kept, removed screenshots being deleted, and markdown order defining final order. However, this directly contradicts the annotation destructiveHint: false, since deleting screenshots is a destructive side effect. Per scoring rules, contradiction forces a 1.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact, with each sentence serving a purpose: what the tool does, how placeholders work, side-effect behavior, and usage workflow. It is well-structured and front-loaded, though slightly repetitive with the word 'markdown'.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
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 description covers the essential workflow, side effects, and ordering semantics. It doesn't mention return value or error handling, but those are less critical given the simplicity and the strong workflow guidance.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 adds meaningful semantics beyond the schema by explaining how markdown placeholders control screenshot positioning, preservation, deletion, and ordering. This enriches the markdown parameter's meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool updates article text content from markdown, giving a specific verb and resource. It doesn't explicitly differentiate from sibling tools like update_article_media or add_article_media, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit workflow guidance: get the article first with get_article, modify the markdown, then call this tool. This is clear contextual usage, but it doesn't mention when not to use it or name alternatives, so it misses the top score.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_article_mediaUpdate or inspect article mediaAInspect
Update an article image/GIF (screenshot), or inspect its current state.
Provide one or more of
zoom_factor,crop,shapesto change metadata.Pass
render=true(with no other updates) to fetch the current details without mutating.
To DELETE an article image/GIF: call update_article with markdown that omits the <SCREENSHOT id> reference. Unreferenced media is pruned server-side on save. There is no separate delete tool — the markdown IS the source of truth for what's present.
| Name | Required | Description | Default |
|---|---|---|---|
| crop | No | Crop data: { position: [x,y], size: [w,h] } in fractional coords. | |
| render | No | If true (and no other updates supplied), returns current details and a PNG preview without mutating. | |
| shapes | No | Array of shape objects for annotations. | |
| project_id | Yes | Project ID. | |
| zoom_factor | No | Zoom magnification (1.0 = no zoom). | |
| screenshot_id | Yes | Screenshot ID (from get_article). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations indicate readOnlyHint=false, destructiveHint=false, which suggests the tool can mutate but is not destructive. The description adds crucial behavior: it can both mutate and inspect, and explicitly states that render=true performs a non-mutating fetch. It also reveals that deletion is not directly supported here, which is important behavioral context. No contradictions; just a minor gap on whether updates are reversible or any side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with bullet points and a clear separation of update vs. inspect usage. It front-loads the primary purpose and then provides the deletion alternative. No redundancy; every sentence adds value. Slightly longer than minimal but justified given the dual functionality.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (6 params, nested objects) and the absence of an output schema, the description fully compensates. It explains the update mode, the inspect mode, and the deletion path. It covers the key use cases and clarifies the source-of-truth for deletion, which is critical for correct usage. No missing critical information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so each parameter is described. The description adds usage semantics (e.g., render=true with no other updates for inspection) but does not elaborate on shape structure or crop coordinate details beyond schema. Since schema is comprehensive, the baseline is 3; the description adds a little value by explaining how to combine parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the dual purpose: update article media metadata (zoom, crop, shapes) or inspect current state via render=true. It distinguishes from the sibling update_article by noting that deletion is handled through markdown omission, not a dedicated delete tool. This distinguishes it from other media tools like add_article_media and generate_media.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance: use render=true with no other updates for inspection, provide one or more of zoom_factor, crop, shapes for updates. It also explicitly details how to delete media (via update_article with markdown), preventing misuse and clarifying the tool's limits. This is exceptional guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_audioUpdate an existing audio trackAInspect
Mutate fields on an existing music/SFX track by id. Read existing tracks via get_project.audio_tracks — the per-entry shape there matches this tool's args, so you can flip a knob (volume, fades, timing, loop) and write it back without losing the track's id.
Only fields you pass are changed; omitted fields are preserved. To delete a track entirely, use remove_from_project(target='audio') instead.
| Name | Required | Description | Default |
|---|---|---|---|
| loop | No | Whether the track loops | |
| volume | No | New playback volume 0-100 | |
| fade_in | No | Fade-in duration (seconds) | |
| fade_out | No | Fade-out duration (seconds) | |
| music_id | Yes | ID of the audio track (from get_project.audio_tracks[].id) | |
| project_id | Yes | The project ID | |
| guide_end_time | No | New end time on the project timeline (seconds) | |
| music_end_time | No | New end offset within the source file (seconds) | |
| guide_start_time | No | New start time on the project timeline (seconds) | |
| music_start_time | No | New start offset within the source file (seconds) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as a mutation (readOnlyHint: false, destructiveHint: false), and the description adds genuine value beyond that: the partial-update semantics ('Only fields you pass are changed; omitted fields are preserved') and the id-preservation pattern. No contradiction with annotations — the 'Mutate' wording aligns with the non-readonly hint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight paragraphs with zero filler. The purpose is front-loaded in the first sentence, and the second paragraph delivers only the two critical facts: partial-update behavior and the deletion alternative. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with 10 params, no output schema, and 2 required fields, the description covers the essential operational context: how to obtain track data, what gets preserved, and what not to use it for. It is complete enough for an agent to call it correctly; return-value details are reasonably omitted given no output schema exists.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so every one of the 10 parameters already carries a description in the schema. The description adds the useful note that the arg shape matches get_project.audio_tracks entries, which helps an agent populate fields, but it doesn't add per-parameter detail — the baseline of 3 for high schema coverage is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Mutate fields on an existing music/SFX track by id' — a specific verb, resource, and identification method. It clearly distinguishes from add_audio (creation) and remove_from_project (deletion) by name, so an agent can differentiate 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description tells the agent to read existing tracks via get_project.audio_tracks and notes the per-entry shape matches the tool's args, establishing the read-then-write workflow. It also gives an explicit exclusion for deletion via remove_from_project(target='audio'). It doesn't contrast with update_clips, but the audio/clip domain split is clear enough from names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_clipsUpdate clips (batch)ADestructiveInspect
Update one or more clips in a single call — background, transition, duration, title, visibility, position, and (video clips) the footage transform via video_styling. Always batch.
Each entry: { clip_index, duration?, title?, background_color? | background?, transition?, hidden?, position?, voiceover_volume?, video_styling? }
voiceover_volume: 0-100. This is how you make a clip SILENT — set 0 to mute the narration while keeping the text and its word timings. get_clip and get_project report the current value, so read it before muting to restore it later. There is no "delete voiceover" tool; muting is the supported way.
background_color: hex (keeps the existing pattern/image, changes color). background: full object from find(type='backgrounds') — replaces the whole background.
transition: { type, duration, direction?, color? }, or null to remove. Set on the OUTGOING clip — the transition plays at the END of clip_index, into the next clip. Types: circleWipe, rainbowWipe, cornerWipe, stack, colorWipe, dissolve, pushPull, fadeToColor. Directions: rainbowWipe/cornerWipe take topLeft|topRight|bottomLeft|bottomRight; colorWipe left|right; stack/pushPull left|right|top|bottom.
position: move the clip to a new zero-based index. Moves apply FIRST (in array order), then property patches — keep reorders in a separate call from property edits so indices stay predictable.
video_styling (VIDEO CLIPS ONLY — ignored on slide clips): reposition/resize the clip's recording on the canvas, e.g. into a designed window slot. { position?: [cx, cy], size?: [w, h] } as canvas fractions 0–1 ([1,1] = full-bleed, position is the footage CENTER), plus crop? and border?. Fields merge onto the clip's existing video_styling.
Concurrency: parallel-safe per clip — all property updates land in ONE save. Safe to fan out across DIFFERENT clips. Do NOT run concurrently with element/voiceover edits on the SAME clip, or whole-project mutations (add_clips, add_audio, update_project). When adding audio + resizing clips, run update_clips BEFORE add_audio.
| Name | Required | Description | Default |
|---|---|---|---|
| updates | Yes | One entry per clip to update. | |
| project_id | Yes | Project ID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes beyond the destructiveHint annotation by explaining that operations are batched into one save, that nothing is deleted implicitly (muting is reversible), and that position moves apply first before property patches—a critical ordering behavior not obvious from the schema. It also warns about concurrency limitations, which is valuable behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long, but every section earns its place by addressing non-obvious semantics, constraints, and usage patterns. It is front-loaded with the core purpose and 'Always batch' instruction, then organized by parameter with clear examples. No redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex tool with nested objects and nuanced behaviors, the description covers all necessary information: parameter meanings, allowed values, edge cases (video-only, voiceover mute), ordering, concurrency, and prerequisites. Since there's no output schema, the description explains the effect sufficiently. It addresses every parameter's non-trivial aspects.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema covers all parameters with 100% coverage, but the description adds significant semantic value: it clarifies that background_color keeps the pattern while background replaces it, that transition is set on the outgoing clip and plays at the end, and that video_styling fields merge onto existing values. These clarifications reduce ambiguity beyond the schema's descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear verb ('Update'), a specific resource ('clips'), and enumerates the exact properties that can be updated, distinguishing it from sibling tools like add_clips, remove_clip, or update_project. It even notes video_clips-only behavior for video_styling, which separates it from other update tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance: 'Always batch', describes how to mute voiceover (set volume to 0) as the supported way since no delete tool exists, and gives concurrency constraints including what NOT to run concurrently (element/voiceover edits on the same clip, whole-project mutations). It also advises running update_clips before add_audio when both needed, offering clear alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_clueprintUpdate clueprintADestructiveInspect
Update a clueprint's metadata and/or file contents in one call.
Metadata fields (name, description, tags, visibility, thumbnail_path) are applied as a patch — only the fields you pass change. Pass at least one to update metadata.
files is a list of file mutations:
Write text:
{ path, content }Write binary:
{ path, content, encoding: "base64" }Write from URL:
{ path, source_url }(presigned URL, e.g. from get_clip with save=true)Delete:
{ path, content: null }
You can mix writes and deletes in a single call. Existing files at the same path are overwritten.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | New name. | |
| tags | No | New tags (replaces existing). | |
| files | No | File mutations — writes and deletes. Empty/omitted for metadata-only updates. | |
| visibility | No | New visibility. | |
| description | No | New description. | |
| clueprint_id | Yes | ID of the clueprint to update. | |
| thumbnail_path | No | Relative path of a screenshot in the clueprint to use as thumbnail (e.g. 'screenshots/title-slide.png'). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes well beyond the annotations by explaining patch semantics ('only the fields you pass change'), overwrite behavior ('Existing files at the same path are overwritten'), and deletion via content: null. These behavioral details are not expressed in the annotations or schema alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is organized into scannable paragraphs and bullet lists, with every sentence carrying operational value. The file mutation formats and overwrite/delete caveats are presented efficiently and front-loaded enough to prevent misuse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description sufficiently covers metadata patch semantics, all file mutation patterns, URL handling, and overwrite/delete behavior for correct invocation. It does not mention the response/return value or what happens if neither metadata nor files are provided, but these are minor gaps given the detailed schema and no output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description adds operation-level meaning by defining four file mutation shapes: text, binary, URL, and delete. It also clarifies when to use source_url vs inline content and how metadata fields behave as a patch, which the bare schema descriptions do not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Update a clueprint's metadata and/or file contents in one call,' which clearly states the verb, resource, and scope. This distinguishes it from create_clueprint and get_clueprint by naming both metadata and file-content mutation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives concrete usage context, such as using a presigned URL from get_clip with save=true and preferring source_url for large/binary files. It doesn't explicitly state when not to use the tool or name alternative update tools, so it stops short of full when/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_elementsUpdate elementsADestructiveInspect
Update many elements across one or more clips in a single tool call. Replaces the per-element tool — always batch.
SEND LESS, GET BACK LESS. defaults carries what every item shares (clip_index, element_type, and type_data entries like font_setting or alignment) so you send it once instead of per item; each item overrides any key it sets. returning declares what comes back, the way select shapes a get_clip read — omit it for a sensible default, or pass [] for just the counts.
defaults: { clip_index: 1, element_type: 'text', type_data: { font_setting: {...} } } returning: [] → { total, succeeded, failed } only returning: ['layout'] → + the measured text fit per element returning: ['qa.codes'] → + the clip audit with prose stripped from non-errors (any returning value → error findings regardless; only warnings are opt-in)
Each item can update position/timing fields alone, or type-specific fields via type_data (use get_element_schema in 'update' mode to see what's settable for an element_type). Items within one call are applied in order; partial success is fine.
You do NOT need clip_index here — an element_id is unique within the project, so the server locates the clip itself. Pass it only as a hint; a wrong one is corrected rather than rejected.
Grouping: pass group: "<name>" to move an element into a named group (created on demand), or group: "" to pull it back out to the clip root. Several items sharing a name collect into one group — the way to tidy loose elements into units the user can move or hide together. Grouping never changes coordinates. It does affect z-order: a group's members render contiguously at the group's slot, and a NEW group takes the slot of its first member, so grouping already-adjacent elements keeps their z-position while grouping scattered ones pulls them together at the lowest member's slot.
Customising a component: after add_elements(component_id=...), set its content here with type_data.parameter_values on the animation element it returned.
Concurrency: parallel-safe (conflict domain: the individual element), same as add_elements — fan out across subagents as long as they touch DIFFERENT element ids — those carry different entity paths and both land. Two concurrent edits to the SAME element id do NOT merge and do NOT last-write-win: the later one is REJECTED ('changed since this edit was based on'), nothing is written, and you must re-read and re-apply. Do NOT run concurrently with whole-clip/whole-project mutations on the same guide (update_clips on that clip, structural clip ops, add_audio, update_project).
Keyframes: pass a top-level keyframes array (sibling of x/y/type_data, NOT inside type_data) to set, or null to clear. Per-entry shape: { timestamp, positionX?, positionY?, width?, height?, interpolation? } in canvas pixels; positionX/Y use the element's alignment-aware origin.
Text elements: pass fit_to_lines: N to run an automatic widen + font-shrink pass after the entry's regular update lands. The server reshapes the element so the rendered text wraps to at most N lines without overlapping its neighbours.
| Name | Required | Description | Default |
|---|---|---|---|
| updates | Yes | Element updates — at least one entry. | |
| defaults | No | Values shared by every item, sent once rather than repeated. Items win per key; type_data merges one level. E.g. defaults:{clip_index:1, element_type:'text', type_data:{font_setting:{font:'Inter',weight:'600'}, alignment:'center'}} then items carry only what differs. | |
| returning | No | Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). A text element measured on a fallback face is listed in top-level `font_warnings` whichever you choose. ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write. | |
| project_id | Yes | Project ID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint: false, destructiveHint: true), the description discloses critical behavior: partial success is fine, later concurrent edits to the same element are rejected (no last-write-win), wrong clip_index is corrected rather than rejected, error findings always return while warnings are opt-in, and grouping never moves coordinates. It also explains z-order effects and keyframe replacement semantics. This goes far beyond what annotations alone provide and contains no contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is exceptionally long but well-structured with clear sections (defaults/returning, grouping, keyframes, text, concurrency) and front-loaded with the core purpose. While every sentence adds value for such a complex tool, the sheer length risks overwhelming an agent. It earns a high score for organization but loses a point for verbosity that could have been trimmed without losing essential information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool of this complexity with no output schema, the description is remarkably complete. It covers return shaping, failure semantics, grouping edge cases, keyframe replacement, text fitting, concurrency conflict rules, and even the meaning of 'fits' vs 'fits_height'. It also explains the fallback font warning. An agent has everything needed to call it correctly across varied scenarios.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already has detailed parameter descriptions, but the tool description adds substantial meaning: it explains the defaults/items override model, the exact meaning of each `returning` value, the group name semantics, the top-level vs type_data keyframe distinction, and fit_to_lines behavior. It provides concrete examples (e.g., defaults snippet) and clarifies nuanced behaviors like placement vs width checks. This far exceeds the schema's coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it updates many elements across clips in one call and explicitly replaces the per-element tool, always batching. It names the sibling tool it supersedes, distinguishing itself from add_elements, remove_elements, and update_clips. The verb-resource pairing is specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides rich usage guidance: when to batch, how to use defaults to avoid repetition, how to shape returns with `returning`, when to use `group` for organizing, and clear concurrency rules. It explicitly warns against concurrent whole-clip/project mutations and tells agents to re-read after a rejected edit. It also directs users to get_element_schema for type-specific fields, so alternatives are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_groupsUpdate groupsAInspect
Transform, keyframe, rename, nest or lock GROUPS. A group moves, scales, rotates and fades as ONE unit, without touching any child's stored position — which is how you get a camera push instead of building the target layout twice and crossfading it.
Address by group_id, never by name. Ids come from get_clip, or from the group_id that add_elements/update_elements hands back when you pass group. An unknown id is an error, never a silent create.
There is no add_groups: a group is CREATED by putting elements in one — add_elements(group: "hero-card") — which also returns its id. That is not a shortcut; a group's pivot comes from its children's bounding box, so an empty group has no geometry to transform.
The shortest path, in one script:
const clip = get_clip({ project_id, clip_index: 2, select: ["groups"] }); const byName = new Map(clip.groups.map(g => [g.name, g.id])); update_groups({ project_id, items: [{ clip_index: 2, group_id: byName.get("hero-card"), anchor_px: [960, 540], keyframes: [ { timestamp: 0, scaleX: 1, scaleY: 1 }, { timestamp: 1.2, scaleX: 2.4, scaleY: 2.4, offsetX: -400, offsetY: -120, interpolation: "easeOut" }, ], }]});
Units are canvas pixels, as everywhere else: offset_px, blur_px and anchor_px are pixels; scale is a multiplier; rotation/rotate are degrees; opacity is 0-100.
anchor_px is the pivot everything rotates and scales about. Give it as a point on the canvas — the server converts it to a fraction of the group's child bounding box and reports back both that fraction and the box, so you can check it. Default is the box's centre. Set it when you want a push that favours one corner.
Only fields you pass are changed. keyframes: [] CLEARS every track; omitting keyframes leaves them alone; a non-empty list replaces only the properties it names. parent_group_id: "" moves a group to the clip root; omitting it leaves the parent alone.
Keyframable: offsetX, offsetY, scaleX, scaleY, rotation, rotateX, rotateY, opacity, blur. Position, size and colour belong to elements, not groups.
Concurrency: clip-scoped (a group edit can add or re-parent nodes in its clip). Serialize against other mutations on the SAME clip; different clips and different projects run in parallel freely.
| Name | Required | Description | Default |
|---|---|---|---|
| items | Yes | One entry per group to update | |
| returning | No | Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). A text element measured on a fallback face is listed in top-level `font_warnings` whichever you choose. ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write. | |
| project_id | Yes | The project ID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only supply readOnly/destructive/openWorld hints, so the description carries most of the burden. It discloses that unknown ids are errors, that only passed fields are changed, that keyframes: [] clears every track, that parent_group_id: "" moves to the clip root, and that anchor_px is converted and reported back. These side effects go well beyond the annotations and do not contradict them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and each block has a clear purpose, but it is long and includes a full code example plus some explanatory prose that could be tightened. It remains well-structured and readable, with the most critical warnings appearing early.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema and sparse annotations, the description covers identification, creation path, units, partial-update semantics, keyframe clearing/replacement behavior, anchor behavior, and concurrency. The comprehensive input schema handles per-field detail, so nothing essential to invoking this tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 meaningful semantics: centralized units (pixels, multipliers, degrees, 0-100 opacity), the distinction between group-level transform and element-level position/size/colour, keyframable property list, and the fact that anchor_px is converted to a fraction of the child bounding box. This significantly reduces the risk of incorrect values or false expectations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with 'Transform, keyframe, rename, nest or lock GROUPS,' naming both the resource and the specific actions. It also distinguishes itself from sibling tools by stating that position, size and colour belong to elements rather than groups, and pre-empts any confusion with add_groups by explaining that group creation happens via add_elements.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing guidance: no add_groups exists, create groups via add_elements(group: ...), get ids from get_clip or add_elements/update_elements, and address by group_id, never by name. It also provides concurrency rules, telling the agent when to serialize against other mutations versus when parallel calls are safe.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_projectUpdate projectAInspect
Update a project's metadata: rename, change description, move to a different folder, or change aspect ratio.
Only fields you provide are changed. To move a project to the workspace root, pass folder_id="" (empty string).
Aspect ratio: pass any "W:H" (positive integers). The canvas is fit inside 1920×1080 keeping the ratio, so element pixel coordinates use the resulting canvas. Common values:
"16:9" → 1920×1080 (landscape, YouTube/web — default)
"9:16" → 608×1080 (portrait — TikTok/Reels/Shorts)
"1:1" → 1080×1080 (square — Instagram feed)
"3:4" → 810×1080 (portrait card)
"4:5" → 864×1080 (portrait — Instagram feed)
Element coordinates are stored as fractions of the canvas, so existing elements reflow to the new canvas automatically — no element coordinates are rewritten.
Concurrency: whole-project mutation (conflict domain: the entire project) — serialize. Do not run it in parallel with ANY other mutation on the same project_id, including element/voiceover edits; run them one at a time. (Mutations to different projects run in parallel freely.)
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | New project title | |
| folder_id | No | New folder ID. Pass '' (empty string) to move to workspace root. | |
| project_id | Yes | The project ID to update | |
| description | No | New description | |
| aspect_ratio | No | New aspect ratio as 'W:H' (positive integers). Common: '16:9' landscape, '9:16'/'4:5'/'3:4' portrait, '1:1' square. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses important behavior: partial updates, aspect-ratio canvas fitting, automatic element reflow via fractional coordinates, and concurrency constraints. These are non-obvious traits that materially affect how an agent should invoke and schedule the tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose, then moves through field behavior, aspect-ratio examples, and concurrency. Every sentence earns its place, and the bullet list for common aspect ratios keeps the content scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a metadata-update tool, the description covers the parameter semantics, coordinate consequences, and concurrency model. Nothing required to call the tool correctly is missing, and the annotations confirm it is a write operation without contradiction.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although the schema already documents all 5 parameters, the description adds real semantic value: folder_id="" as the root signal, aspect ratio examples mapped to concrete canvas sizes, and the 'only fields you provide are changed' partial-update contract. This goes well beyond the baseline schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
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: 'Update a project's metadata: rename, change description, move to a different folder, or change aspect ratio.' This clearly scopes the tool against siblings like create_project, duplicate_project, and update_elements.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context on when to use the tool and how to behave: only provided fields change, folder_id="" moves to root, and actions must be serialized because it's a whole-project mutation. It explicitly warns against running it in parallel with other mutations on the same project_id, which is strong when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upload_fileUpload fileAInspect
Upload one or more files to Clueso. Pick a mode by client + where the file lives:
files — ChatGPT only: files the user attached in the conversation. ChatGPT fills each entry (download_url + file_id) itself; pass the attachments here rather than asking the user to re-upload. Returns one mcp_upload_id per file.
file_name — HOSTED upload, the default for any non-UI / programmatic upload (Claude Code, Cursor, Claude Desktop, scripts). Returns an upload URL on Clueso's OWN base domain + a ready-to-run curl that streams a single local file to it; Clueso relays the bytes to storage server-side. The PUT targets the base domain — NOT cloud storage directly — so it works on desktop/agent clients that can't reach or are blocked from S3. Requirement: the client must be able to PUT bytes to the Clueso base domain (run the returned curl, or any HTTP PUT). The agent (or the user at a shell prompt) runs the curl. Prefer this whenever there's no human at a browser.
file_url: Pass a public https URL. Server fetches and stages the file. Returns mcp_upload_id immediately. Use when the file is already on the open web — no user interaction needed.
request_hosted_upload (UI mode — use ONLY when a human should pick files in a browser: many files at once, or a host with no shell / no PUT capability): Returns a single upload_token + upload_page URL. Share the link with the user; they open it in a new browser tab, drop their files, click Done. Then call check_uploads(upload_token) to retrieve all mcp_upload_ids. Call once for all files.
Hosted uploads cover any number of files per call: one call issues one upload_token, and that token covers every file the user drops on the page. Repeat calls issue additional tokens, each tracking only its own files.
The returned mcp_upload_id (prefixed mup_) can be passed to:
add_elements / update_elements (image or video → an element ON a clip: pass it as
type_data.mcp_upload_id, on either tool — this is how a local image becomes on-canvas content, and how an existing element's source is swapped). To fill an animation's image slot, pass it insidetype_data.parameter_valueson update_elements only — parameter_values is an update-path field and is stripped on add.add_audio (audio → project music track that plays under all clips)
add_clips(kind='video') (video or audio → sequential clip with auto-transcription)
add_clips(kind='pptx') (.ppt/.pptx → slide clips)
add_article_media (image/GIF → article asset)
analyze_audio (audio → transcript / silences / beats / features)
| Name | Required | Description | Default |
|---|---|---|---|
| files | No | ChatGPT file attachments, one entry per file (filled by ChatGPT). | |
| file_url | No | Public URL to fetch the file from | |
| file_name | No | File name with extension. Returns a Clueso upload URL + curl command that streams this single local file to us (single file). | |
| file_names | No | List of file names the user will upload (for hosted mode). Shown on the upload page as guidance. | |
| request_hosted_upload | No | If true, returns a hosted upload page. Call once for all files — the page accepts multiple uploads under one token. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false, openWorldHint=true, destructiveHint=false. The description carries the full behavioral burden: it discloses that uploads go to Clueso's own domain, relays bytes server-side, requires PUT capability, returns upload URLs, tokens, and mcp_upload_ids, and explains the curl execution step. It also warns about parameter_values being stripped on add for animation slots. All of this goes beyond the sparse annotations and contradicts nothing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but justifiably so given the tool's complexity with four modes and downstream usage. It is well-structured with numbered modes, bullet points, and clear separation of concerns. Front-loaded with the core purpose and mode selection. A minor deduction because it could be trimmed slightly (e.g., the long paragraph about how mcp_upload_id is used could be condensed), but overall every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the absence of an output schema, the description explicitly covers return values for every mode (mcp_upload_id, upload URL + curl, upload_token + upload_page). It explains the workflow for hosted uploads and how to retrieve IDs via check_uploads. It also maps the ID to consumption tools and notes the parameter_values caveat. Nothing an agent needs to correctly invoke and handle this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although the schema has 100% parameter descriptions, the tool description adds substantial meaning: it explains the semantic difference between file_name (single local file, returns curl) and file_names (list of file names for hosted upload page), clarifies that files is ChatGPT-only and auto-populated, and details how request_hosted_upload triggers a UI flow. This is far more than the one-line schema descriptions, giving agents the context needed to pick the right parameter for the situation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear verb+resource: 'Upload one or more files to Clueso.' It then breaks down four distinct modes (files, file_name, file_url, request_hosted_upload) with specific use cases, fully distinguishing the tool from its siblings. The description also explains how the returned mcp_upload_id flows into other tools (add_elements, add_audio, add_clips, etc.), which further clarifies its role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance for each mode: files for ChatGPT-only attachments, file_name as the default for non-UI/programmatic uploads, file_url for public web files, and request_hosted_upload for browser-based human selection. It even names the alternative tool check_uploads for polling uploads and states conditions like 'Prefer this whenever there's no human at a browser' and 'use ONLY when a human should pick files in a browser.' This is exemplary routing information.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
voiceover_batchSet voiceover scriptsADestructiveInspect
Set voiceover text and/or trigger speech generation for any number of clips in a single call.
Each entry chooses its own action:
"set_text" — set transcript for a clip (clip_index + text)
"generate_speech" — async TTS for a clip (returns immediately)
"set_and_generate" — set text and kick off TTS in one entry (+ text)
Address a clip the same way as everywhere else: clip_index. Pass clip_id instead if you already have it — it survives clips being inserted or reordered mid-build — but you never need both; whichever you omit is looked up once for the whole call.
Entries within one call are applied in order. Returns one result object per input entry. All text-set actions land in ONE save; the TTS for generate/set_and_generate runs async per clip after.
IMPORTANT — generating speech RESCALES the whole clip, it does not clamp it: when audio is generated (generate_speech / set_and_generate), the clip's duration is reset to the spoken audio length, and then EVERY element on that clip is retimed proportionally by (new duration ÷ old duration). start_time, end_time and every keyframe timestamp are multiplied by that factor. Nothing is merely truncated — on a 6s clip that becomes 1.02s, an animation you placed at [0, 1.6] ends up at [0, 0.27]. Zoom elements whose window falls under the minimum after scaling are DROPPED entirely. Generation is async, so this lands AFTER this call has already returned success. So: generate speech BEFORE placing time-sensitive elements, or size them against estimate_duration first — then re-read the clip and check what your elements actually became, not just the clip duration.
Concurrency: parallel-safe (conflict domain: a clip's voiceover). The server merges each clip's voiceover under a per-guide lock and preserves that clip's elements, so you can fan voiceover work out across subagents by clip — and it's safe to run alongside element edits. Two concurrent edits to the SAME clip's voiceover do not last-write-win — both claim that clip's voiceover path, so the later one is REJECTED and nothing is written; re-read and re-apply. Do NOT run concurrently with whole-clip/whole-project mutations on the same guide (update_clips on that clip, structural clip ops, add_audio, update_project).
| Name | Required | Description | Default |
|---|---|---|---|
| entries | Yes | Voiceover entries — at least one. | |
| project_id | Yes | Project ID |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations mark this as destructive, and the description substantially honors and extends that warning. It details the rescaling of the entire clip, proportional retiming of all elements, potential dropping of zoom elements, async landing after return, and the non-last-write-wins concurrent conflict behavior. This is far more disclosure than the annotation alone provides.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long, but each section earns its place: summary, action list, addressing, order/results, rescale warning with concrete example, and concurrency rules. The most critical warning is front-loaded with IMPORTANT, and the structure makes a complex destructive tool safer to invoke.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with destructive side effects, async behavior, and subtle concurrency semantics, the description is complete. It covers param usage, return shape, timing, failure modes, and safe concurrent usage. Nothing an agent needs 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.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description adds meaning beyond the schema by explaining the three action modes, the clip_index/clip_id resolution rule (the omitted one is looked up once), per-call ordering, single-save semantics for text, and async TTS behavior. These are essential runtime semantics the schema does not convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource: "Set voiceover text and/or trigger speech generation for any number of clips in a single call." It clearly enumerates the three action types and distinguishes this batch tool from related sibling operations by emphasizing multi-clip, per-entry behavior.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit guidance on when to generate speech before placing time-sensitive elements, how to address clips via clip_index vs clip_id, and when not to run concurrently with specific mutations like update_clips and add_audio. This goes well beyond a generic usage hint and actively routes the agent to safer workflows.
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.
8 tool updates
- Changed
add_elements3 fields changed- changed
Input schema / properties / defaults / properties / keyframes / anyOfPrevious value: -[ - { - "items": { - "additionalProperties": false, - "properties": { - "backgroundBlur": { - "description": "Backdrop blur behind the element", - "type": "number" - }, - "bezier": { - "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "bezier_overrides": { - "additionalProperties": { - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "string" - }, - "required": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "object" - }, - "blur": { - "description": "Layer blur", - "type": "number" - }, - "borderRadiusBottomLeft": { - "description": "borderRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "borderRadiusBottomRight": { - "description": "borderRadiusBottomRight in canvas pixels", - "type": "number" - }, - "borderRadiusTopLeft": { - "description": "borderRadiusTopLeft in canvas pixels", - "type": "number" - }, - "borderRadiusTopRight": { - "description": "borderRadiusTopRight in canvas pixels", - "type": "number" - }, - "cropHeight": { - "description": "cropHeight (native unit)", - "type": "number" - }, - "cropWidth": { - "description": "cropWidth (native unit)", - "type": "number" - }, - "cropX": { - "description": "cropX (native unit)", - "type": "number" - }, - "cropY": { - "description": "cropY (native unit)", - "type": "number" - }, - "fillColor": { - "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "fontSize": { - "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", - "type": "number" - }, - "height": { - "description": "Height in canvas pixels (0 allowed)", - "minimum": 0, - "type": "number" - }, - "imageBorderColor": { - "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "imageBorderWidth": { - "description": "imageBorderWidth in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomLeft": { - "description": "imageCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomRight": { - "description": "imageCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopLeft": { - "description": "imageCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopRight": { - "description": "imageCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "interpolation": { - "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "interpolation_overrides": { - "additionalProperties": { - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "string" - }, - "required": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "object" - }, - "letterSpacing": { - "description": "Letter spacing in canvas pixels.", - "type": "number" - }, - "lineHeight": { - "description": "lineHeight (native unit)", - "type": "number" - }, - "opacity": { - "description": "Opacity 0-100", - "maximum": 100, - "minimum": 0, - "type": "number" - }, - "paddingBottom": { - "description": "paddingBottom in canvas pixels", - "type": "number" - }, - "paddingLeft": { - "description": "paddingLeft in canvas pixels", - "type": "number" - }, - "paddingRight": { - "description": "paddingRight in canvas pixels", - "type": "number" - }, - "paddingTop": { - "description": "paddingTop in canvas pixels", - "type": "number" - }, - "positionX": { - "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", - "type": "number" - }, - "positionY": { - "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", - "type": "number" - }, - "rotateX": { - "description": "rotateX (native unit)", - "type": "number" - }, - "rotateY": { - "description": "rotateY (native unit)", - "type": "number" - }, - "rotation": { - "description": "Rotation in degrees", - "type": "number" - }, - "scaleX": { - "description": "Horizontal scale multiplier (1 = 100%)", - "type": "number" - }, - "scaleY": { - "description": "Vertical scale multiplier (1 = 100%)", - "type": "number" - }, - "shadowBlur": { - "description": "shadowBlur in canvas pixels", - "type": "number" - }, - "shadowColor": { - "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "shadowOffsetX": { - "description": "shadowOffsetX in canvas pixels", - "type": "number" - }, - "shadowOffsetY": { - "description": "shadowOffsetY in canvas pixels", - "type": "number" - }, - "shadowSpread": { - "description": "shadowSpread in canvas pixels", - "type": "number" - }, - "strokeColor": { - "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "strokeDash": { - "description": "strokeDash in canvas pixels", - "type": "number" - }, - "strokeGap": { - "description": "strokeGap in canvas pixels", - "type": "number" - }, - "strokeTrimEnd": { - "description": "strokeTrimEnd (native unit)", - "type": "number" - }, - "strokeTrimOffset": { - "description": "strokeTrimOffset (native unit)", - "type": "number" - }, - "strokeTrimStart": { - "description": "strokeTrimStart (native unit)", - "type": "number" - }, - "strokeWidth": { - "description": "strokeWidth in canvas pixels", - "type": "number" - }, - "textBackgroundColor": { - "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textBgRadiusBottomLeft": { - "description": "textBgRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusBottomRight": { - "description": "textBgRadiusBottomRight in canvas pixels", - "type": "number" - }, - "textBgRadiusTopLeft": { - "description": "textBgRadiusTopLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusTopRight": { - "description": "textBgRadiusTopRight in canvas pixels", - "type": "number" - }, - "textColor": { - "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textStrokeColor": { - "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textStrokeDash": { - "description": "textStrokeDash in canvas pixels", - "type": "number" - }, - "textStrokeGap": { - "description": "textStrokeGap in canvas pixels", - "type": "number" - }, - "textStrokeWidth": { - "description": "textStrokeWidth in canvas pixels", - "type": "number" - }, - "timestamp": { - "description": "Clip-relative time in seconds", - "minimum": 0, - "type": "number" - }, - "videoCornerRadiusBottomLeft": { - "description": "videoCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusBottomRight": { - "description": "videoCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopLeft": { - "description": "videoCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopRight": { - "description": "videoCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "width": { - "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", - "minimum": 0, - "type": "number" - } - }, - "required": [ - "timestamp" - ], - "type": "object" - }, - "type": "array" - }, - { - "type": "null" - } -]New value: +[ + { + "items": { + "additionalProperties": false, + "properties": { + "backgroundBlur": { + "description": "Backdrop blur behind the element", + "type": "number" + }, + "bezier": { + "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "bezier_overrides": { + "additionalProperties": { + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "type": "object" + }, + "blur": { + "description": "Layer blur", + "type": "number" + }, + "borderRadiusBottomLeft": { + "description": "borderRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "borderRadiusBottomRight": { + "description": "borderRadiusBottomRight in canvas pixels", + "type": "number" + }, + "borderRadiusTopLeft": { + "description": "borderRadiusTopLeft in canvas pixels", + "type": "number" + }, + "borderRadiusTopRight": { + "description": "borderRadiusTopRight in canvas pixels", + "type": "number" + }, + "cropHeight": { + "description": "cropHeight (native unit)", + "type": "number" + }, + "cropWidth": { + "description": "cropWidth (native unit)", + "type": "number" + }, + "cropX": { + "description": "cropX (native unit)", + "type": "number" + }, + "cropY": { + "description": "cropY (native unit)", + "type": "number" + }, + "fillColor": { + "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "fontSize": { + "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", + "type": "number" + }, + "height": { + "description": "Height in canvas pixels (0 allowed)", + "minimum": 0, + "type": "number" + }, + "imageBorderColor": { + "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "imageBorderWidth": { + "description": "imageBorderWidth in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomLeft": { + "description": "imageCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomRight": { + "description": "imageCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopLeft": { + "description": "imageCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopRight": { + "description": "imageCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "interpolation": { + "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "interpolation_overrides": { + "additionalProperties": { + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "type": "object" + }, + "letterSpacing": { + "description": "Letter spacing in canvas pixels.", + "type": "number" + }, + "lineHeight": { + "description": "lineHeight (native unit)", + "type": "number" + }, + "opacity": { + "description": "Opacity 0-100", + "maximum": 100, + "minimum": 0, + "type": "number" + }, + "paddingBottom": { + "description": "paddingBottom in canvas pixels", + "type": "number" + }, + "paddingLeft": { + "description": "paddingLeft in canvas pixels", + "type": "number" + }, + "paddingRight": { + "description": "paddingRight in canvas pixels", + "type": "number" + }, + "paddingTop": { + "description": "paddingTop in canvas pixels", + "type": "number" + }, + "positionX": { + "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", + "type": "number" + }, + "positionY": { + "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", + "type": "number" + }, + "rotateX": { + "description": "rotateX (native unit)", + "type": "number" + }, + "rotateY": { + "description": "rotateY (native unit)", + "type": "number" + }, + "rotation": { + "description": "Rotation in degrees", + "type": "number" + }, + "scaleX": { + "description": "Horizontal scale multiplier (1 = 100%)", + "type": "number" + }, + "scaleY": { + "description": "Vertical scale multiplier (1 = 100%)", + "type": "number" + }, + "shadowBlur": { + "description": "shadowBlur in canvas pixels", + "type": "number" + }, + "shadowColor": { + "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "shadowOffsetX": { + "description": "shadowOffsetX in canvas pixels", + "type": "number" + }, + "shadowOffsetY": { + "description": "shadowOffsetY in canvas pixels", + "type": "number" + }, + "shadowSpread": { + "description": "shadowSpread in canvas pixels", + "type": "number" + }, + "strokeColor": { + "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "strokeDash": { + "description": "strokeDash in canvas pixels", + "type": "number" + }, + "strokeGap": { + "description": "strokeGap in canvas pixels", + "type": "number" + }, + "strokeTrimEnd": { + "description": "strokeTrimEnd (native unit)", + "type": "number" + }, + "strokeTrimOffset": { + "description": "strokeTrimOffset (native unit)", + "type": "number" + }, + "strokeTrimStart": { + "description": "strokeTrimStart (native unit)", + "type": "number" + }, + "strokeWidth": { + "description": "strokeWidth in canvas pixels", + "type": "number" + }, + "textBackgroundColor": { + "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textBgRadiusBottomLeft": { + "description": "textBgRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusBottomRight": { + "description": "textBgRadiusBottomRight in canvas pixels", + "type": "number" + }, + "textBgRadiusTopLeft": { + "description": "textBgRadiusTopLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusTopRight": { + "description": "textBgRadiusTopRight in canvas pixels", + "type": "number" + }, + "textColor": { + "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeColor": { + "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeDash": { + "description": "textStrokeDash in canvas pixels", + "type": "number" + }, + "textStrokeGap": { + "description": "textStrokeGap in canvas pixels", + "type": "number" + }, + "textStrokeWidth": { + "description": "textStrokeWidth in canvas pixels", + "type": "number" + }, + "timestamp": { + "description": "Clip-relative time in seconds", + "minimum": 0, + "type": "number" + }, + "videoCornerRadiusBottomLeft": { + "description": "videoCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusBottomRight": { + "description": "videoCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopLeft": { + "description": "videoCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopRight": { + "description": "videoCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "width": { + "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } +] - changed
Input schema / properties / elements / items / properties / keyframes / anyOfPrevious value: -[ - { - "items": { - "additionalProperties": false, - "properties": { - "backgroundBlur": { - "description": "Backdrop blur behind the element", - "type": "number" - }, - "bezier": { - "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "bezier_overrides": { - "additionalProperties": { - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "string" - }, - "required": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "object" - }, - "blur": { - "description": "Layer blur", - "type": "number" - }, - "borderRadiusBottomLeft": { - "description": "borderRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "borderRadiusBottomRight": { - "description": "borderRadiusBottomRight in canvas pixels", - "type": "number" - }, - "borderRadiusTopLeft": { - "description": "borderRadiusTopLeft in canvas pixels", - "type": "number" - }, - "borderRadiusTopRight": { - "description": "borderRadiusTopRight in canvas pixels", - "type": "number" - }, - "cropHeight": { - "description": "cropHeight (native unit)", - "type": "number" - }, - "cropWidth": { - "description": "cropWidth (native unit)", - "type": "number" - }, - "cropX": { - "description": "cropX (native unit)", - "type": "number" - }, - "cropY": { - "description": "cropY (native unit)", - "type": "number" - }, - "fillColor": { - "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "fontSize": { - "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", - "type": "number" - }, - "height": { - "description": "Height in canvas pixels (0 allowed)", - "minimum": 0, - "type": "number" - }, - "imageBorderColor": { - "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "imageBorderWidth": { - "description": "imageBorderWidth in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomLeft": { - "description": "imageCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomRight": { - "description": "imageCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopLeft": { - "description": "imageCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopRight": { - "description": "imageCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "interpolation": { - "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "interpolation_overrides": { - "additionalProperties": { - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "string" - }, - "required": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "object" - }, - "letterSpacing": { - "description": "Letter spacing in canvas pixels.", - "type": "number" - }, - "lineHeight": { - "description": "lineHeight (native unit)", - "type": "number" - }, - "opacity": { - "description": "Opacity 0-100", - "maximum": 100, - "minimum": 0, - "type": "number" - }, - "paddingBottom": { - "description": "paddingBottom in canvas pixels", - "type": "number" - }, - "paddingLeft": { - "description": "paddingLeft in canvas pixels", - "type": "number" - }, - "paddingRight": { - "description": "paddingRight in canvas pixels", - "type": "number" - }, - "paddingTop": { - "description": "paddingTop in canvas pixels", - "type": "number" - }, - "positionX": { - "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", - "type": "number" - }, - "positionY": { - "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", - "type": "number" - }, - "rotateX": { - "description": "rotateX (native unit)", - "type": "number" - }, - "rotateY": { - "description": "rotateY (native unit)", - "type": "number" - }, - "rotation": { - "description": "Rotation in degrees", - "type": "number" - }, - "scaleX": { - "description": "Horizontal scale multiplier (1 = 100%)", - "type": "number" - }, - "scaleY": { - "description": "Vertical scale multiplier (1 = 100%)", - "type": "number" - }, - "shadowBlur": { - "description": "shadowBlur in canvas pixels", - "type": "number" - }, - "shadowColor": { - "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "shadowOffsetX": { - "description": "shadowOffsetX in canvas pixels", - "type": "number" - }, - "shadowOffsetY": { - "description": "shadowOffsetY in canvas pixels", - "type": "number" - }, - "shadowSpread": { - "description": "shadowSpread in canvas pixels", - "type": "number" - }, - "strokeColor": { - "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "strokeDash": { - "description": "strokeDash in canvas pixels", - "type": "number" - }, - "strokeGap": { - "description": "strokeGap in canvas pixels", - "type": "number" - }, - "strokeTrimEnd": { - "description": "strokeTrimEnd (native unit)", - "type": "number" - }, - "strokeTrimOffset": { - "description": "strokeTrimOffset (native unit)", - "type": "number" - }, - "strokeTrimStart": { - "description": "strokeTrimStart (native unit)", - "type": "number" - }, - "strokeWidth": { - "description": "strokeWidth in canvas pixels", - "type": "number" - }, - "textBackgroundColor": { - "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textBgRadiusBottomLeft": { - "description": "textBgRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusBottomRight": { - "description": "textBgRadiusBottomRight in canvas pixels", - "type": "number" - }, - "textBgRadiusTopLeft": { - "description": "textBgRadiusTopLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusTopRight": { - "description": "textBgRadiusTopRight in canvas pixels", - "type": "number" - }, - "textColor": { - "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textStrokeColor": { - "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textStrokeDash": { - "description": "textStrokeDash in canvas pixels", - "type": "number" - }, - "textStrokeGap": { - "description": "textStrokeGap in canvas pixels", - "type": "number" - }, - "textStrokeWidth": { - "description": "textStrokeWidth in canvas pixels", - "type": "number" - }, - "timestamp": { - "description": "Clip-relative time in seconds", - "minimum": 0, - "type": "number" - }, - "videoCornerRadiusBottomLeft": { - "description": "videoCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusBottomRight": { - "description": "videoCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopLeft": { - "description": "videoCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopRight": { - "description": "videoCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "width": { - "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", - "minimum": 0, - "type": "number" - } - }, - "required": [ - "timestamp" - ], - "type": "object" - }, - "type": "array" - }, - { - "type": "null" - } -]New value: +[ + { + "items": { + "additionalProperties": false, + "properties": { + "backgroundBlur": { + "description": "Backdrop blur behind the element", + "type": "number" + }, + "bezier": { + "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "bezier_overrides": { + "additionalProperties": { + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "type": "object" + }, + "blur": { + "description": "Layer blur", + "type": "number" + }, + "borderRadiusBottomLeft": { + "description": "borderRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "borderRadiusBottomRight": { + "description": "borderRadiusBottomRight in canvas pixels", + "type": "number" + }, + "borderRadiusTopLeft": { + "description": "borderRadiusTopLeft in canvas pixels", + "type": "number" + }, + "borderRadiusTopRight": { + "description": "borderRadiusTopRight in canvas pixels", + "type": "number" + }, + "cropHeight": { + "description": "cropHeight (native unit)", + "type": "number" + }, + "cropWidth": { + "description": "cropWidth (native unit)", + "type": "number" + }, + "cropX": { + "description": "cropX (native unit)", + "type": "number" + }, + "cropY": { + "description": "cropY (native unit)", + "type": "number" + }, + "fillColor": { + "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "fontSize": { + "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", + "type": "number" + }, + "height": { + "description": "Height in canvas pixels (0 allowed)", + "minimum": 0, + "type": "number" + }, + "imageBorderColor": { + "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "imageBorderWidth": { + "description": "imageBorderWidth in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomLeft": { + "description": "imageCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomRight": { + "description": "imageCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopLeft": { + "description": "imageCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopRight": { + "description": "imageCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "interpolation": { + "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "interpolation_overrides": { + "additionalProperties": { + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "type": "object" + }, + "letterSpacing": { + "description": "Letter spacing in canvas pixels.", + "type": "number" + }, + "lineHeight": { + "description": "lineHeight (native unit)", + "type": "number" + }, + "opacity": { + "description": "Opacity 0-100", + "maximum": 100, + "minimum": 0, + "type": "number" + }, + "paddingBottom": { + "description": "paddingBottom in canvas pixels", + "type": "number" + }, + "paddingLeft": { + "description": "paddingLeft in canvas pixels", + "type": "number" + }, + "paddingRight": { + "description": "paddingRight in canvas pixels", + "type": "number" + }, + "paddingTop": { + "description": "paddingTop in canvas pixels", + "type": "number" + }, + "positionX": { + "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", + "type": "number" + }, + "positionY": { + "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", + "type": "number" + }, + "rotateX": { + "description": "rotateX (native unit)", + "type": "number" + }, + "rotateY": { + "description": "rotateY (native unit)", + "type": "number" + }, + "rotation": { + "description": "Rotation in degrees", + "type": "number" + }, + "scaleX": { + "description": "Horizontal scale multiplier (1 = 100%)", + "type": "number" + }, + "scaleY": { + "description": "Vertical scale multiplier (1 = 100%)", + "type": "number" + }, + "shadowBlur": { + "description": "shadowBlur in canvas pixels", + "type": "number" + }, + "shadowColor": { + "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "shadowOffsetX": { + "description": "shadowOffsetX in canvas pixels", + "type": "number" + }, + "shadowOffsetY": { + "description": "shadowOffsetY in canvas pixels", + "type": "number" + }, + "shadowSpread": { + "description": "shadowSpread in canvas pixels", + "type": "number" + }, + "strokeColor": { + "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "strokeDash": { + "description": "strokeDash in canvas pixels", + "type": "number" + }, + "strokeGap": { + "description": "strokeGap in canvas pixels", + "type": "number" + }, + "strokeTrimEnd": { + "description": "strokeTrimEnd (native unit)", + "type": "number" + }, + "strokeTrimOffset": { + "description": "strokeTrimOffset (native unit)", + "type": "number" + }, + "strokeTrimStart": { + "description": "strokeTrimStart (native unit)", + "type": "number" + }, + "strokeWidth": { + "description": "strokeWidth in canvas pixels", + "type": "number" + }, + "textBackgroundColor": { + "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textBgRadiusBottomLeft": { + "description": "textBgRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusBottomRight": { + "description": "textBgRadiusBottomRight in canvas pixels", + "type": "number" + }, + "textBgRadiusTopLeft": { + "description": "textBgRadiusTopLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusTopRight": { + "description": "textBgRadiusTopRight in canvas pixels", + "type": "number" + }, + "textColor": { + "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeColor": { + "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeDash": { + "description": "textStrokeDash in canvas pixels", + "type": "number" + }, + "textStrokeGap": { + "description": "textStrokeGap in canvas pixels", + "type": "number" + }, + "textStrokeWidth": { + "description": "textStrokeWidth in canvas pixels", + "type": "number" + }, + "timestamp": { + "description": "Clip-relative time in seconds", + "minimum": 0, + "type": "number" + }, + "videoCornerRadiusBottomLeft": { + "description": "videoCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusBottomRight": { + "description": "videoCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopLeft": { + "description": "videoCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopRight": { + "description": "videoCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "width": { + "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } +] - changed
Input schema / properties / returning / descriptionPrevious value: -"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."New value: +"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). A text element measured on a fallback face is listed in top-level `font_warnings` whichever you choose. ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."
- Changed
find1 field changed- changed
Input schema / properties / type / enumPrevious value: -[ - "projects", - "folders", - "clueprints", - "workspaces", - "backgrounds", - "voices", - "image_gen_style_packs", - "element_components", - "images", - "videos", - "music", - "sfx" -]New value: +[ + "projects", + "folders", + "clueprints", + "workspaces", + "backgrounds", + "voices", + "fonts", + "image_gen_style_packs", + "element_components", + "images", + "videos", + "music", + "sfx" +]
- Changed
generate_media7 fields changed- added
Input schema / additionalPropertiesAdded value: +{} - removed
Input schema / properties / animation_setting / properties / entry / properties / duration_per_unit_ms / exclusiveMinimumRemoved value: -0 - added
Input schema / properties / animation_setting / properties / entry / properties / duration_per_unit_ms / minimumAdded value: +0 - removed
Input schema / properties / animation_setting / properties / exit / properties / duration_per_unit_ms / exclusiveMinimumRemoved value: -0 - added
Input schema / properties / animation_setting / properties / exit / properties / duration_per_unit_ms / minimumAdded value: +0 - added
Input schema / properties / aspect_ratioAdded value: +{ + "description": "Image only. Overrides the ratio inferred from width/height. Leave it off and the box decides, which is usually what you want — set it when the box is a placeholder and you know the shape you need. Still clamped to what the model accepts: gpt-image-1/1.5 only do 1:1, 4:3 and 3:4; the gpt-image-2.5 pair adds 16:9 and 9:16; gpt-image-2 has no 3:2 or 2:3, so those become 4:3 and 3:4. The response does not report the ratio used.", + "enum": [ + "1:1", + "4:3", + "3:4", + "16:9", + "9:16", + "3:2", + "2:3" + ], + "type": "string" +} - changed
Input schema / properties / background / descriptionPrevious value: -"Image only, and only honoured by `gpt-image-2.5-flare`, `gpt-image-2.5-sunburst`, `gpt-image-1` and `gpt-image-1.5` — every other model is always opaque and ignores this. Pass `false` for a cut-out with no background: icons, logos, stickers, anything meant to sit ON the composition rather than behind it. You MUST set `model` to one of those four in the same call; `gpt-image-2.5-flare` is the one to default to, since the older pair cannot frame wide."New value: +"Image only, and only honoured by `gpt-image-2.5-flare`, `gpt-image-2.5-sunburst`, `gpt-image-1` and `gpt-image-1.5` — every other model is always opaque and ignores this. Pass `false` for a cut-out with no background: icons, logos, stickers, anything meant to sit ON the composition rather than behind it. You MUST set `model` to one of those four in the same call; `gpt-image-2.5-flare` is the one to default to, since the older pair cannot frame wide. Asking for transparency in the PROMPT instead does not work — the model paints a grey-and-white checkerboard as real pixels."
- Changed
remove_from_project3 fields changed- changed
Input schema / properties / clip_index / descriptionPrevious value: -"Zero-based clip index (required for target='element')"New value: +"Zero-based clip index. Required for target='group'; for target='element' an optional hint — the element is found by id either way" - changed
Input schema / properties / element_id / descriptionPrevious value: -"Element ID to remove (required for target='element')"New value: +"Element ID to remove (target='element'; or use element_ids)" - added
Input schema / properties / element_idsAdded value: +{ + "description": "Several element IDs to remove (target='element'). Removed one at a time, so a failure part-way leaves the earlier ones removed; retrying the same list is safe — ids already gone come back as already_absent. For a large batch prefer remove_elements, which lands in one save", + "items": { + "type": "string" + }, + "type": "array" +}
- Changed
run_script1 field changed- changed
Input schema / properties / timeout_seconds / descriptionPrevious value: -"Wall-clock budget, default 45s. Raise it only if your client's own request timeout is longer — many cut off at 60s, and a script killed by the client reports nothing at all. Watch the slow tools: analyze_audio in 'transcript' or 'beats' mode, export_project and auto_sync take tens of seconds each and will eat a budget fast. analyze_audio in 'features' mode is ~1s and is fine to loop over."New value: +"Wall-clock budget for the SCRIPT — separate from wait_seconds, which is only how long this call stays open. By default a script gets 45s while you are waiting on it, and is raised to 5 minutes the moment it outlives the wait and becomes a job you poll with get_script_job. Set this only to override BOTH with one fixed budget. Watch the slow tools: analyze_audio in 'transcript' or 'beats' mode, export_project and auto_sync take tens of seconds each and will eat a budget fast. analyze_audio in 'features' mode is ~1s and is fine to loop over."
- Changed
update_elements4 fields changed- changed
Input schema / properties / defaults / properties / keyframes / anyOfPrevious value: -[ - { - "items": { - "additionalProperties": false, - "properties": { - "backgroundBlur": { - "description": "Backdrop blur behind the element", - "type": "number" - }, - "bezier": { - "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "bezier_overrides": { - "additionalProperties": { - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "string" - }, - "required": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "object" - }, - "blur": { - "description": "Layer blur", - "type": "number" - }, - "borderRadiusBottomLeft": { - "description": "borderRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "borderRadiusBottomRight": { - "description": "borderRadiusBottomRight in canvas pixels", - "type": "number" - }, - "borderRadiusTopLeft": { - "description": "borderRadiusTopLeft in canvas pixels", - "type": "number" - }, - "borderRadiusTopRight": { - "description": "borderRadiusTopRight in canvas pixels", - "type": "number" - }, - "cropHeight": { - "description": "cropHeight (native unit)", - "type": "number" - }, - "cropWidth": { - "description": "cropWidth (native unit)", - "type": "number" - }, - "cropX": { - "description": "cropX (native unit)", - "type": "number" - }, - "cropY": { - "description": "cropY (native unit)", - "type": "number" - }, - "fillColor": { - "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "fontSize": { - "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", - "type": "number" - }, - "height": { - "description": "Height in canvas pixels (0 allowed)", - "minimum": 0, - "type": "number" - }, - "imageBorderColor": { - "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "imageBorderWidth": { - "description": "imageBorderWidth in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomLeft": { - "description": "imageCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomRight": { - "description": "imageCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopLeft": { - "description": "imageCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopRight": { - "description": "imageCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "interpolation": { - "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "interpolation_overrides": { - "additionalProperties": { - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "string" - }, - "required": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "object" - }, - "letterSpacing": { - "description": "Letter spacing in canvas pixels.", - "type": "number" - }, - "lineHeight": { - "description": "lineHeight (native unit)", - "type": "number" - }, - "opacity": { - "description": "Opacity 0-100", - "maximum": 100, - "minimum": 0, - "type": "number" - }, - "paddingBottom": { - "description": "paddingBottom in canvas pixels", - "type": "number" - }, - "paddingLeft": { - "description": "paddingLeft in canvas pixels", - "type": "number" - }, - "paddingRight": { - "description": "paddingRight in canvas pixels", - "type": "number" - }, - "paddingTop": { - "description": "paddingTop in canvas pixels", - "type": "number" - }, - "positionX": { - "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", - "type": "number" - }, - "positionY": { - "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", - "type": "number" - }, - "rotateX": { - "description": "rotateX (native unit)", - "type": "number" - }, - "rotateY": { - "description": "rotateY (native unit)", - "type": "number" - }, - "rotation": { - "description": "Rotation in degrees", - "type": "number" - }, - "scaleX": { - "description": "Horizontal scale multiplier (1 = 100%)", - "type": "number" - }, - "scaleY": { - "description": "Vertical scale multiplier (1 = 100%)", - "type": "number" - }, - "shadowBlur": { - "description": "shadowBlur in canvas pixels", - "type": "number" - }, - "shadowColor": { - "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "shadowOffsetX": { - "description": "shadowOffsetX in canvas pixels", - "type": "number" - }, - "shadowOffsetY": { - "description": "shadowOffsetY in canvas pixels", - "type": "number" - }, - "shadowSpread": { - "description": "shadowSpread in canvas pixels", - "type": "number" - }, - "strokeColor": { - "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "strokeDash": { - "description": "strokeDash in canvas pixels", - "type": "number" - }, - "strokeGap": { - "description": "strokeGap in canvas pixels", - "type": "number" - }, - "strokeTrimEnd": { - "description": "strokeTrimEnd (native unit)", - "type": "number" - }, - "strokeTrimOffset": { - "description": "strokeTrimOffset (native unit)", - "type": "number" - }, - "strokeTrimStart": { - "description": "strokeTrimStart (native unit)", - "type": "number" - }, - "strokeWidth": { - "description": "strokeWidth in canvas pixels", - "type": "number" - }, - "textBackgroundColor": { - "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textBgRadiusBottomLeft": { - "description": "textBgRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusBottomRight": { - "description": "textBgRadiusBottomRight in canvas pixels", - "type": "number" - }, - "textBgRadiusTopLeft": { - "description": "textBgRadiusTopLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusTopRight": { - "description": "textBgRadiusTopRight in canvas pixels", - "type": "number" - }, - "textColor": { - "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textStrokeColor": { - "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textStrokeDash": { - "description": "textStrokeDash in canvas pixels", - "type": "number" - }, - "textStrokeGap": { - "description": "textStrokeGap in canvas pixels", - "type": "number" - }, - "textStrokeWidth": { - "description": "textStrokeWidth in canvas pixels", - "type": "number" - }, - "timestamp": { - "description": "Clip-relative time in seconds", - "minimum": 0, - "type": "number" - }, - "videoCornerRadiusBottomLeft": { - "description": "videoCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusBottomRight": { - "description": "videoCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopLeft": { - "description": "videoCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopRight": { - "description": "videoCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "width": { - "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", - "minimum": 0, - "type": "number" - } - }, - "required": [ - "timestamp" - ], - "type": "object" - }, - "type": "array" - }, - { - "type": "null" - } -]New value: +[ + { + "items": { + "additionalProperties": false, + "properties": { + "backgroundBlur": { + "description": "Backdrop blur behind the element", + "type": "number" + }, + "bezier": { + "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "bezier_overrides": { + "additionalProperties": { + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "type": "object" + }, + "blur": { + "description": "Layer blur", + "type": "number" + }, + "borderRadiusBottomLeft": { + "description": "borderRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "borderRadiusBottomRight": { + "description": "borderRadiusBottomRight in canvas pixels", + "type": "number" + }, + "borderRadiusTopLeft": { + "description": "borderRadiusTopLeft in canvas pixels", + "type": "number" + }, + "borderRadiusTopRight": { + "description": "borderRadiusTopRight in canvas pixels", + "type": "number" + }, + "cropHeight": { + "description": "cropHeight (native unit)", + "type": "number" + }, + "cropWidth": { + "description": "cropWidth (native unit)", + "type": "number" + }, + "cropX": { + "description": "cropX (native unit)", + "type": "number" + }, + "cropY": { + "description": "cropY (native unit)", + "type": "number" + }, + "fillColor": { + "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "fontSize": { + "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", + "type": "number" + }, + "height": { + "description": "Height in canvas pixels (0 allowed)", + "minimum": 0, + "type": "number" + }, + "imageBorderColor": { + "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "imageBorderWidth": { + "description": "imageBorderWidth in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomLeft": { + "description": "imageCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomRight": { + "description": "imageCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopLeft": { + "description": "imageCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopRight": { + "description": "imageCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "interpolation": { + "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "interpolation_overrides": { + "additionalProperties": { + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "type": "object" + }, + "letterSpacing": { + "description": "Letter spacing in canvas pixels.", + "type": "number" + }, + "lineHeight": { + "description": "lineHeight (native unit)", + "type": "number" + }, + "opacity": { + "description": "Opacity 0-100", + "maximum": 100, + "minimum": 0, + "type": "number" + }, + "paddingBottom": { + "description": "paddingBottom in canvas pixels", + "type": "number" + }, + "paddingLeft": { + "description": "paddingLeft in canvas pixels", + "type": "number" + }, + "paddingRight": { + "description": "paddingRight in canvas pixels", + "type": "number" + }, + "paddingTop": { + "description": "paddingTop in canvas pixels", + "type": "number" + }, + "positionX": { + "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", + "type": "number" + }, + "positionY": { + "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", + "type": "number" + }, + "rotateX": { + "description": "rotateX (native unit)", + "type": "number" + }, + "rotateY": { + "description": "rotateY (native unit)", + "type": "number" + }, + "rotation": { + "description": "Rotation in degrees", + "type": "number" + }, + "scaleX": { + "description": "Horizontal scale multiplier (1 = 100%)", + "type": "number" + }, + "scaleY": { + "description": "Vertical scale multiplier (1 = 100%)", + "type": "number" + }, + "shadowBlur": { + "description": "shadowBlur in canvas pixels", + "type": "number" + }, + "shadowColor": { + "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "shadowOffsetX": { + "description": "shadowOffsetX in canvas pixels", + "type": "number" + }, + "shadowOffsetY": { + "description": "shadowOffsetY in canvas pixels", + "type": "number" + }, + "shadowSpread": { + "description": "shadowSpread in canvas pixels", + "type": "number" + }, + "strokeColor": { + "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "strokeDash": { + "description": "strokeDash in canvas pixels", + "type": "number" + }, + "strokeGap": { + "description": "strokeGap in canvas pixels", + "type": "number" + }, + "strokeTrimEnd": { + "description": "strokeTrimEnd (native unit)", + "type": "number" + }, + "strokeTrimOffset": { + "description": "strokeTrimOffset (native unit)", + "type": "number" + }, + "strokeTrimStart": { + "description": "strokeTrimStart (native unit)", + "type": "number" + }, + "strokeWidth": { + "description": "strokeWidth in canvas pixels", + "type": "number" + }, + "textBackgroundColor": { + "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textBgRadiusBottomLeft": { + "description": "textBgRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusBottomRight": { + "description": "textBgRadiusBottomRight in canvas pixels", + "type": "number" + }, + "textBgRadiusTopLeft": { + "description": "textBgRadiusTopLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusTopRight": { + "description": "textBgRadiusTopRight in canvas pixels", + "type": "number" + }, + "textColor": { + "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeColor": { + "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeDash": { + "description": "textStrokeDash in canvas pixels", + "type": "number" + }, + "textStrokeGap": { + "description": "textStrokeGap in canvas pixels", + "type": "number" + }, + "textStrokeWidth": { + "description": "textStrokeWidth in canvas pixels", + "type": "number" + }, + "timestamp": { + "description": "Clip-relative time in seconds", + "minimum": 0, + "type": "number" + }, + "videoCornerRadiusBottomLeft": { + "description": "videoCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusBottomRight": { + "description": "videoCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopLeft": { + "description": "videoCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopRight": { + "description": "videoCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "width": { + "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } +] - changed
Input schema / properties / returning / descriptionPrevious value: -"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."New value: +"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). A text element measured on a fallback face is listed in top-level `font_warnings` whichever you choose. ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write." - changed
Input schema / properties / updates / items / properties / keyframes / anyOfPrevious value: -[ - { - "items": { - "additionalProperties": false, - "properties": { - "backgroundBlur": { - "description": "Backdrop blur behind the element", - "type": "number" - }, - "bezier": { - "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "bezier_overrides": { - "additionalProperties": { - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "string" - }, - "required": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "object" - }, - "blur": { - "description": "Layer blur", - "type": "number" - }, - "borderRadiusBottomLeft": { - "description": "borderRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "borderRadiusBottomRight": { - "description": "borderRadiusBottomRight in canvas pixels", - "type": "number" - }, - "borderRadiusTopLeft": { - "description": "borderRadiusTopLeft in canvas pixels", - "type": "number" - }, - "borderRadiusTopRight": { - "description": "borderRadiusTopRight in canvas pixels", - "type": "number" - }, - "cropHeight": { - "description": "cropHeight (native unit)", - "type": "number" - }, - "cropWidth": { - "description": "cropWidth (native unit)", - "type": "number" - }, - "cropX": { - "description": "cropX (native unit)", - "type": "number" - }, - "cropY": { - "description": "cropY (native unit)", - "type": "number" - }, - "fillColor": { - "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "fontSize": { - "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", - "type": "number" - }, - "height": { - "description": "Height in canvas pixels (0 allowed)", - "minimum": 0, - "type": "number" - }, - "imageBorderColor": { - "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "imageBorderWidth": { - "description": "imageBorderWidth in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomLeft": { - "description": "imageCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomRight": { - "description": "imageCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopLeft": { - "description": "imageCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopRight": { - "description": "imageCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "interpolation": { - "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "interpolation_overrides": { - "additionalProperties": { - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "string" - }, - "required": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ], - "type": "object" - }, - "letterSpacing": { - "description": "Letter spacing in canvas pixels.", - "type": "number" - }, - "lineHeight": { - "description": "lineHeight (native unit)", - "type": "number" - }, - "opacity": { - "description": "Opacity 0-100", - "maximum": 100, - "minimum": 0, - "type": "number" - }, - "paddingBottom": { - "description": "paddingBottom in canvas pixels", - "type": "number" - }, - "paddingLeft": { - "description": "paddingLeft in canvas pixels", - "type": "number" - }, - "paddingRight": { - "description": "paddingRight in canvas pixels", - "type": "number" - }, - "paddingTop": { - "description": "paddingTop in canvas pixels", - "type": "number" - }, - "positionX": { - "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", - "type": "number" - }, - "positionY": { - "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", - "type": "number" - }, - "rotateX": { - "description": "rotateX (native unit)", - "type": "number" - }, - "rotateY": { - "description": "rotateY (native unit)", - "type": "number" - }, - "rotation": { - "description": "Rotation in degrees", - "type": "number" - }, - "scaleX": { - "description": "Horizontal scale multiplier (1 = 100%)", - "type": "number" - }, - "scaleY": { - "description": "Vertical scale multiplier (1 = 100%)", - "type": "number" - }, - "shadowBlur": { - "description": "shadowBlur in canvas pixels", - "type": "number" - }, - "shadowColor": { - "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "shadowOffsetX": { - "description": "shadowOffsetX in canvas pixels", - "type": "number" - }, - "shadowOffsetY": { - "description": "shadowOffsetY in canvas pixels", - "type": "number" - }, - "shadowSpread": { - "description": "shadowSpread in canvas pixels", - "type": "number" - }, - "strokeColor": { - "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "strokeDash": { - "description": "strokeDash in canvas pixels", - "type": "number" - }, - "strokeGap": { - "description": "strokeGap in canvas pixels", - "type": "number" - }, - "strokeTrimEnd": { - "description": "strokeTrimEnd (native unit)", - "type": "number" - }, - "strokeTrimOffset": { - "description": "strokeTrimOffset (native unit)", - "type": "number" - }, - "strokeTrimStart": { - "description": "strokeTrimStart (native unit)", - "type": "number" - }, - "strokeWidth": { - "description": "strokeWidth in canvas pixels", - "type": "number" - }, - "textBackgroundColor": { - "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textBgRadiusBottomLeft": { - "description": "textBgRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusBottomRight": { - "description": "textBgRadiusBottomRight in canvas pixels", - "type": "number" - }, - "textBgRadiusTopLeft": { - "description": "textBgRadiusTopLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusTopRight": { - "description": "textBgRadiusTopRight in canvas pixels", - "type": "number" - }, - "textColor": { - "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textStrokeColor": { - "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "textStrokeDash": { - "description": "textStrokeDash in canvas pixels", - "type": "number" - }, - "textStrokeGap": { - "description": "textStrokeGap in canvas pixels", - "type": "number" - }, - "textStrokeWidth": { - "description": "textStrokeWidth in canvas pixels", - "type": "number" - }, - "timestamp": { - "description": "Clip-relative time in seconds", - "minimum": 0, - "type": "number" - }, - "videoCornerRadiusBottomLeft": { - "description": "videoCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusBottomRight": { - "description": "videoCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopLeft": { - "description": "videoCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopRight": { - "description": "videoCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "width": { - "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", - "minimum": 0, - "type": "number" - } - }, - "required": [ - "timestamp" - ], - "type": "object" - }, - "type": "array" - }, - { - "type": "null" - } -]New value: +[ + { + "items": { + "additionalProperties": false, + "properties": { + "backgroundBlur": { + "description": "Backdrop blur behind the element", + "type": "number" + }, + "bezier": { + "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "bezier_overrides": { + "additionalProperties": { + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "type": "object" + }, + "blur": { + "description": "Layer blur", + "type": "number" + }, + "borderRadiusBottomLeft": { + "description": "borderRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "borderRadiusBottomRight": { + "description": "borderRadiusBottomRight in canvas pixels", + "type": "number" + }, + "borderRadiusTopLeft": { + "description": "borderRadiusTopLeft in canvas pixels", + "type": "number" + }, + "borderRadiusTopRight": { + "description": "borderRadiusTopRight in canvas pixels", + "type": "number" + }, + "cropHeight": { + "description": "cropHeight (native unit)", + "type": "number" + }, + "cropWidth": { + "description": "cropWidth (native unit)", + "type": "number" + }, + "cropX": { + "description": "cropX (native unit)", + "type": "number" + }, + "cropY": { + "description": "cropY (native unit)", + "type": "number" + }, + "fillColor": { + "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "fontSize": { + "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", + "type": "number" + }, + "height": { + "description": "Height in canvas pixels (0 allowed)", + "minimum": 0, + "type": "number" + }, + "imageBorderColor": { + "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "imageBorderWidth": { + "description": "imageBorderWidth in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomLeft": { + "description": "imageCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomRight": { + "description": "imageCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopLeft": { + "description": "imageCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopRight": { + "description": "imageCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "interpolation": { + "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "interpolation_overrides": { + "additionalProperties": { + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "type": "object" + }, + "letterSpacing": { + "description": "Letter spacing in canvas pixels.", + "type": "number" + }, + "lineHeight": { + "description": "lineHeight (native unit)", + "type": "number" + }, + "opacity": { + "description": "Opacity 0-100", + "maximum": 100, + "minimum": 0, + "type": "number" + }, + "paddingBottom": { + "description": "paddingBottom in canvas pixels", + "type": "number" + }, + "paddingLeft": { + "description": "paddingLeft in canvas pixels", + "type": "number" + }, + "paddingRight": { + "description": "paddingRight in canvas pixels", + "type": "number" + }, + "paddingTop": { + "description": "paddingTop in canvas pixels", + "type": "number" + }, + "positionX": { + "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", + "type": "number" + }, + "positionY": { + "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", + "type": "number" + }, + "rotateX": { + "description": "rotateX (native unit)", + "type": "number" + }, + "rotateY": { + "description": "rotateY (native unit)", + "type": "number" + }, + "rotation": { + "description": "Rotation in degrees", + "type": "number" + }, + "scaleX": { + "description": "Horizontal scale multiplier (1 = 100%)", + "type": "number" + }, + "scaleY": { + "description": "Vertical scale multiplier (1 = 100%)", + "type": "number" + }, + "shadowBlur": { + "description": "shadowBlur in canvas pixels", + "type": "number" + }, + "shadowColor": { + "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "shadowOffsetX": { + "description": "shadowOffsetX in canvas pixels", + "type": "number" + }, + "shadowOffsetY": { + "description": "shadowOffsetY in canvas pixels", + "type": "number" + }, + "shadowSpread": { + "description": "shadowSpread in canvas pixels", + "type": "number" + }, + "strokeColor": { + "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "strokeDash": { + "description": "strokeDash in canvas pixels", + "type": "number" + }, + "strokeGap": { + "description": "strokeGap in canvas pixels", + "type": "number" + }, + "strokeTrimEnd": { + "description": "strokeTrimEnd (native unit)", + "type": "number" + }, + "strokeTrimOffset": { + "description": "strokeTrimOffset (native unit)", + "type": "number" + }, + "strokeTrimStart": { + "description": "strokeTrimStart (native unit)", + "type": "number" + }, + "strokeWidth": { + "description": "strokeWidth in canvas pixels", + "type": "number" + }, + "textBackgroundColor": { + "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textBgRadiusBottomLeft": { + "description": "textBgRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusBottomRight": { + "description": "textBgRadiusBottomRight in canvas pixels", + "type": "number" + }, + "textBgRadiusTopLeft": { + "description": "textBgRadiusTopLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusTopRight": { + "description": "textBgRadiusTopRight in canvas pixels", + "type": "number" + }, + "textColor": { + "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeColor": { + "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeDash": { + "description": "textStrokeDash in canvas pixels", + "type": "number" + }, + "textStrokeGap": { + "description": "textStrokeGap in canvas pixels", + "type": "number" + }, + "textStrokeWidth": { + "description": "textStrokeWidth in canvas pixels", + "type": "number" + }, + "timestamp": { + "description": "Clip-relative time in seconds", + "minimum": 0, + "type": "number" + }, + "videoCornerRadiusBottomLeft": { + "description": "videoCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusBottomRight": { + "description": "videoCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopLeft": { + "description": "videoCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopRight": { + "description": "videoCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "width": { + "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } +] - added
Input schema / properties / updates / items / properties / parent_idAdded value: +{ + "description": "The parent `get_clip` reports on this element: a group id, or the clip id for an ungrouped element. Accepted so a read round-trips unedited — the element's current parent is a no-op and leaves z-order alone. A different group id on this element's clip moves it there (the group must have a name); the clip id or null moves it to the root. Use `group` when you are choosing a group — the name is the handle. `group` wins if both are sent.", + "type": [ + "string", + "null" + ] +}
- Changed
update_groups3 fields changed- removed
Input schema / properties / items / items / properties / keyframes / items / properties / bezier_overrides / requiredRemoved value: -[ - "offsetX", - "offsetY", - "scaleX", - "scaleY", - "rotation", - "rotateX", - "rotateY", - "opacity", - "blur" -] - removed
Input schema / properties / items / items / properties / keyframes / items / properties / interpolation_overrides / requiredRemoved value: -[ - "offsetX", - "offsetY", - "scaleX", - "scaleY", - "rotation", - "rotateX", - "rotateY", - "opacity", - "blur" -] - changed
Input schema / properties / returning / descriptionPrevious value: -"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."New value: +"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). A text element measured on a fallback face is listed in top-level `font_warnings` whichever you choose. ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."
- Changed
upload_file1 field changed- added
Input schema / properties / filesAdded value: +{ + "description": "ChatGPT file attachments, one entry per file (filled by ChatGPT).", + "items": { + "properties": { + "download_url": { + "description": "Temporary download URL supplied by ChatGPT", + "type": "string" + }, + "file_id": { + "description": "ChatGPT file id", + "type": "string" + }, + "file_name": { + "type": "string" + }, + "mime_type": { + "type": "string" + } + }, + "required": [ + "download_url", + "file_id" + ], + "type": "object" + }, + "type": "array" +}
1 tool update
- Changed
record_screen8 fields changed- added
Input schema / properties / article_script_modeAdded value: +{ + "description": "'exact': the article is used word for word. 'rewrite': the article may be reworded to match the recording. Overrides exact_article_script when both are set.", + "enum": [ + "rewrite", + "exact" + ], + "type": "string" +} - changed
Input schema / properties / exact_article_script / descriptionPrevious value: -"Set to true when the article must be used exactly as written — the agent that does the recording will not reword, rephrase, or rewrite article_script at all. Default false."New value: +"Legacy flag — prefer article_script_mode instead. Set to true when the article must be used exactly as written — the agent that does the recording will not reword, rephrase, or rewrite article_script at all. Default false." - changed
Input schema / properties / exact_video_script / descriptionPrevious value: -"Set to true when the video narration must be used exactly as written — the agent that does the recording will not reword, rephrase, or rewrite video_script at all. Default false."New value: +"Legacy flag — prefer video_script_mode instead. Set to true when the video narration must be used exactly as written — the agent that does the recording will not reword, rephrase, or rewrite video_script at all. Default false." - added
Input schema / properties / scenes / items / properties / article_script_modeAdded value: +{ + "description": "How the article is treated for this scene. Overrides the top-level setting for this scene.", + "enum": [ + "rewrite", + "exact" + ], + "type": "string" +} - changed
Input schema / properties / scenes / items / properties / exact_article_script / descriptionPrevious value: -"When true, article_script for this scene is used verbatim and left unreworded. Overrides the top-level setting for this scene."New value: +"Legacy flag — prefer article_script_mode instead. When true, article_script for this scene is used verbatim and left unreworded. Overrides the top-level setting for this scene." - changed
Input schema / properties / scenes / items / properties / exact_video_script / descriptionPrevious value: -"When true, narration_script for this scene is used verbatim and left unreworded. Overrides the top-level setting for this scene."New value: +"Legacy flag — prefer video_script_mode instead. When true, narration_script for this scene is used verbatim and left unreworded. Overrides the top-level setting for this scene." - added
Input schema / properties / scenes / items / properties / video_script_modeAdded value: +{ + "description": "How the narration is treated for this scene. Overrides the top-level setting for this scene.", + "enum": [ + "rewrite", + "near_exact", + "exact" + ], + "type": "string" +} - added
Input schema / properties / video_script_modeAdded value: +{ + "description": "How the narration is treated. 'exact': the user's narration is final and is read word for word; steps the script does not mention play silently. 'near_exact': keep the user's narration word for word, but briefly narrate steps the recording must take that the script does not mention (for example opening a settings dialog to reach something) — use this when the user gives a finished script and did not ask for strictly exact wording. 'rewrite': the narration is a draft and may be reworded to match what was recorded — use this when there is no user script or it is rough. Overrides exact_video_script when both are set.", + "enum": [ + "rewrite", + "near_exact", + "exact" + ], + "type": "string" +}
1 tool update
- Changed
get_clip2 fields changed- changed
Input schema / properties / select / descriptionPrevious value: -"Ask for exactly the JSON you want, GraphQL-style. Omit for everything; pass [] for none.\n Sections: 'elements' (whole element rows), 'voiceover_words' (per-word VO timings; returns the key of the same name, holding `{word, start, end, punctuated_word}` with start/end in SECONDS — null on a clip with no transcription), 'groups' (group rows: id, name, parent_id, bounds_px, anchor_px, keyframes), 'busy' (generations still writing to this clip, as `[{entity_path, job_type}]` — EMPTY means nothing is pending, which is how you know a voiceover or AI image has landed; it is the same lock that would refuse your write, so a non-empty list also tells you what not to touch yet). Each section returns the key it is named after. Rendering is `render`, not a value here.\n Per-key: 'elements.<key>' projects element rows to just those keys (id is always kept). Keys: name, element_type, x, y, width, height, start_time, end_time, rotation, keyframes, textdata, shapedata, imagedata, videodata, zoomdata, codedata, parent_id. y_top is text-only and present ONLY when alignment is 'center' — the unambiguous TOP edge, which is exactly the case where `y` is NOT the top but the vertical CENTRE. To put that position back, send it as `y` with y_anchor:'top'.\n Examples: ['elements.x','elements.y','elements.width','elements.height'] to read geometry; ['elements.name','elements.start_time','elements.end_time'] for a timing pass; ['voiceover_words'] to sync visuals to narration; ['groups'] to resolve a group id for update_groups; [] with render:{} returns the PNG with no JSON (smallest read); ['elements.textdata','voiceover_words'] to rewrite copy against the VO.\n Mixing 'elements' with 'elements.<key>' returns whole rows. Use element_ids to choose WHICH rows — that is independent of this."New value: +"Ask for exactly the JSON you want, GraphQL-style. Omit for everything; pass [] for none.\n Sections: 'elements' (whole element rows), 'voiceover_words' (per-word VO timings; returns the key of the same name, holding `{word, start, end, punctuated_word}` with start/end in SECONDS — null on a clip with no transcription), 'groups' (group rows: id, name, parent_id, bounds_px, anchor_px, keyframes), 'busy' (generations still writing to this clip, as `[{entity_path, job_type}]` — EMPTY means nothing is pending, which is how you know a voiceover or AI image has landed; it is the same lock that would refuse your write, so a non-empty list also tells you what not to touch yet). Each section returns the key it is named after. Rendering is `render`, not a value here.\n Per-key: 'elements.<key>' projects element rows to just those keys (id is always kept). Keys: name, element_type, x, y, width, height, start_time, end_time, rotation, keyframes, textdata, shapedata, imagedata, videodata, zoomdata, codedata, parent_id, dropShadows. y_top is text-only and present ONLY when alignment is 'center' — the unambiguous TOP edge, which is exactly the case where `y` is NOT the top but the vertical CENTRE. To put that position back, send it as `y` with y_anchor:'top'.\n Examples: ['elements.x','elements.y','elements.width','elements.height'] to read geometry; ['elements.name','elements.start_time','elements.end_time'] for a timing pass; ['voiceover_words'] to sync visuals to narration; ['groups'] to resolve a group id for update_groups; [] with render:{} returns the PNG with no JSON (smallest read); ['elements.textdata','voiceover_words'] to rewrite copy against the VO.\n Mixing 'elements' with 'elements.<key>' returns whole rows. Use element_ids to choose WHICH rows — that is independent of this." - changed
Input schema / properties / select / items / enumPrevious value: -[ - "elements", - "voiceover_words", - "groups", - "busy", - "elements.name", - "elements.element_type", - "elements.x", - "elements.y", - "elements.width", - "elements.height", - "elements.start_time", - "elements.end_time", - "elements.rotation", - "elements.keyframes", - "elements.textdata", - "elements.shapedata", - "elements.imagedata", - "elements.videodata", - "elements.zoomdata", - "elements.codedata", - "elements.parent_id" -]New value: +[ + "elements", + "voiceover_words", + "groups", + "busy", + "elements.name", + "elements.element_type", + "elements.x", + "elements.y", + "elements.width", + "elements.height", + "elements.start_time", + "elements.end_time", + "elements.rotation", + "elements.keyframes", + "elements.textdata", + "elements.shapedata", + "elements.imagedata", + "elements.videodata", + "elements.zoomdata", + "elements.codedata", + "elements.parent_id", + "elements.dropShadows" +]
44 tool updates
- Changed
add_article_media4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "kind", - "project_id", - "context", - "llm_model" -]New value: +[ + "kind", + "project_id" +]
- Changed
add_audio4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "type", - "context", - "llm_model" -]New value: +[ + "project_id", + "type" +]
- Changed
add_clips4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "kind", - "project_id", - "context", - "llm_model" -]New value: +[ + "kind", + "project_id" +]
- Changed
add_comment4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "comment_text", - "context", - "llm_model" -]New value: +[ + "project_id", + "comment_text" +]
- Changed
add_elements4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "elements", - "context", - "llm_model" -]New value: +[ + "project_id", + "elements" +]
- Changed
add_sync_point4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "word", - "timestamp_seconds", - "context", - "llm_model" -]New value: +[ + "project_id", + "word", + "timestamp_seconds" +]
- Changed
analyze_audio4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "mode", - "context", - "llm_model" -]New value: +[ + "mode" +]
- Changed
auto_sync4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "clip_id", - "context", - "llm_model" -]New value: +[ + "project_id", + "clip_id" +]
- Changed
check_uploads4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "upload_token", - "context", - "llm_model" -]New value: +[ + "upload_token" +]
- Changed
create_clueprint4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "name", - "visibility", - "context", - "llm_model" -]New value: +[ + "name", + "visibility" +]
- Changed
create_project4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - removed
Input schema / requiredRemoved value: -[ - "context", - "llm_model" -]
- Changed
duplicate_clip4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "target_project_id", - "source_clip_id", - "context", - "llm_model" -]New value: +[ + "target_project_id", + "source_clip_id" +]
- Changed
duplicate_project4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "source_project_id", - "context", - "llm_model" -]New value: +[ + "source_project_id" +]
- Changed
estimate_duration4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "texts", - "context", - "llm_model" -]New value: +[ + "texts" +]
- Changed
export_project4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "context", - "llm_model" -]New value: +[ + "project_id" +]
- Changed
find4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "type", - "context", - "llm_model" -]New value: +[ + "type" +]
- Changed
generate_media4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "kind", - "project_id", - "clip_id", - "prompt", - "x", - "y", - "width", - "height", - "context", - "llm_model" -]New value: +[ + "kind", + "project_id", + "clip_id", + "prompt", + "x", + "y", + "width", + "height" +]
- Changed
get_article4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "context", - "llm_model" -]New value: +[ + "project_id" +]
- Changed
get_clip4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "clip_index", - "context", - "llm_model" -]New value: +[ + "project_id", + "clip_index" +]
- Changed
get_clueprint4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "clueprint_id", - "context", - "llm_model" -]New value: +[ + "clueprint_id" +]
- Changed
get_comments4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "context", - "llm_model" -]New value: +[ + "project_id" +]
- Changed
get_design_guide4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - removed
Input schema / requiredRemoved value: -[ - "context", - "llm_model" -]
- Changed
get_element_schema4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "element_type", - "context", - "llm_model" -]New value: +[ + "element_type" +]
- Changed
get_project4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "context", - "llm_model" -]New value: +[ + "project_id" +]
- Changed
get_script_job4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "job_id", - "context", - "llm_model" -]New value: +[ + "job_id" +]
- Changed
record_screen4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "guide_id", - "chat_id", - "preceding_clip_id", - "scenes", - "context", - "llm_model" -]New value: +[ + "guide_id", + "chat_id", + "preceding_clip_id", + "scenes" +]
- Changed
remove_clip4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "clip_index", - "context", - "llm_model" -]New value: +[ + "project_id", + "clip_index" +]
- Changed
remove_elements4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "removals", - "context", - "llm_model" -]New value: +[ + "project_id", + "removals" +]
- Changed
remove_from_project4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "target", - "context", - "llm_model" -]New value: +[ + "project_id", + "target" +]
- Changed
reorder_elements4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "clip_index", - "ordered_element_ids", - "context", - "llm_model" -]New value: +[ + "project_id", + "clip_index", + "ordered_element_ids" +]
- Changed
run_script4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "code", - "context", - "llm_model" -]New value: +[ + "code" +]
- Changed
set_voice4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "voice_name", - "voice_engine", - "context", - "llm_model" -]New value: +[ + "project_id", + "voice_name", + "voice_engine" +]
- Changed
split_clip4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "clip_index", - "split_time", - "context", - "llm_model" -]New value: +[ + "project_id", + "clip_index", + "split_time" +]
- Changed
switch_workspace4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "workspaceId", - "context", - "llm_model" -]New value: +[ + "workspaceId" +]
- Changed
update_article4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "markdown", - "context", - "llm_model" -]New value: +[ + "project_id", + "markdown" +]
- Changed
update_article_media4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "screenshot_id", - "context", - "llm_model" -]New value: +[ + "project_id", + "screenshot_id" +]
- Changed
update_audio4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "music_id", - "context", - "llm_model" -]New value: +[ + "project_id", + "music_id" +]
- Changed
update_clips4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "updates", - "context", - "llm_model" -]New value: +[ + "project_id", + "updates" +]
- Changed
update_clueprint4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "clueprint_id", - "context", - "llm_model" -]New value: +[ + "clueprint_id" +]
- Changed
update_elements4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "updates", - "context", - "llm_model" -]New value: +[ + "project_id", + "updates" +]
- Changed
update_groups4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "items", - "context", - "llm_model" -]New value: +[ + "project_id", + "items" +]
- Changed
update_project4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "context", - "llm_model" -]New value: +[ + "project_id" +]
- Changed
upload_file4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - removed
Input schema / requiredRemoved value: -[ - "context", - "llm_model" -]
- Changed
voiceover_batch4 fields changed- removed
Input schema / properties / contextRemoved value: -{ - "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", - "type": "string" -} - removed
Input schema / properties / conversation_idRemoved value: -{ - "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", - "type": "string" -} - removed
Input schema / properties / llm_modelRemoved value: -{ - "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", - "type": "string" -} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "entries", - "context", - "llm_model" -]New value: +[ + "project_id", + "entries" +]
44 tool updates
- Changed
add_article_media4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "kind", - "project_id" -]New value: +[ + "kind", + "project_id", + "context", + "llm_model" +]
- Changed
add_audio4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "type" -]New value: +[ + "project_id", + "type", + "context", + "llm_model" +]
- Changed
add_clips4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "kind", - "project_id" -]New value: +[ + "kind", + "project_id", + "context", + "llm_model" +]
- Changed
add_comment4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "comment_text" -]New value: +[ + "project_id", + "comment_text", + "context", + "llm_model" +]
- Changed
add_elements4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "elements" -]New value: +[ + "project_id", + "elements", + "context", + "llm_model" +]
- Changed
add_sync_point4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "word", - "timestamp_seconds" -]New value: +[ + "project_id", + "word", + "timestamp_seconds", + "context", + "llm_model" +]
- Changed
analyze_audio4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "mode" -]New value: +[ + "mode", + "context", + "llm_model" +]
- Changed
auto_sync4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "clip_id" -]New value: +[ + "project_id", + "clip_id", + "context", + "llm_model" +]
- Changed
check_uploads4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "upload_token" -]New value: +[ + "upload_token", + "context", + "llm_model" +]
- Changed
create_clueprint4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "name", - "visibility" -]New value: +[ + "name", + "visibility", + "context", + "llm_model" +]
- Changed
create_project4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - added
Input schema / requiredAdded value: +[ + "context", + "llm_model" +]
- Changed
duplicate_clip4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "target_project_id", - "source_clip_id" -]New value: +[ + "target_project_id", + "source_clip_id", + "context", + "llm_model" +]
- Changed
duplicate_project4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "source_project_id" -]New value: +[ + "source_project_id", + "context", + "llm_model" +]
- Changed
estimate_duration4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "texts" -]New value: +[ + "texts", + "context", + "llm_model" +]
- Changed
export_project4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id" -]New value: +[ + "project_id", + "context", + "llm_model" +]
- Changed
find4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "type" -]New value: +[ + "type", + "context", + "llm_model" +]
- Changed
generate_media4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "kind", - "project_id", - "clip_id", - "prompt", - "x", - "y", - "width", - "height" -]New value: +[ + "kind", + "project_id", + "clip_id", + "prompt", + "x", + "y", + "width", + "height", + "context", + "llm_model" +]
- Changed
get_article4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id" -]New value: +[ + "project_id", + "context", + "llm_model" +]
- Changed
get_clip4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "clip_index" -]New value: +[ + "project_id", + "clip_index", + "context", + "llm_model" +]
- Changed
get_clueprint4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "clueprint_id" -]New value: +[ + "clueprint_id", + "context", + "llm_model" +]
- Changed
get_comments4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id" -]New value: +[ + "project_id", + "context", + "llm_model" +]
- Changed
get_design_guide4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - added
Input schema / requiredAdded value: +[ + "context", + "llm_model" +]
- Changed
get_element_schema4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "element_type" -]New value: +[ + "element_type", + "context", + "llm_model" +]
- Changed
get_project4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id" -]New value: +[ + "project_id", + "context", + "llm_model" +]
- Changed
get_script_job4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "job_id" -]New value: +[ + "job_id", + "context", + "llm_model" +]
- Changed
record_screen4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "guide_id", - "chat_id", - "preceding_clip_id", - "scenes" -]New value: +[ + "guide_id", + "chat_id", + "preceding_clip_id", + "scenes", + "context", + "llm_model" +]
- Changed
remove_clip4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "clip_index" -]New value: +[ + "project_id", + "clip_index", + "context", + "llm_model" +]
- Changed
remove_elements4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "removals" -]New value: +[ + "project_id", + "removals", + "context", + "llm_model" +]
- Changed
remove_from_project4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "target" -]New value: +[ + "project_id", + "target", + "context", + "llm_model" +]
- Changed
reorder_elements4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "clip_index", - "ordered_element_ids" -]New value: +[ + "project_id", + "clip_index", + "ordered_element_ids", + "context", + "llm_model" +]
- Changed
run_script4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "code" -]New value: +[ + "code", + "context", + "llm_model" +]
- Changed
set_voice4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "voice_name", - "voice_engine" -]New value: +[ + "project_id", + "voice_name", + "voice_engine", + "context", + "llm_model" +]
- Changed
split_clip4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "clip_index", - "split_time" -]New value: +[ + "project_id", + "clip_index", + "split_time", + "context", + "llm_model" +]
- Changed
switch_workspace4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "workspaceId" -]New value: +[ + "workspaceId", + "context", + "llm_model" +]
- Changed
update_article4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "markdown" -]New value: +[ + "project_id", + "markdown", + "context", + "llm_model" +]
- Changed
update_article_media4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "screenshot_id" -]New value: +[ + "project_id", + "screenshot_id", + "context", + "llm_model" +]
- Changed
update_audio4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "music_id" -]New value: +[ + "project_id", + "music_id", + "context", + "llm_model" +]
- Changed
update_clips4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "updates" -]New value: +[ + "project_id", + "updates", + "context", + "llm_model" +]
- Changed
update_clueprint4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "clueprint_id" -]New value: +[ + "clueprint_id", + "context", + "llm_model" +]
- Changed
update_elements4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "updates" -]New value: +[ + "project_id", + "updates", + "context", + "llm_model" +]
- Changed
update_groups4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "items" -]New value: +[ + "project_id", + "items", + "context", + "llm_model" +]
- Changed
update_project4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id" -]New value: +[ + "project_id", + "context", + "llm_model" +]
- Changed
upload_file4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - added
Input schema / requiredAdded value: +[ + "context", + "llm_model" +]
- Changed
voiceover_batch4 fields changed- added
Input schema / properties / contextAdded value: +{ + "description": "Explain in 15-25 words, in third person, why this tool is called and how it supports the user's goal. For analytics only. You MUST describe only the abstract purpose of the tool call. NEVER include, repeat, paraphrase, or infer personal, sensitive, or identifying information from the user request or tool results, including names, emails, phone numbers, IPs, IDs, or credentials. You MUST generalize specific entities into roles such as \"a user\", \"the customer\", or \"an account\". Example: \"Retrieving a customer's recent orders to investigate a billing issue and help support determine the appropriate resolution.\"", + "type": "string" +} - added
Input schema / properties / conversation_idAdded value: +{ + "description": "Echo the conversation_id from the server's previous response. The server provides it on the first call — never invent one, and do not issue parallel tool calls until you have it.", + "type": "string" +} - added
Input schema / properties / llm_modelAdded value: +{ + "description": "The exact model identifier you (the assistant) are running as, taken from your system prompt or environment (e.g. \"claude-opus-4-8\", \"gpt-5.2\"). Used for analytics only. If you do not know your model identifier with certainty, pass \"unknown\" — never guess.", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "project_id", - "entries" -]New value: +[ + "project_id", + "entries", + "context", + "llm_model" +]
44 tool updates
- Changed
add_article_media2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
add_audio2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
add_clips7 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / clips / items / additionalPropertiesRemoved value: -false - added
Input schema / properties / clips / items / properties / background / propertyNamesAdded value: +{ + "type": "string" +} - removed
Input schema / properties / clips / items / properties / transition / additionalPropertiesRemoved value: -false - removed
Input schema / properties / cuts / items / additionalPropertiesRemoved value: -false - added
Input schema / properties / slide_indices / items / maximumAdded value: +9007199254740991
- Changed
add_comment3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / parent_comment_idAdded value: +{ + "description": "Reply to this comment instead of starting a new thread. Take the id from get_comments. Replying is how you answer feedback you have acted on — the clip pin and timestamp come from the parent, so leave clip_id/clip_timestamp off.", + "type": "string" +}
- Changed
add_elements14 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / defaults / properties / clip_index / maximumAdded value: +9007199254740991 - changed
Input schema / properties / defaults / properties / keyframes / anyOfPrevious value: -[ - { - "items": { - "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items" - }, - "type": "array" - }, - { - "type": "null" - } -]New value: +[ + { + "items": { + "additionalProperties": false, + "properties": { + "backgroundBlur": { + "description": "Backdrop blur behind the element", + "type": "number" + }, + "bezier": { + "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "bezier_overrides": { + "additionalProperties": { + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "required": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "object" + }, + "blur": { + "description": "Layer blur", + "type": "number" + }, + "borderRadiusBottomLeft": { + "description": "borderRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "borderRadiusBottomRight": { + "description": "borderRadiusBottomRight in canvas pixels", + "type": "number" + }, + "borderRadiusTopLeft": { + "description": "borderRadiusTopLeft in canvas pixels", + "type": "number" + }, + "borderRadiusTopRight": { + "description": "borderRadiusTopRight in canvas pixels", + "type": "number" + }, + "cropHeight": { + "description": "cropHeight (native unit)", + "type": "number" + }, + "cropWidth": { + "description": "cropWidth (native unit)", + "type": "number" + }, + "cropX": { + "description": "cropX (native unit)", + "type": "number" + }, + "cropY": { + "description": "cropY (native unit)", + "type": "number" + }, + "fillColor": { + "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "fontSize": { + "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", + "type": "number" + }, + "height": { + "description": "Height in canvas pixels (0 allowed)", + "minimum": 0, + "type": "number" + }, + "imageBorderColor": { + "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "imageBorderWidth": { + "description": "imageBorderWidth in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomLeft": { + "description": "imageCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomRight": { + "description": "imageCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopLeft": { + "description": "imageCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopRight": { + "description": "imageCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "interpolation": { + "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "interpolation_overrides": { + "additionalProperties": { + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "required": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "object" + }, + "letterSpacing": { + "description": "Letter spacing in canvas pixels.", + "type": "number" + }, + "lineHeight": { + "description": "lineHeight (native unit)", + "type": "number" + }, + "opacity": { + "description": "Opacity 0-100", + "maximum": 100, + "minimum": 0, + "type": "number" + }, + "paddingBottom": { + "description": "paddingBottom in canvas pixels", + "type": "number" + }, + "paddingLeft": { + "description": "paddingLeft in canvas pixels", + "type": "number" + }, + "paddingRight": { + "description": "paddingRight in canvas pixels", + "type": "number" + }, + "paddingTop": { + "description": "paddingTop in canvas pixels", + "type": "number" + }, + "positionX": { + "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", + "type": "number" + }, + "positionY": { + "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", + "type": "number" + }, + "rotateX": { + "description": "rotateX (native unit)", + "type": "number" + }, + "rotateY": { + "description": "rotateY (native unit)", + "type": "number" + }, + "rotation": { + "description": "Rotation in degrees", + "type": "number" + }, + "scaleX": { + "description": "Horizontal scale multiplier (1 = 100%)", + "type": "number" + }, + "scaleY": { + "description": "Vertical scale multiplier (1 = 100%)", + "type": "number" + }, + "shadowBlur": { + "description": "shadowBlur in canvas pixels", + "type": "number" + }, + "shadowColor": { + "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "shadowOffsetX": { + "description": "shadowOffsetX in canvas pixels", + "type": "number" + }, + "shadowOffsetY": { + "description": "shadowOffsetY in canvas pixels", + "type": "number" + }, + "shadowSpread": { + "description": "shadowSpread in canvas pixels", + "type": "number" + }, + "strokeColor": { + "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "strokeDash": { + "description": "strokeDash in canvas pixels", + "type": "number" + }, + "strokeGap": { + "description": "strokeGap in canvas pixels", + "type": "number" + }, + "strokeTrimEnd": { + "description": "strokeTrimEnd (native unit)", + "type": "number" + }, + "strokeTrimOffset": { + "description": "strokeTrimOffset (native unit)", + "type": "number" + }, + "strokeTrimStart": { + "description": "strokeTrimStart (native unit)", + "type": "number" + }, + "strokeWidth": { + "description": "strokeWidth in canvas pixels", + "type": "number" + }, + "textBackgroundColor": { + "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textBgRadiusBottomLeft": { + "description": "textBgRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusBottomRight": { + "description": "textBgRadiusBottomRight in canvas pixels", + "type": "number" + }, + "textBgRadiusTopLeft": { + "description": "textBgRadiusTopLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusTopRight": { + "description": "textBgRadiusTopRight in canvas pixels", + "type": "number" + }, + "textColor": { + "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeColor": { + "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeDash": { + "description": "textStrokeDash in canvas pixels", + "type": "number" + }, + "textStrokeGap": { + "description": "textStrokeGap in canvas pixels", + "type": "number" + }, + "textStrokeWidth": { + "description": "textStrokeWidth in canvas pixels", + "type": "number" + }, + "timestamp": { + "description": "Clip-relative time in seconds", + "minimum": 0, + "type": "number" + }, + "videoCornerRadiusBottomLeft": { + "description": "videoCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusBottomRight": { + "description": "videoCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopLeft": { + "description": "videoCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopRight": { + "description": "videoCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "width": { + "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } +] - added
Input schema / properties / defaults / properties / type_data / propertyNamesAdded value: +{ + "type": "string" +} - added
Input schema / properties / elements / items / properties / clip_index / maximumAdded value: +9007199254740991 - changed
Input schema / properties / elements / items / properties / insert_at / descriptionPrevious value: -"Where the element lands in z-order, so you don't need a follow-up reorder_elements. `front` (default) puts it on top of what's already on the clip; `back` puts it behind everything — what a backdrop panel or a wash needs. `{before: element_id}` / `{after: element_id}` place it next to a specific element or group and put it in THAT node's group, which is the only way to position inside a group. Placement is relative to the clip AS IT STANDS when the item is applied, so several `back` items in one call end up in REVERSE input order: send one backdrop per call, or list them back-to-front."New value: +"Where the element lands in z-order, so you don't need a follow-up reorder_elements. `front` (default) puts it on top of what's already on the clip; `back` puts it behind everything — what a backdrop panel or a wash needs. `{before: element_id}` / `{after: element_id}` place it next to a specific element or group and put it in THAT node's group, which is the only way to position inside a group. Passing `group` as well changes what `front`/`back` address — see the Z-order notes in this tool's description. Placement is relative to the clip AS IT STANDS when the item is applied, so several `back` items in one call end up in REVERSE input order: send one backdrop per call, or list them back-to-front." - changed
Input schema / properties / elements / items / properties / keyframes / anyOfPrevious value: -[ - { - "items": { - "additionalProperties": false, - "properties": { - "backgroundBlur": { - "description": "Backdrop blur behind the element", - "type": "number" - }, - "bezier": { - "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "bezier_overrides": { - "additionalProperties": { - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ] - }, - "type": "object" - }, - "blur": { - "description": "Layer blur", - "type": "number" - }, - "borderRadiusBottomLeft": { - "description": "borderRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "borderRadiusBottomRight": { - "description": "borderRadiusBottomRight in canvas pixels", - "type": "number" - }, - "borderRadiusTopLeft": { - "description": "borderRadiusTopLeft in canvas pixels", - "type": "number" - }, - "borderRadiusTopRight": { - "description": "borderRadiusTopRight in canvas pixels", - "type": "number" - }, - "cropHeight": { - "description": "cropHeight (native unit)", - "type": "number" - }, - "cropWidth": { - "description": "cropWidth (native unit)", - "type": "number" - }, - "cropX": { - "description": "cropX (native unit)", - "type": "number" - }, - "cropY": { - "description": "cropY (native unit)", - "type": "number" - }, - "fillColor": { - "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "fontSize": { - "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", - "type": "number" - }, - "height": { - "description": "Height in canvas pixels (0 allowed)", - "minimum": 0, - "type": "number" - }, - "imageBorderColor": { - "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "imageBorderWidth": { - "description": "imageBorderWidth in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomLeft": { - "description": "imageCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomRight": { - "description": "imageCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopLeft": { - "description": "imageCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopRight": { - "description": "imageCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "interpolation": { - "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "interpolation_overrides": { - "additionalProperties": { - "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/interpolation" - }, - "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ] - }, - "type": "object" - }, - "letterSpacing": { - "description": "Letter spacing in canvas pixels.", - "type": "number" - }, - "lineHeight": { - "description": "lineHeight (native unit)", - "type": "number" - }, - "opacity": { - "description": "Opacity 0-100", - "maximum": 100, - "minimum": 0, - "type": "number" - }, - "paddingBottom": { - "description": "paddingBottom in canvas pixels", - "type": "number" - }, - "paddingLeft": { - "description": "paddingLeft in canvas pixels", - "type": "number" - }, - "paddingRight": { - "description": "paddingRight in canvas pixels", - "type": "number" - }, - "paddingTop": { - "description": "paddingTop in canvas pixels", - "type": "number" - }, - "positionX": { - "description": "X position in canvas pixels (NOT `x`). Uses the SAME alignment-aware origin as the element's top-level x — left-aligned text uses top-left, center-aligned uses CENTER POINT, right-aligned uses top-right; all other types use top-left.", - "type": "number" - }, - "positionY": { - "description": "Y position in canvas pixels (NOT `y`). Origin matches positionX — center-aligned text positions by vertical center. y_anchor applies to the element's own y, not to keyframe values — keyframes use the alignment origin, so read the element back and key off its stored y.", - "type": "number" - }, - "rotateX": { - "description": "rotateX (native unit)", - "type": "number" - }, - "rotateY": { - "description": "rotateY (native unit)", - "type": "number" - }, - "rotation": { - "description": "Rotation in degrees", - "type": "number" - }, - "scaleX": { - "description": "Horizontal scale multiplier (1 = 100%)", - "type": "number" - }, - "scaleY": { - "description": "Vertical scale multiplier (1 = 100%)", - "type": "number" - }, - "shadowBlur": { - "description": "shadowBlur in canvas pixels", - "type": "number" - }, - "shadowColor": { - "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "shadowOffsetX": { - "description": "shadowOffsetX in canvas pixels", - "type": "number" - }, - "shadowOffsetY": { - "description": "shadowOffsetY in canvas pixels", - "type": "number" - }, - "shadowSpread": { - "description": "shadowSpread in canvas pixels", - "type": "number" - }, - "strokeColor": { - "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "strokeDash": { - "description": "strokeDash in canvas pixels", - "type": "number" - }, - "strokeGap": { - "description": "strokeGap in canvas pixels", - "type": "number" - }, - "strokeTrimEnd": { - "description": "strokeTrimEnd (native unit)", - "type": "number" - }, - "strokeTrimOffset": { - "description": "strokeTrimOffset (native unit)", - "type": "number" - }, - "strokeTrimStart": { - "description": "strokeTrimStart (native unit)", - "type": "number" - }, - "strokeWidth": { - "description": "strokeWidth in canvas pixels", - "type": "number" - }, - "textBackgroundColor": { - "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textBgRadiusBottomLeft": { - "description": "textBgRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusBottomRight": { - "description": "textBgRadiusBottomRight in canvas pixels", - "type": "number" - }, - "textBgRadiusTopLeft": { - "description": "textBgRadiusTopLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusTopRight": { - "description": "textBgRadiusTopRight in canvas pixels", - "type": "number" - }, - "textColor": { - "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textStrokeColor": { - "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textStrokeDash": { - "description": "textStrokeDash in canvas pixels", - "type": "number" - }, - "textStrokeGap": { - "description": "textStrokeGap in canvas pixels", - "type": "number" - }, - "textStrokeWidth": { - "description": "textStrokeWidth in canvas pixels", - "type": "number" - }, - "timestamp": { - "description": "Clip-relative time in seconds", - "minimum": 0, - "type": "number" - }, - "videoCornerRadiusBottomLeft": { - "description": "videoCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusBottomRight": { - "description": "videoCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopLeft": { - "description": "videoCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopRight": { - "description": "videoCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "width": { - "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", - "minimum": 0, - "type": "number" - } - }, - "required": [ - "timestamp" - ], - "type": "object" - }, - "type": "array" - }, - { - "type": "null" - } -]New value: +[ + { + "items": { + "additionalProperties": false, + "properties": { + "backgroundBlur": { + "description": "Backdrop blur behind the element", + "type": "number" + }, + "bezier": { + "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "bezier_overrides": { + "additionalProperties": { + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "required": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "object" + }, + "blur": { + "description": "Layer blur", + "type": "number" + }, + "borderRadiusBottomLeft": { + "description": "borderRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "borderRadiusBottomRight": { + "description": "borderRadiusBottomRight in canvas pixels", + "type": "number" + }, + "borderRadiusTopLeft": { + "description": "borderRadiusTopLeft in canvas pixels", + "type": "number" + }, + "borderRadiusTopRight": { + "description": "borderRadiusTopRight in canvas pixels", + "type": "number" + }, + "cropHeight": { + "description": "cropHeight (native unit)", + "type": "number" + }, + "cropWidth": { + "description": "cropWidth (native unit)", + "type": "number" + }, + "cropX": { + "description": "cropX (native unit)", + "type": "number" + }, + "cropY": { + "description": "cropY (native unit)", + "type": "number" + }, + "fillColor": { + "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "fontSize": { + "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", + "type": "number" + }, + "height": { + "description": "Height in canvas pixels (0 allowed)", + "minimum": 0, + "type": "number" + }, + "imageBorderColor": { + "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "imageBorderWidth": { + "description": "imageBorderWidth in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomLeft": { + "description": "imageCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomRight": { + "description": "imageCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopLeft": { + "description": "imageCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopRight": { + "description": "imageCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "interpolation": { + "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "interpolation_overrides": { + "additionalProperties": { + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "required": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "object" + }, + "letterSpacing": { + "description": "Letter spacing in canvas pixels.", + "type": "number" + }, + "lineHeight": { + "description": "lineHeight (native unit)", + "type": "number" + }, + "opacity": { + "description": "Opacity 0-100", + "maximum": 100, + "minimum": 0, + "type": "number" + }, + "paddingBottom": { + "description": "paddingBottom in canvas pixels", + "type": "number" + }, + "paddingLeft": { + "description": "paddingLeft in canvas pixels", + "type": "number" + }, + "paddingRight": { + "description": "paddingRight in canvas pixels", + "type": "number" + }, + "paddingTop": { + "description": "paddingTop in canvas pixels", + "type": "number" + }, + "positionX": { + "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", + "type": "number" + }, + "positionY": { + "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", + "type": "number" + }, + "rotateX": { + "description": "rotateX (native unit)", + "type": "number" + }, + "rotateY": { + "description": "rotateY (native unit)", + "type": "number" + }, + "rotation": { + "description": "Rotation in degrees", + "type": "number" + }, + "scaleX": { + "description": "Horizontal scale multiplier (1 = 100%)", + "type": "number" + }, + "scaleY": { + "description": "Vertical scale multiplier (1 = 100%)", + "type": "number" + }, + "shadowBlur": { + "description": "shadowBlur in canvas pixels", + "type": "number" + }, + "shadowColor": { + "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "shadowOffsetX": { + "description": "shadowOffsetX in canvas pixels", + "type": "number" + }, + "shadowOffsetY": { + "description": "shadowOffsetY in canvas pixels", + "type": "number" + }, + "shadowSpread": { + "description": "shadowSpread in canvas pixels", + "type": "number" + }, + "strokeColor": { + "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "strokeDash": { + "description": "strokeDash in canvas pixels", + "type": "number" + }, + "strokeGap": { + "description": "strokeGap in canvas pixels", + "type": "number" + }, + "strokeTrimEnd": { + "description": "strokeTrimEnd (native unit)", + "type": "number" + }, + "strokeTrimOffset": { + "description": "strokeTrimOffset (native unit)", + "type": "number" + }, + "strokeTrimStart": { + "description": "strokeTrimStart (native unit)", + "type": "number" + }, + "strokeWidth": { + "description": "strokeWidth in canvas pixels", + "type": "number" + }, + "textBackgroundColor": { + "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textBgRadiusBottomLeft": { + "description": "textBgRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusBottomRight": { + "description": "textBgRadiusBottomRight in canvas pixels", + "type": "number" + }, + "textBgRadiusTopLeft": { + "description": "textBgRadiusTopLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusTopRight": { + "description": "textBgRadiusTopRight in canvas pixels", + "type": "number" + }, + "textColor": { + "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeColor": { + "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeDash": { + "description": "textStrokeDash in canvas pixels", + "type": "number" + }, + "textStrokeGap": { + "description": "textStrokeGap in canvas pixels", + "type": "number" + }, + "textStrokeWidth": { + "description": "textStrokeWidth in canvas pixels", + "type": "number" + }, + "timestamp": { + "description": "Clip-relative time in seconds", + "minimum": 0, + "type": "number" + }, + "videoCornerRadiusBottomLeft": { + "description": "videoCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusBottomRight": { + "description": "videoCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopLeft": { + "description": "videoCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopRight": { + "description": "videoCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "width": { + "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } +] - added
Input schema / properties / elements / items / properties / keyframes_repeat / properties / count / maximumAdded value: +9007199254740991 - added
Input schema / properties / elements / items / properties / type_data / propertyNamesAdded value: +{ + "type": "string" +} - changed
Input schema / properties / elements / items / properties / x / descriptionPrevious value: -"X position in canvas pixels. ORIGIN is alignment-dependent: TEXT only — left-aligned uses top-left, center-aligned uses CENTER POINT, right-aligned uses top-right. All other element types (callout, rectangle, arrow, blur, spotlight, image, animation) use top-left. For zoom, use type_data.centerX instead."New value: +"X position in canvas pixels. `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right (callout, rectangle, arrow, blur, spotlight, image and animation all use the left edge). For zoom, use type_data.centerX instead." - changed
Input schema / properties / elements / items / properties / y / descriptionPrevious value: -"Y position in canvas pixels. Which part of the element this refers to is set by type_data.y_anchor for text (top / center / bottom). To sit a label on a row, pill, chip, card or beside an icon, pass that container's centre line here with y_anchor:'center'."New value: +"Y position in canvas pixels — for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. Pair it with y_anchor (below), always." - added
Input schema / properties / elements / items / properties / y_anchorAdded value: +{ + "description": "TEXT only. ALWAYS send `y_anchor` ('top'|'center'|'bottom') when you set `y` on text, so the position states what you meant instead of inheriting the alignment origin. To centre in a row, pill, chip, card or button: pass the container's centre line as `y` with y_anchor:'center'. The server centres the MEASURED box — you cannot compute that height, since wrapping and `fit` change it. A write-time DIRECTIVE: never stored, never returned by a read, so send it on every call whose `y` means the same thing. (Also accepted inside type_data — older spelling; this one wins.)", + "enum": [ + "top", + "center", + "bottom" + ], + "type": "string" +} - changed
Input schema / properties / returning / descriptionPrevious value: -"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."New value: +"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."
- Changed
add_sync_point4 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / clip_index / maximumAdded value: +9007199254740991 - added
Input schema / properties / occurrence / maximumAdded value: +9007199254740991
- Changed
analyze_audio7 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / range_end_ms / maximumAdded value: +9007199254740991 - added
Input schema / properties / range_start_ms / maximumAdded value: +9007199254740991 - removed
Input schema / properties / silences_options / additionalPropertiesRemoved value: -false - added
Input schema / properties / silences_options / properties / min_pause_ms / maximumAdded value: +9007199254740991 - removed
Input schema / properties / transcript_options / additionalPropertiesRemoved value: -false
- Changed
auto_sync2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
check_uploads2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
create_clueprint2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
create_project2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
duplicate_clip2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
duplicate_project2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
estimate_duration2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
export_project5 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / fps / anyOfAdded value: +[ + { + "const": 24, + "type": "number" + }, + { + "const": 30, + "type": "number" + }, + { + "const": 60, + "type": "number" + } +] - removed
Input schema / properties / fps / enumRemoved value: -[ - 24, - 30, - 60 -] - removed
Input schema / properties / fps / typeRemoved value: -"number"
- Changed
find5 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / max_duration / maximumAdded value: +9007199254740991 - added
Input schema / properties / min_duration / maximumAdded value: +9007199254740991 - added
Input schema / properties / page / maximumAdded value: +9007199254740991
- Changed
generate_media5 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / animation_settingAdded value: +{ + "description": "Image only. Entry/exit animation, same shape as add_elements' type_data.animation_setting. The design guide asks AI images to enter with `masked_reveal` or a slow fade, so set it here rather than following up with update_elements — that follow-up targets the element while it is still generating. Ignored for kind='animation', which animates through its generated code.", + "properties": { + "entry": { + "description": "Entry (appear) animation phase.", + "properties": { + "apply_to_unit": { + "description": "Granularity. 'typewriter' is restricted to 'char'.", + "enum": [ + "char", + "word", + "line", + "box" + ], + "type": "string" + }, + "direction": { + "description": "Slide direction for this phase. Ignored by fade/scale/pop/typewriter; pass 'none' when the preset has no direction.", + "enum": [ + "left", + "right", + "top", + "bottom", + "center_all", + "center_vertically", + "center_horizontally", + "none" + ], + "type": "string" + }, + "duration_per_unit_ms": { + "description": "NAME IS MISLEADING — this is the TOTAL duration of the phase in ms (NOT per unit). The renderer splits it across all N units with ~50% overlap. For a perceptible per-unit rhythm scale UP with the unit count (e.g. typewriter on N chars ≈ N × 100–200 ms). For applyToUnit='box' it's just the phase duration. Omit it and you get 400ms, the same default the editor creates with.", + "exclusiveMinimum": 0, + "type": "number" + }, + "preset": { + "description": "Preset for this phase. 'typewriter' is char-only and has no direction.", + "enum": [ + "slide", + "fade", + "pop", + "scale", + "masked_reveal", + "typewriter", + "none" + ], + "type": "string" + } + }, + "type": "object" + }, + "exit": { + "description": "Exit (disappear) animation phase.", + "properties": { + "apply_to_unit": { + "description": "Granularity. 'typewriter' is restricted to 'char'.", + "enum": [ + "char", + "word", + "line", + "box" + ], + "type": "string" + }, + "direction": { + "description": "Slide direction for this phase. Ignored by fade/scale/pop/typewriter; pass 'none' when the preset has no direction.", + "enum": [ + "left", + "right", + "top", + "bottom", + "center_all", + "center_vertically", + "center_horizontally", + "none" + ], + "type": "string" + }, + "duration_per_unit_ms": { + "description": "NAME IS MISLEADING — this is the TOTAL duration of the phase in ms (NOT per unit). The renderer splits it across all N units with ~50% overlap. For a perceptible per-unit rhythm scale UP with the unit count (e.g. typewriter on N chars ≈ N × 100–200 ms). For applyToUnit='box' it's just the phase duration. Omit it and you get 400ms, the same default the editor creates with.", + "exclusiveMinimum": 0, + "type": "number" + }, + "preset": { + "description": "Preset for this phase. 'typewriter' is char-only and has no direction.", + "enum": [ + "slide", + "fade", + "pop", + "scale", + "masked_reveal", + "typewriter", + "none" + ], + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" +} - added
Input schema / properties / backgroundAdded value: +{ + "anyOf": [ + { + "type": "boolean" + }, + { + "enum": [ + "0", + "1", + "true", + "false", + "yes", + "no" + ], + "type": "string" + } + ], + "description": "Image only, and only honoured by `gpt-image-2.5-flare`, `gpt-image-2.5-sunburst`, `gpt-image-1` and `gpt-image-1.5` — every other model is always opaque and ignores this. Pass `false` for a cut-out with no background: icons, logos, stickers, anything meant to sit ON the composition rather than behind it. You MUST set `model` to one of those four in the same call; `gpt-image-2.5-flare` is the one to default to, since the older pair cannot frame wide." +} - added
Input schema / properties / modelAdded value: +{ + "description": "Image only. Which image model renders it. Default `gemini-3-pro-image-preview` (Nano Banana Pro), a strong general choice — leave it off unless you want one of the specifics below. `gemini-3.1-flash-image-preview` (Nano Banana 2) and `gemini-2.5-flash-image` are faster and cheaper. `gpt-image-2.5-flare` is OpenAI's fast one, `gpt-image-2.5-sunburst` its most precise editor, and `gpt-image-2` is the one to reach for when the image must carry legible text or follow several reference images. `gpt-image-1` / `gpt-image-1.5` are the older pair and only accept square-ish framing — a wide box is snapped to 4:3 rather than honoured, so do not pick them for a banner. An unlisted value is rejected here rather than silently swapped for the default, which is what the backend does with one.", + "enum": [ + "gemini-3-pro-image-preview", + "gemini-3.1-flash-image-preview", + "gemini-2.5-flash-image", + "gpt-image-2.5-flare", + "gpt-image-2.5-sunburst", + "gpt-image-2", + "gpt-image-1.5", + "gpt-image-1" + ], + "type": "string" +}
- Changed
get_article2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
get_clip5 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / clip_index / maximumAdded value: +9007199254740991 - changed
Input schema / properties / select / descriptionPrevious value: -"Ask for exactly the JSON you want, GraphQL-style. Omit for everything; pass [] for none.\n Sections: 'elements' (whole element rows), 'voiceover_words' (per-word VO timings; returns the key of the same name, holding `{word, start, end, punctuated_word}` with start/end in SECONDS — null on a clip with no transcription), 'groups' (group rows: id, name, parent_id, bounds_px, anchor_px, keyframes). Each section returns the key it is named after. Rendering is `render`, not a value here.\n Per-key: 'elements.<key>' projects element rows to just those keys (id is always kept). Keys: name, element_type, x, y, width, height, start_time, end_time, rotation, keyframes, textdata, shapedata, imagedata, videodata, zoomdata, codedata, parent_id.\n Examples: ['elements.x','elements.y','elements.width','elements.height'] to read geometry; ['elements.name','elements.start_time','elements.end_time'] for a timing pass; ['voiceover_words'] to sync visuals to narration; ['groups'] to resolve a group id for update_groups; [] with render:{} returns the PNG with no JSON (smallest read); ['elements.textdata','voiceover_words'] to rewrite copy against the VO.\n Mixing 'elements' with 'elements.<key>' returns whole rows. Use element_ids to choose WHICH rows — that is independent of this."New value: +"Ask for exactly the JSON you want, GraphQL-style. Omit for everything; pass [] for none.\n Sections: 'elements' (whole element rows), 'voiceover_words' (per-word VO timings; returns the key of the same name, holding `{word, start, end, punctuated_word}` with start/end in SECONDS — null on a clip with no transcription), 'groups' (group rows: id, name, parent_id, bounds_px, anchor_px, keyframes), 'busy' (generations still writing to this clip, as `[{entity_path, job_type}]` — EMPTY means nothing is pending, which is how you know a voiceover or AI image has landed; it is the same lock that would refuse your write, so a non-empty list also tells you what not to touch yet). Each section returns the key it is named after. Rendering is `render`, not a value here.\n Per-key: 'elements.<key>' projects element rows to just those keys (id is always kept). Keys: name, element_type, x, y, width, height, start_time, end_time, rotation, keyframes, textdata, shapedata, imagedata, videodata, zoomdata, codedata, parent_id. y_top is text-only and present ONLY when alignment is 'center' — the unambiguous TOP edge, which is exactly the case where `y` is NOT the top but the vertical CENTRE. To put that position back, send it as `y` with y_anchor:'top'.\n Examples: ['elements.x','elements.y','elements.width','elements.height'] to read geometry; ['elements.name','elements.start_time','elements.end_time'] for a timing pass; ['voiceover_words'] to sync visuals to narration; ['groups'] to resolve a group id for update_groups; [] with render:{} returns the PNG with no JSON (smallest read); ['elements.textdata','voiceover_words'] to rewrite copy against the VO.\n Mixing 'elements' with 'elements.<key>' returns whole rows. Use element_ids to choose WHICH rows — that is independent of this." - changed
Input schema / properties / select / items / enumPrevious value: -[ - "elements", - "voiceover_words", - "groups", - "elements.name", - "elements.element_type", - "elements.x", - "elements.y", - "elements.width", - "elements.height", - "elements.start_time", - "elements.end_time", - "elements.rotation", - "elements.keyframes", - "elements.textdata", - "elements.shapedata", - "elements.imagedata", - "elements.videodata", - "elements.zoomdata", - "elements.codedata", - "elements.parent_id" -]New value: +[ + "elements", + "voiceover_words", + "groups", + "busy", + "elements.name", + "elements.element_type", + "elements.x", + "elements.y", + "elements.width", + "elements.height", + "elements.start_time", + "elements.end_time", + "elements.rotation", + "elements.keyframes", + "elements.textdata", + "elements.shapedata", + "elements.imagedata", + "elements.videodata", + "elements.zoomdata", + "elements.codedata", + "elements.parent_id" +]
- Changed
get_clueprint2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Added
get_comments - Changed
get_design_guide1 field changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
get_element_schema2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
get_project2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
get_script_job4 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / job_id / formatAdded value: +"uuid" - added
Input schema / properties / job_id / patternAdded value: +"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
- Changed
record_screen5 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / scenes / items / additionalPropertiesRemoved value: -false - removed
Input schema / properties / scenes / items / properties / entry / additionalPropertiesRemoved value: -false - removed
Input schema / properties / scenes / items / properties / exit / additionalPropertiesRemoved value: -false
- Changed
remove_clip3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / clip_index / maximumAdded value: +9007199254740991
- Changed
remove_elements3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / removals / items / properties / clip_index / maximumAdded value: +9007199254740991
- Changed
remove_from_project3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / clip_index / maximumAdded value: +9007199254740991
- Changed
reorder_elements3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / clip_index / maximumAdded value: +9007199254740991
- Changed
run_script2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
set_voice2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
split_clip3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / clip_index / maximumAdded value: +9007199254740991
- Changed
switch_workspace2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
update_article2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
update_article_media4 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / crop / propertyNamesAdded value: +{ + "type": "string" +} - added
Input schema / properties / shapes / items / propertyNamesAdded value: +{ + "type": "string" +}
- Changed
update_audio3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / loop / anyOfPrevious value: -[ - { - "type": "boolean" - }, - { - "enum": [ - "true", - "false", - "1", - "0", - "yes", - "no" - ], - "type": "string" - } -]New value: +[ + { + "type": "boolean" + }, + { + "enum": [ + "0", + "1", + "true", + "false", + "yes", + "no" + ], + "type": "string" + } +]
- Changed
update_clips11 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / updates / items / additionalPropertiesRemoved value: -false - added
Input schema / properties / updates / items / properties / background / propertyNamesAdded value: +{ + "type": "string" +} - added
Input schema / properties / updates / items / properties / clip_index / maximumAdded value: +9007199254740991 - changed
Input schema / properties / updates / items / properties / hidden / anyOfPrevious value: -[ - { - "type": "boolean" - }, - { - "enum": [ - "true", - "false", - "1", - "0", - "yes", - "no" - ], - "type": "string" - } -]New value: +[ + { + "type": "boolean" + }, + { + "enum": [ + "0", + "1", + "true", + "false", + "yes", + "no" + ], + "type": "string" + } +] - added
Input schema / properties / updates / items / properties / position / maximumAdded value: +9007199254740991 - changed
Input schema / properties / updates / items / properties / transition / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "color": { - "description": "Hex color, honoured by fadeToColor (default #000000), colorWipe (default #073cad) and rainbowWipe (default #D43F8C).", - "type": "string" - }, - "direction": { - "description": "Direction, honoured only by some types: rainbowWipe and cornerWipe take topLeft/topRight/bottomLeft/bottomRight (default topRight); colorWipe takes left or right (default right); stack and pushPull take left/right/top/bottom (default right). Ignored by dissolve, circleWipe and fadeToColor.", - "type": "string" - }, - "duration": { - "description": "Transition length in seconds.", - "exclusiveMinimum": 0, - "type": "number" - }, - "type": { - "description": "Transition style. NOTE: a clip's transition plays at the END of that clip, into the next one — to put a transition between clips 2 and 3, set it on clip 2.", - "enum": [ - "circleWipe", - "rainbowWipe", - "cornerWipe", - "stack", - "colorWipe", - "dissolve", - "pushPull", - "fadeToColor" - ], - "type": "string" - } - }, - "required": [ - "type", - "duration" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "properties": { + "color": { + "description": "Hex color, honoured by fadeToColor (default #000000), colorWipe (default #073cad) and rainbowWipe (default #D43F8C).", + "type": "string" + }, + "direction": { + "description": "Direction, honoured only by some types: rainbowWipe and cornerWipe take topLeft/topRight/bottomLeft/bottomRight (default topRight); colorWipe takes left or right (default right); stack and pushPull take left/right/top/bottom (default right). Ignored by dissolve, circleWipe and fadeToColor.", + "type": "string" + }, + "duration": { + "description": "Transition length in seconds.", + "exclusiveMinimum": 0, + "type": "number" + }, + "type": { + "description": "Transition style. NOTE: a clip's transition plays at the END of that clip, into the next one — to put a transition between clips 2 and 3, set it on clip 2.", + "enum": [ + "circleWipe", + "rainbowWipe", + "cornerWipe", + "stack", + "colorWipe", + "dissolve", + "pushPull", + "fadeToColor" + ], + "type": "string" + } + }, + "required": [ + "type", + "duration" + ], + "type": "object" + }, + { + "type": "null" + } +] - removed
Input schema / properties / updates / items / properties / video_styling / additionalPropertiesRemoved value: -false - changed
Input schema / properties / updates / items / properties / video_styling / properties / border / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "borderWidth": { - "description": "Border width in pixels.", - "minimum": 0, - "type": "number" - }, - "border_width": { - "description": "Snake-case alias for borderWidth. Border width in pixels.", - "minimum": 0, - "type": "number" - }, - "color": { - "description": "Border color hex (defaults to brand color).", - "type": "string" - }, - "type": { - "description": "Border style. 'none' = no border.", - "enum": [ - "none", - "solid", - "glass", - "animated", - "browser" - ], - "type": "string" - } - }, - "required": [ - "type" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "properties": { + "borderWidth": { + "description": "Border width in pixels.", + "minimum": 0, + "type": "number" + }, + "border_width": { + "description": "Snake-case alias for borderWidth. Border width in pixels.", + "minimum": 0, + "type": "number" + }, + "color": { + "description": "Border color hex (defaults to brand color).", + "type": "string" + }, + "type": { + "description": "Border style. 'none' = no border.", + "enum": [ + "none", + "solid", + "glass", + "animated", + "browser" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + { + "type": "null" + } +] - changed
Input schema / properties / updates / items / properties / video_styling / properties / crop / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "position": { - "description": "[left, top] as fractions of natural size (0–1).", - "items": { - "type": "number" - }, - "maxItems": 2, - "minItems": 2, - "type": "array" - }, - "size": { - "description": "[width, height] as fractions of natural size (0–1).", - "items": { - "type": "number" - }, - "maxItems": 2, - "minItems": 2, - "type": "array" - } - }, - "required": [ - "position", - "size" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "properties": { + "position": { + "description": "[left, top] as fractions of natural size (0–1).", + "items": { + "type": "number" + }, + "maxItems": 2, + "minItems": 2, + "type": "array" + }, + "size": { + "description": "[width, height] as fractions of natural size (0–1).", + "items": { + "type": "number" + }, + "maxItems": 2, + "minItems": 2, + "type": "array" + } + }, + "required": [ + "position", + "size" + ], + "type": "object" + }, + { + "type": "null" + } +]
- Changed
update_clueprint3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / files / items / additionalPropertiesRemoved value: -false
- Changed
update_elements15 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / defaults / properties / clip_index / maximumAdded value: +9007199254740991 - changed
Input schema / properties / defaults / properties / keyframes / anyOfPrevious value: -[ - { - "items": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items" - }, - "type": "array" - }, - { - "type": "null" - } -]New value: +[ + { + "items": { + "additionalProperties": false, + "properties": { + "backgroundBlur": { + "description": "Backdrop blur behind the element", + "type": "number" + }, + "bezier": { + "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "bezier_overrides": { + "additionalProperties": { + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "required": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "object" + }, + "blur": { + "description": "Layer blur", + "type": "number" + }, + "borderRadiusBottomLeft": { + "description": "borderRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "borderRadiusBottomRight": { + "description": "borderRadiusBottomRight in canvas pixels", + "type": "number" + }, + "borderRadiusTopLeft": { + "description": "borderRadiusTopLeft in canvas pixels", + "type": "number" + }, + "borderRadiusTopRight": { + "description": "borderRadiusTopRight in canvas pixels", + "type": "number" + }, + "cropHeight": { + "description": "cropHeight (native unit)", + "type": "number" + }, + "cropWidth": { + "description": "cropWidth (native unit)", + "type": "number" + }, + "cropX": { + "description": "cropX (native unit)", + "type": "number" + }, + "cropY": { + "description": "cropY (native unit)", + "type": "number" + }, + "fillColor": { + "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "fontSize": { + "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", + "type": "number" + }, + "height": { + "description": "Height in canvas pixels (0 allowed)", + "minimum": 0, + "type": "number" + }, + "imageBorderColor": { + "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "imageBorderWidth": { + "description": "imageBorderWidth in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomLeft": { + "description": "imageCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomRight": { + "description": "imageCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopLeft": { + "description": "imageCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopRight": { + "description": "imageCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "interpolation": { + "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "interpolation_overrides": { + "additionalProperties": { + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "required": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "object" + }, + "letterSpacing": { + "description": "Letter spacing in canvas pixels.", + "type": "number" + }, + "lineHeight": { + "description": "lineHeight (native unit)", + "type": "number" + }, + "opacity": { + "description": "Opacity 0-100", + "maximum": 100, + "minimum": 0, + "type": "number" + }, + "paddingBottom": { + "description": "paddingBottom in canvas pixels", + "type": "number" + }, + "paddingLeft": { + "description": "paddingLeft in canvas pixels", + "type": "number" + }, + "paddingRight": { + "description": "paddingRight in canvas pixels", + "type": "number" + }, + "paddingTop": { + "description": "paddingTop in canvas pixels", + "type": "number" + }, + "positionX": { + "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", + "type": "number" + }, + "positionY": { + "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", + "type": "number" + }, + "rotateX": { + "description": "rotateX (native unit)", + "type": "number" + }, + "rotateY": { + "description": "rotateY (native unit)", + "type": "number" + }, + "rotation": { + "description": "Rotation in degrees", + "type": "number" + }, + "scaleX": { + "description": "Horizontal scale multiplier (1 = 100%)", + "type": "number" + }, + "scaleY": { + "description": "Vertical scale multiplier (1 = 100%)", + "type": "number" + }, + "shadowBlur": { + "description": "shadowBlur in canvas pixels", + "type": "number" + }, + "shadowColor": { + "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "shadowOffsetX": { + "description": "shadowOffsetX in canvas pixels", + "type": "number" + }, + "shadowOffsetY": { + "description": "shadowOffsetY in canvas pixels", + "type": "number" + }, + "shadowSpread": { + "description": "shadowSpread in canvas pixels", + "type": "number" + }, + "strokeColor": { + "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "strokeDash": { + "description": "strokeDash in canvas pixels", + "type": "number" + }, + "strokeGap": { + "description": "strokeGap in canvas pixels", + "type": "number" + }, + "strokeTrimEnd": { + "description": "strokeTrimEnd (native unit)", + "type": "number" + }, + "strokeTrimOffset": { + "description": "strokeTrimOffset (native unit)", + "type": "number" + }, + "strokeTrimStart": { + "description": "strokeTrimStart (native unit)", + "type": "number" + }, + "strokeWidth": { + "description": "strokeWidth in canvas pixels", + "type": "number" + }, + "textBackgroundColor": { + "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textBgRadiusBottomLeft": { + "description": "textBgRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusBottomRight": { + "description": "textBgRadiusBottomRight in canvas pixels", + "type": "number" + }, + "textBgRadiusTopLeft": { + "description": "textBgRadiusTopLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusTopRight": { + "description": "textBgRadiusTopRight in canvas pixels", + "type": "number" + }, + "textColor": { + "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeColor": { + "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeDash": { + "description": "textStrokeDash in canvas pixels", + "type": "number" + }, + "textStrokeGap": { + "description": "textStrokeGap in canvas pixels", + "type": "number" + }, + "textStrokeWidth": { + "description": "textStrokeWidth in canvas pixels", + "type": "number" + }, + "timestamp": { + "description": "Clip-relative time in seconds", + "minimum": 0, + "type": "number" + }, + "videoCornerRadiusBottomLeft": { + "description": "videoCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusBottomRight": { + "description": "videoCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopLeft": { + "description": "videoCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopRight": { + "description": "videoCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "width": { + "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } +] - added
Input schema / properties / defaults / properties / type_data / propertyNamesAdded value: +{ + "type": "string" +} - changed
Input schema / properties / returning / descriptionPrevious value: -"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."New value: +"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write." - added
Input schema / properties / updates / items / properties / clip_index / maximumAdded value: +9007199254740991 - added
Input schema / properties / updates / items / properties / fit_to_lines / maximumAdded value: +9007199254740991 - changed
Input schema / properties / updates / items / properties / insert_at / descriptionPrevious value: -"Move this element in z-order, without rebuilding it. `front`/`back` are the ends of the group it is already in (the clip itself for an ungrouped element), so they never change what it belongs to. `{before: element_id}` / `{after: element_id}` sit it next to that element or group and put it in THAT node's group — which is how you move something into or out of a group and position it in one call. Applied after `group` when both are passed."New value: +"Move this element in z-order, without rebuilding it. `front`/`back` are the ends of the group it is already in (the clip itself for an ungrouped element), so they never change what it belongs to — with one exception: for an element that is ALONE in its group they move the GROUP within its parent scope, because positioning a sole member inside its own group would be a no-op. `{before: element_id}` / `{after: element_id}` sit it next to that element or group and put it in THAT node's group — which is how you move something into or out of a group and position it in one call. Applied after `group` when both are passed." - changed
Input schema / properties / updates / items / properties / keyframes / anyOfPrevious value: -[ - { - "items": { - "additionalProperties": false, - "properties": { - "backgroundBlur": { - "description": "Backdrop blur behind the element", - "type": "number" - }, - "bezier": { - "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "bezier_overrides": { - "additionalProperties": { - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ] - }, - "type": "object" - }, - "blur": { - "description": "Layer blur", - "type": "number" - }, - "borderRadiusBottomLeft": { - "description": "borderRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "borderRadiusBottomRight": { - "description": "borderRadiusBottomRight in canvas pixels", - "type": "number" - }, - "borderRadiusTopLeft": { - "description": "borderRadiusTopLeft in canvas pixels", - "type": "number" - }, - "borderRadiusTopRight": { - "description": "borderRadiusTopRight in canvas pixels", - "type": "number" - }, - "cropHeight": { - "description": "cropHeight (native unit)", - "type": "number" - }, - "cropWidth": { - "description": "cropWidth (native unit)", - "type": "number" - }, - "cropX": { - "description": "cropX (native unit)", - "type": "number" - }, - "cropY": { - "description": "cropY (native unit)", - "type": "number" - }, - "fillColor": { - "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "fontSize": { - "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", - "type": "number" - }, - "height": { - "description": "Height in canvas pixels (0 allowed)", - "minimum": 0, - "type": "number" - }, - "imageBorderColor": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "imageBorderWidth": { - "description": "imageBorderWidth in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomLeft": { - "description": "imageCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomRight": { - "description": "imageCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopLeft": { - "description": "imageCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopRight": { - "description": "imageCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "interpolation": { - "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "interpolation_overrides": { - "additionalProperties": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/interpolation" - }, - "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "cropX", - "cropY", - "cropWidth", - "cropHeight", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "fillColor", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ] - }, - "type": "object" - }, - "letterSpacing": { - "description": "Letter spacing in canvas pixels.", - "type": "number" - }, - "lineHeight": { - "description": "lineHeight (native unit)", - "type": "number" - }, - "opacity": { - "description": "Opacity 0-100", - "maximum": 100, - "minimum": 0, - "type": "number" - }, - "paddingBottom": { - "description": "paddingBottom in canvas pixels", - "type": "number" - }, - "paddingLeft": { - "description": "paddingLeft in canvas pixels", - "type": "number" - }, - "paddingRight": { - "description": "paddingRight in canvas pixels", - "type": "number" - }, - "paddingTop": { - "description": "paddingTop in canvas pixels", - "type": "number" - }, - "positionX": { - "description": "X position in canvas pixels (NOT `x`). Uses the SAME alignment-aware origin as the element's top-level x — left-aligned text uses top-left, center-aligned uses CENTER POINT, right-aligned uses top-right; all other types use top-left.", - "type": "number" - }, - "positionY": { - "description": "Y position in canvas pixels (NOT `y`). Origin matches positionX — center-aligned text positions by vertical center. y_anchor applies to the element's own y, not to keyframe values — keyframes use the alignment origin, so read the element back and key off its stored y.", - "type": "number" - }, - "rotateX": { - "description": "rotateX (native unit)", - "type": "number" - }, - "rotateY": { - "description": "rotateY (native unit)", - "type": "number" - }, - "rotation": { - "description": "Rotation in degrees", - "type": "number" - }, - "scaleX": { - "description": "Horizontal scale multiplier (1 = 100%)", - "type": "number" - }, - "scaleY": { - "description": "Vertical scale multiplier (1 = 100%)", - "type": "number" - }, - "shadowBlur": { - "description": "shadowBlur in canvas pixels", - "type": "number" - }, - "shadowColor": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "shadowOffsetX": { - "description": "shadowOffsetX in canvas pixels", - "type": "number" - }, - "shadowOffsetY": { - "description": "shadowOffsetY in canvas pixels", - "type": "number" - }, - "shadowSpread": { - "description": "shadowSpread in canvas pixels", - "type": "number" - }, - "strokeColor": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "strokeDash": { - "description": "strokeDash in canvas pixels", - "type": "number" - }, - "strokeGap": { - "description": "strokeGap in canvas pixels", - "type": "number" - }, - "strokeTrimEnd": { - "description": "strokeTrimEnd (native unit)", - "type": "number" - }, - "strokeTrimOffset": { - "description": "strokeTrimOffset (native unit)", - "type": "number" - }, - "strokeTrimStart": { - "description": "strokeTrimStart (native unit)", - "type": "number" - }, - "strokeWidth": { - "description": "strokeWidth in canvas pixels", - "type": "number" - }, - "textBackgroundColor": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textBgRadiusBottomLeft": { - "description": "textBgRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusBottomRight": { - "description": "textBgRadiusBottomRight in canvas pixels", - "type": "number" - }, - "textBgRadiusTopLeft": { - "description": "textBgRadiusTopLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusTopRight": { - "description": "textBgRadiusTopRight in canvas pixels", - "type": "number" - }, - "textColor": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textStrokeColor": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", - "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textStrokeDash": { - "description": "textStrokeDash in canvas pixels", - "type": "number" - }, - "textStrokeGap": { - "description": "textStrokeGap in canvas pixels", - "type": "number" - }, - "textStrokeWidth": { - "description": "textStrokeWidth in canvas pixels", - "type": "number" - }, - "timestamp": { - "description": "Clip-relative time in seconds", - "minimum": 0, - "type": "number" - }, - "videoCornerRadiusBottomLeft": { - "description": "videoCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusBottomRight": { - "description": "videoCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopLeft": { - "description": "videoCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopRight": { - "description": "videoCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "width": { - "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", - "minimum": 0, - "type": "number" - } - }, - "required": [ - "timestamp" - ], - "type": "object" - }, - "type": "array" - }, - { - "type": "null" - } -]New value: +[ + { + "items": { + "additionalProperties": false, + "properties": { + "backgroundBlur": { + "description": "Backdrop blur behind the element", + "type": "number" + }, + "bezier": { + "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "bezier_overrides": { + "additionalProperties": { + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "required": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "object" + }, + "blur": { + "description": "Layer blur", + "type": "number" + }, + "borderRadiusBottomLeft": { + "description": "borderRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "borderRadiusBottomRight": { + "description": "borderRadiusBottomRight in canvas pixels", + "type": "number" + }, + "borderRadiusTopLeft": { + "description": "borderRadiusTopLeft in canvas pixels", + "type": "number" + }, + "borderRadiusTopRight": { + "description": "borderRadiusTopRight in canvas pixels", + "type": "number" + }, + "cropHeight": { + "description": "cropHeight (native unit)", + "type": "number" + }, + "cropWidth": { + "description": "cropWidth (native unit)", + "type": "number" + }, + "cropX": { + "description": "cropX (native unit)", + "type": "number" + }, + "cropY": { + "description": "cropY (native unit)", + "type": "number" + }, + "fillColor": { + "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "fontSize": { + "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", + "type": "number" + }, + "height": { + "description": "Height in canvas pixels (0 allowed)", + "minimum": 0, + "type": "number" + }, + "imageBorderColor": { + "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "imageBorderWidth": { + "description": "imageBorderWidth in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomLeft": { + "description": "imageCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomRight": { + "description": "imageCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopLeft": { + "description": "imageCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopRight": { + "description": "imageCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "interpolation": { + "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "interpolation_overrides": { + "additionalProperties": { + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "string" + }, + "required": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ], + "type": "object" + }, + "letterSpacing": { + "description": "Letter spacing in canvas pixels.", + "type": "number" + }, + "lineHeight": { + "description": "lineHeight (native unit)", + "type": "number" + }, + "opacity": { + "description": "Opacity 0-100", + "maximum": 100, + "minimum": 0, + "type": "number" + }, + "paddingBottom": { + "description": "paddingBottom in canvas pixels", + "type": "number" + }, + "paddingLeft": { + "description": "paddingLeft in canvas pixels", + "type": "number" + }, + "paddingRight": { + "description": "paddingRight in canvas pixels", + "type": "number" + }, + "paddingTop": { + "description": "paddingTop in canvas pixels", + "type": "number" + }, + "positionX": { + "description": "X position in canvas pixels (NOT `x`). Same origin as the element's top-level x: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right.", + "type": "number" + }, + "positionY": { + "description": "Y position in canvas pixels (NOT `y`). Same origin as the element's top-level y: for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. y_anchor applies to the element's own y, NOT to keyframe values, so read the element back and key off its stored y.", + "type": "number" + }, + "rotateX": { + "description": "rotateX (native unit)", + "type": "number" + }, + "rotateY": { + "description": "rotateY (native unit)", + "type": "number" + }, + "rotation": { + "description": "Rotation in degrees", + "type": "number" + }, + "scaleX": { + "description": "Horizontal scale multiplier (1 = 100%)", + "type": "number" + }, + "scaleY": { + "description": "Vertical scale multiplier (1 = 100%)", + "type": "number" + }, + "shadowBlur": { + "description": "shadowBlur in canvas pixels", + "type": "number" + }, + "shadowColor": { + "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "shadowOffsetX": { + "description": "shadowOffsetX in canvas pixels", + "type": "number" + }, + "shadowOffsetY": { + "description": "shadowOffsetY in canvas pixels", + "type": "number" + }, + "shadowSpread": { + "description": "shadowSpread in canvas pixels", + "type": "number" + }, + "strokeColor": { + "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "strokeDash": { + "description": "strokeDash in canvas pixels", + "type": "number" + }, + "strokeGap": { + "description": "strokeGap in canvas pixels", + "type": "number" + }, + "strokeTrimEnd": { + "description": "strokeTrimEnd (native unit)", + "type": "number" + }, + "strokeTrimOffset": { + "description": "strokeTrimOffset (native unit)", + "type": "number" + }, + "strokeTrimStart": { + "description": "strokeTrimStart (native unit)", + "type": "number" + }, + "strokeWidth": { + "description": "strokeWidth in canvas pixels", + "type": "number" + }, + "textBackgroundColor": { + "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textBgRadiusBottomLeft": { + "description": "textBgRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusBottomRight": { + "description": "textBgRadiusBottomRight in canvas pixels", + "type": "number" + }, + "textBgRadiusTopLeft": { + "description": "textBgRadiusTopLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusTopRight": { + "description": "textBgRadiusTopRight in canvas pixels", + "type": "number" + }, + "textColor": { + "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeColor": { + "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "textStrokeDash": { + "description": "textStrokeDash in canvas pixels", + "type": "number" + }, + "textStrokeGap": { + "description": "textStrokeGap in canvas pixels", + "type": "number" + }, + "textStrokeWidth": { + "description": "textStrokeWidth in canvas pixels", + "type": "number" + }, + "timestamp": { + "description": "Clip-relative time in seconds", + "minimum": 0, + "type": "number" + }, + "videoCornerRadiusBottomLeft": { + "description": "videoCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusBottomRight": { + "description": "videoCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopLeft": { + "description": "videoCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopRight": { + "description": "videoCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "width": { + "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } +] - added
Input schema / properties / updates / items / properties / keyframes_repeat / properties / count / maximumAdded value: +9007199254740991 - added
Input schema / properties / updates / items / properties / type_data / propertyNamesAdded value: +{ + "type": "string" +} - changed
Input schema / properties / updates / items / properties / x / descriptionPrevious value: -"New X (canvas pixels). ORIGIN follows the element's alignment: text uses top-left / CENTER / top-right per alignment, all other types use top-left. Changing alignment in the same call re-anchors x/y to the new origin."New value: +"New X (canvas pixels). Same origin as add_elements: `x` is the left edge, except TEXT where alignment picks it: left→left, center→centre, right→right. Changing alignment in the same call re-anchors x to the new edge." - changed
Input schema / properties / updates / items / properties / y / descriptionPrevious value: -"New Y (canvas pixels). Takes type_data.y_anchor the same way add_elements does."New value: +"New Y (canvas pixels) — for TEXT `y` is the vertical CENTRE when centre-aligned and the TOP otherwise; every other type uses the top. See y_anchor." - added
Input schema / properties / updates / items / properties / y_anchorAdded value: +{ + "description": "TEXT only. ALWAYS send `y_anchor` ('top'|'center'|'bottom') when you set `y` on text, so the position states what you meant instead of inheriting the alignment origin. Omit `y` and it anchors to the element's CURRENT box, holding a centred label centred across a re-measure. Not stored — state it on every call. (Also accepted inside type_data; this one wins.)", + "enum": [ + "top", + "center", + "bottom" + ], + "type": "string" +}
- Changed
update_groups19 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / items / items / properties / anchor_px / itemsPrevious value: -[ - { - "type": "number" - }, - { - "type": "number" - } -]New value: +false - added
Input schema / properties / items / items / properties / anchor_px / prefixItemsAdded value: +[ + { + "type": "number" + }, + { + "type": "number" + } +] - added
Input schema / properties / items / items / properties / clip_index / maximumAdded value: +9007199254740991 - added
Input schema / properties / items / items / properties / keyframes / items / properties / bezier_overrides / propertyNames / typeAdded value: +"string" - added
Input schema / properties / items / items / properties / keyframes / items / properties / bezier_overrides / requiredAdded value: +[ + "offsetX", + "offsetY", + "scaleX", + "scaleY", + "rotation", + "rotateX", + "rotateY", + "opacity", + "blur" +] - removed
Input schema / properties / items / items / properties / keyframes / items / properties / interpolation_overrides / additionalProperties / $refRemoved value: -"#/properties/items/items/properties/keyframes/items/properties/interpolation" - added
Input schema / properties / items / items / properties / keyframes / items / properties / interpolation_overrides / additionalProperties / enumAdded value: +[ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" +] - added
Input schema / properties / items / items / properties / keyframes / items / properties / interpolation_overrides / additionalProperties / typeAdded value: +"string" - added
Input schema / properties / items / items / properties / keyframes / items / properties / interpolation_overrides / propertyNames / typeAdded value: +"string" - added
Input schema / properties / items / items / properties / keyframes / items / properties / interpolation_overrides / requiredAdded value: +[ + "offsetX", + "offsetY", + "scaleX", + "scaleY", + "rotation", + "rotateX", + "rotateY", + "opacity", + "blur" +] - changed
Input schema / properties / items / items / properties / offset_px / itemsPrevious value: -[ - { - "type": "number" - }, - { - "type": "number" - } -]New value: +false - added
Input schema / properties / items / items / properties / offset_px / prefixItemsAdded value: +[ + { + "type": "number" + }, + { + "type": "number" + } +] - changed
Input schema / properties / items / items / properties / rotate / itemsPrevious value: -[ - { - "type": "number" - }, - { - "type": "number" - } -]New value: +false - added
Input schema / properties / items / items / properties / rotate / prefixItemsAdded value: +[ + { + "type": "number" + }, + { + "type": "number" + } +] - changed
Input schema / properties / items / items / properties / scale / itemsPrevious value: -[ - { - "type": "number" - }, - { - "type": "number" - } -]New value: +false - added
Input schema / properties / items / items / properties / scale / prefixItemsAdded value: +[ + { + "type": "number" + }, + { + "type": "number" + } +] - changed
Input schema / properties / returning / descriptionPrevious value: -"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."New value: +"Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping; plus `placement` {y_anchor, top, center, bottom} — where the box landed and what your `y` meant, emitted only when the origin was implicit or resolves to 'center'. Compare placement.center with a container's centre line to verify centring: a mis-anchored label is the one layout error nothing else reports), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write."
- Changed
update_project2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
upload_file2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
voiceover_batch4 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - removed
Input schema / properties / entries / items / anyOfRemoved value: -[ - { - "additionalProperties": false, - "properties": { - "action": { - "const": "set_text", - "description": "Write the voiceover transcript onto the clip without generating audio.", - "type": "string" - }, - "clip_index": { - "description": "Zero-based clip index", - "minimum": 0, - "type": "integer" - }, - "text": { - "description": "Voiceover transcript", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "action", - "clip_index", - "text" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "action": { - "const": "generate_speech", - "description": "Generate speech audio from the transcript already set on the clip.", - "type": "string" - }, - "clip_id": { - "description": "Clip ID. Give this or clip_index.", - "minLength": 1, - "type": "string" - }, - "clip_index": { - "description": "Zero-based clip index. Give this or clip_id.", - "minimum": 0, - "type": "integer" - } - }, - "required": [ - "action" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "action": { - "const": "set_and_generate", - "description": "Write the transcript and generate its speech audio in one step.", - "type": "string" - }, - "clip_id": { - "description": "Clip ID. Give this or clip_index.", - "minLength": 1, - "type": "string" - }, - "clip_index": { - "description": "Zero-based clip index. Give this or clip_id.", - "minimum": 0, - "type": "integer" - }, - "text": { - "description": "Voiceover transcript", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "action", - "text" - ], - "type": "object" - } -] - added
Input schema / properties / entries / items / oneOfAdded value: +[ + { + "properties": { + "action": { + "const": "set_text", + "description": "Write the voiceover transcript onto the clip without generating audio.", + "type": "string" + }, + "clip_index": { + "description": "Zero-based clip index", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "text": { + "description": "Voiceover transcript", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "action", + "clip_index", + "text" + ], + "type": "object" + }, + { + "properties": { + "action": { + "const": "generate_speech", + "description": "Generate speech audio from the transcript already set on the clip.", + "type": "string" + }, + "clip_id": { + "description": "Clip ID. Give this or clip_index.", + "minLength": 1, + "type": "string" + }, + "clip_index": { + "description": "Zero-based clip index. Give this or clip_id.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "action" + ], + "type": "object" + }, + { + "properties": { + "action": { + "const": "set_and_generate", + "description": "Write the transcript and generate its speech audio in one step.", + "type": "string" + }, + "clip_id": { + "description": "Clip ID. Give this or clip_index.", + "minLength": 1, + "type": "string" + }, + "clip_index": { + "description": "Zero-based clip index. Give this or clip_id.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" + }, + "text": { + "description": "Voiceover transcript", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "action", + "text" + ], + "type": "object" + } +]
9 tool updates
- Changed
add_elements14 fields changed- added
Input schema / properties / defaultsAdded value: +{ + "additionalProperties": false, + "description": "Values shared by every item, sent once rather than repeated. Items win per key; type_data merges one level. E.g. defaults:{clip_index:1, element_type:'text', type_data:{font_setting:{font:'Inter',weight:'600'}, alignment:'center'}} then items carry only what differs.", + "properties": { + "clip_id": { + "type": "string" + }, + "clip_index": { + "minimum": 0, + "type": "integer" + }, + "element_type": { + "enum": [ + "text", + "callout", + "rectangle", + "arrow", + "blur", + "spotlight", + "zoom", + "image", + "video", + "animation" + ], + "type": "string" + }, + "end_time": { + "minimum": 0, + "type": "number" + }, + "group": { + "minLength": 1, + "type": "string" + }, + "height": { + "minimum": 0, + "type": "number" + }, + "insert_at": { + "enum": [ + "front", + "back" + ], + "type": "string" + }, + "keyframes": { + "anyOf": [ + { + "items": { + "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items" + }, + "type": "array" + }, + { + "type": "null" + } + ] + }, + "rotation": { + "type": "number" + }, + "start_time": { + "minimum": 0, + "type": "number" + }, + "type_data": { + "additionalProperties": {}, + "type": "object" + }, + "width": { + "minimum": 0, + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "type": "object" +} - changed
Input schema / properties / elements / items / properties / clip_index / descriptionPrevious value: -"Zero-based clip index"New value: +"Zero-based clip index. Required unless hoisted into `defaults`." - changed
Input schema / properties / elements / items / properties / height / descriptionPrevious value: -"Height, pixels (0 allowed)"New value: +"Height, pixels (0 allowed). For text the box's height always follows the measured text, so this reads as the space you are giving it: the text is centred in that space and layout.fits_height says whether it fit. Use type_data.fit to shrink the font into it." - added
Input schema / properties / elements / items / properties / insert_atAdded value: +{ + "anyOf": [ + { + "enum": [ + "front", + "back" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "before": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "before" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "after": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "after" + ], + "type": "object" + } + ], + "description": "Where the element lands in z-order, so you don't need a follow-up reorder_elements. `front` (default) puts it on top of what's already on the clip; `back` puts it behind everything — what a backdrop panel or a wash needs. `{before: element_id}` / `{after: element_id}` place it next to a specific element or group and put it in THAT node's group, which is the only way to position inside a group. Placement is relative to the clip AS IT STANDS when the item is applied, so several `back` items in one call end up in REVERSE input order: send one backdrop per call, or list them back-to-front." +} - added
Input schema / properties / elements / items / properties / keyframes / anyOfAdded value: +[ + { + "items": { + "additionalProperties": false, + "properties": { + "backgroundBlur": { + "description": "Backdrop blur behind the element", + "type": "number" + }, + "bezier": { + "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "bezier_overrides": { + "additionalProperties": { + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ] + }, + "type": "object" + }, + "blur": { + "description": "Layer blur", + "type": "number" + }, + "borderRadiusBottomLeft": { + "description": "borderRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "borderRadiusBottomRight": { + "description": "borderRadiusBottomRight in canvas pixels", + "type": "number" + }, + "borderRadiusTopLeft": { + "description": "borderRadiusTopLeft in canvas pixels", + "type": "number" + }, + "borderRadiusTopRight": { + "description": "borderRadiusTopRight in canvas pixels", + "type": "number" + }, + "cropHeight": { + "description": "cropHeight (native unit)", + "type": "number" + }, + "cropWidth": { + "description": "cropWidth (native unit)", + "type": "number" + }, + "cropX": { + "description": "cropX (native unit)", + "type": "number" + }, + "cropY": { + "description": "cropY (native unit)", + "type": "number" + }, + "fillColor": { + "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "fontSize": { + "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", + "type": "number" + }, + "height": { + "description": "Height in canvas pixels (0 allowed)", + "minimum": 0, + "type": "number" + }, + "imageBorderColor": { + "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "imageBorderWidth": { + "description": "imageBorderWidth in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomLeft": { + "description": "imageCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomRight": { + "description": "imageCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopLeft": { + "description": "imageCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopRight": { + "description": "imageCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "interpolation": { + "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "interpolation_overrides": { + "additionalProperties": { + "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/interpolation" + }, + "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ] + }, + "type": "object" + }, + "letterSpacing": { + "description": "Letter spacing in canvas pixels.", + "type": "number" + }, + "lineHeight": { + "description": "lineHeight (native unit)", + "type": "number" + }, + "opacity": { + "description": "Opacity 0-100", + "maximum": 100, + "minimum": 0, + "type": "number" + }, + "paddingBottom": { + "description": "paddingBottom in canvas pixels", + "type": "number" + }, + "paddingLeft": { + "description": "paddingLeft in canvas pixels", + "type": "number" + }, + "paddingRight": { + "description": "paddingRight in canvas pixels", + "type": "number" + }, + "paddingTop": { + "description": "paddingTop in canvas pixels", + "type": "number" + }, + "positionX": { + "description": "X position in canvas pixels (NOT `x`). Uses the SAME alignment-aware origin as the element's top-level x — left-aligned text uses top-left, center-aligned uses CENTER POINT, right-aligned uses top-right; all other types use top-left.", + "type": "number" + }, + "positionY": { + "description": "Y position in canvas pixels (NOT `y`). Origin matches positionX — center-aligned text positions by vertical center. y_anchor applies to the element's own y, not to keyframe values — keyframes use the alignment origin, so read the element back and key off its stored y.", + "type": "number" + }, + "rotateX": { + "description": "rotateX (native unit)", + "type": "number" + }, + "rotateY": { + "description": "rotateY (native unit)", + "type": "number" + }, + "rotation": { + "description": "Rotation in degrees", + "type": "number" + }, + "scaleX": { + "description": "Horizontal scale multiplier (1 = 100%)", + "type": "number" + }, + "scaleY": { + "description": "Vertical scale multiplier (1 = 100%)", + "type": "number" + }, + "shadowBlur": { + "description": "shadowBlur in canvas pixels", + "type": "number" + }, + "shadowColor": { + "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "shadowOffsetX": { + "description": "shadowOffsetX in canvas pixels", + "type": "number" + }, + "shadowOffsetY": { + "description": "shadowOffsetY in canvas pixels", + "type": "number" + }, + "shadowSpread": { + "description": "shadowSpread in canvas pixels", + "type": "number" + }, + "strokeColor": { + "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "strokeDash": { + "description": "strokeDash in canvas pixels", + "type": "number" + }, + "strokeGap": { + "description": "strokeGap in canvas pixels", + "type": "number" + }, + "strokeTrimEnd": { + "description": "strokeTrimEnd (native unit)", + "type": "number" + }, + "strokeTrimOffset": { + "description": "strokeTrimOffset (native unit)", + "type": "number" + }, + "strokeTrimStart": { + "description": "strokeTrimStart (native unit)", + "type": "number" + }, + "strokeWidth": { + "description": "strokeWidth in canvas pixels", + "type": "number" + }, + "textBackgroundColor": { + "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "textBgRadiusBottomLeft": { + "description": "textBgRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusBottomRight": { + "description": "textBgRadiusBottomRight in canvas pixels", + "type": "number" + }, + "textBgRadiusTopLeft": { + "description": "textBgRadiusTopLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusTopRight": { + "description": "textBgRadiusTopRight in canvas pixels", + "type": "number" + }, + "textColor": { + "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "textStrokeColor": { + "$ref": "#/properties/elements/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "textStrokeDash": { + "description": "textStrokeDash in canvas pixels", + "type": "number" + }, + "textStrokeGap": { + "description": "textStrokeGap in canvas pixels", + "type": "number" + }, + "textStrokeWidth": { + "description": "textStrokeWidth in canvas pixels", + "type": "number" + }, + "timestamp": { + "description": "Clip-relative time in seconds", + "minimum": 0, + "type": "number" + }, + "videoCornerRadiusBottomLeft": { + "description": "videoCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusBottomRight": { + "description": "videoCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopLeft": { + "description": "videoCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopRight": { + "description": "videoCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "width": { + "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } +] - changed
Input schema / properties / elements / items / properties / keyframes / descriptionPrevious value: -"Animation keyframes (≥2 entries). Each entry has a timestamp plus one or more keyframable properties (position/size in canvas pixels; rotation°, opacity 0-100, scale, colors as #rrggbb[aa], etc. in native units). Easing: per-entry `interpolation` + optional per-property `interpolation_overrides`. Call get_element_schema to see which properties this element_type can keyframe."New value: +"Animation keyframes (≥2 entries). Each entry has a timestamp plus one or more keyframable properties (position/size in canvas pixels; rotation°, opacity 0-100, scale, colors as #rrggbb[aa], etc. in native units). Easing: per-entry `interpolation` + optional per-property `interpolation_overrides`. Call get_element_schema to see which properties this element_type can keyframe. null is accepted and means none." - removed
Input schema / properties / elements / items / properties / keyframes / itemsRemoved value: -{ - "additionalProperties": false, - "properties": { - "backgroundBlur": { - "description": "Backdrop blur behind the element", - "type": "number" - }, - "bezier": { - "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "bezier_overrides": { - "additionalProperties": { - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ] - }, - "type": "object" - }, - "blur": { - "description": "Layer blur", - "type": "number" - }, - "borderRadiusBottomLeft": { - "description": "borderRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "borderRadiusBottomRight": { - "description": "borderRadiusBottomRight in canvas pixels", - "type": "number" - }, - "borderRadiusTopLeft": { - "description": "borderRadiusTopLeft in canvas pixels", - "type": "number" - }, - "borderRadiusTopRight": { - "description": "borderRadiusTopRight in canvas pixels", - "type": "number" - }, - "fontSize": { - "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", - "type": "number" - }, - "height": { - "description": "Height in canvas pixels (0 allowed)", - "minimum": 0, - "type": "number" - }, - "imageBorderColor": { - "$ref": "#/properties/elements/items/properties/keyframes/items/properties/strokeColor", - "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "imageBorderWidth": { - "description": "imageBorderWidth in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomLeft": { - "description": "imageCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomRight": { - "description": "imageCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopLeft": { - "description": "imageCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopRight": { - "description": "imageCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "interpolation": { - "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "interpolation_overrides": { - "additionalProperties": { - "$ref": "#/properties/elements/items/properties/keyframes/items/properties/interpolation" - }, - "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ] - }, - "type": "object" - }, - "letterSpacing": { - "description": "Letter spacing in canvas pixels.", - "type": "number" - }, - "lineHeight": { - "description": "lineHeight (native unit)", - "type": "number" - }, - "opacity": { - "description": "Opacity 0-100", - "maximum": 100, - "minimum": 0, - "type": "number" - }, - "paddingBottom": { - "description": "paddingBottom in canvas pixels", - "type": "number" - }, - "paddingLeft": { - "description": "paddingLeft in canvas pixels", - "type": "number" - }, - "paddingRight": { - "description": "paddingRight in canvas pixels", - "type": "number" - }, - "paddingTop": { - "description": "paddingTop in canvas pixels", - "type": "number" - }, - "positionX": { - "description": "X position in canvas pixels (NOT `x`). Uses the SAME alignment-aware origin as the element's top-level x — left-aligned text uses top-left, center-aligned uses CENTER POINT, right-aligned uses top-right; all other types use top-left.", - "type": "number" - }, - "positionY": { - "description": "Y position in canvas pixels (NOT `y`). Origin matches positionX — center-aligned text positions by vertical center.", - "type": "number" - }, - "rotateX": { - "description": "rotateX (native unit)", - "type": "number" - }, - "rotateY": { - "description": "rotateY (native unit)", - "type": "number" - }, - "rotation": { - "description": "Rotation in degrees", - "type": "number" - }, - "scaleX": { - "description": "Horizontal scale multiplier (1 = 100%)", - "type": "number" - }, - "scaleY": { - "description": "Vertical scale multiplier (1 = 100%)", - "type": "number" - }, - "shadowBlur": { - "description": "shadowBlur in canvas pixels", - "type": "number" - }, - "shadowColor": { - "$ref": "#/properties/elements/items/properties/keyframes/items/properties/strokeColor", - "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "shadowOffsetX": { - "description": "shadowOffsetX in canvas pixels", - "type": "number" - }, - "shadowOffsetY": { - "description": "shadowOffsetY in canvas pixels", - "type": "number" - }, - "shadowSpread": { - "description": "shadowSpread in canvas pixels", - "type": "number" - }, - "strokeColor": { - "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "strokeDash": { - "description": "strokeDash in canvas pixels", - "type": "number" - }, - "strokeGap": { - "description": "strokeGap in canvas pixels", - "type": "number" - }, - "strokeTrimEnd": { - "description": "strokeTrimEnd (native unit)", - "type": "number" - }, - "strokeTrimOffset": { - "description": "strokeTrimOffset (native unit)", - "type": "number" - }, - "strokeTrimStart": { - "description": "strokeTrimStart (native unit)", - "type": "number" - }, - "strokeWidth": { - "description": "strokeWidth in canvas pixels", - "type": "number" - }, - "textBackgroundColor": { - "$ref": "#/properties/elements/items/properties/keyframes/items/properties/strokeColor", - "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textBgRadiusBottomLeft": { - "description": "textBgRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusBottomRight": { - "description": "textBgRadiusBottomRight in canvas pixels", - "type": "number" - }, - "textBgRadiusTopLeft": { - "description": "textBgRadiusTopLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusTopRight": { - "description": "textBgRadiusTopRight in canvas pixels", - "type": "number" - }, - "textColor": { - "$ref": "#/properties/elements/items/properties/keyframes/items/properties/strokeColor", - "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textStrokeColor": { - "$ref": "#/properties/elements/items/properties/keyframes/items/properties/strokeColor", - "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textStrokeDash": { - "description": "textStrokeDash in canvas pixels", - "type": "number" - }, - "textStrokeGap": { - "description": "textStrokeGap in canvas pixels", - "type": "number" - }, - "textStrokeWidth": { - "description": "textStrokeWidth in canvas pixels", - "type": "number" - }, - "timestamp": { - "description": "Clip-relative time in seconds", - "minimum": 0, - "type": "number" - }, - "videoCornerRadiusBottomLeft": { - "description": "videoCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusBottomRight": { - "description": "videoCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopLeft": { - "description": "videoCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopRight": { - "description": "videoCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "width": { - "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", - "minimum": 0, - "type": "number" - } - }, - "required": [ - "timestamp" - ], - "type": "object" -} - removed
Input schema / properties / elements / items / properties / keyframes / typeRemoved value: -"array" - added
Input schema / properties / elements / items / properties / keyframes_repeatAdded value: +{ + "additionalProperties": false, + "description": "Repeat `keyframes` as a cycle — { count, mode?, every? }. Requires `keyframes` in the same call.", + "properties": { + "count": { + "description": "TOTAL number of cycles, INCLUDING the one you wrote. 1 is a no-op. Expansion stops at the clip end rather than piling the overflow onto the last frame, and the generated total is capped at 600 keyframes (it errors rather than silently truncating).", + "minimum": 1, + "type": "integer" + }, + "every": { + "description": "Seconds between cycle STARTS. Defaults to the cycle's own span (back-to-back). A LARGER value holds the last value in the gap — that is how you get a pulse every 2s instead of a constant wobble. Shorter than the cycle is rejected, because the cycles would overlap and collide on the same frames.", + "exclusiveMinimum": 0, + "type": "number" + }, + "mode": { + "description": "'loop' (default) replays the cycle forwards every time — seamless only if your first and last values match. 'pingpong' alternates forwards/backwards, so the value always returns to where it started without a jump; use it for a breathe/pulse written as a one-way ramp.", + "enum": [ + "loop", + "pingpong" + ], + "type": "string" + } + }, + "required": [ + "count" + ], + "type": "object" +} - changed
Input schema / properties / elements / items / properties / width / descriptionPrevious value: -"Width, pixels (0 allowed — e.g. a bar that draws in from 0)"New value: +"Width, pixels (0 allowed — e.g. a bar that draws in from 0). For text this is the WRAP width and it is kept as sent: the text wraps to it and the box stays this wide. (Height differs — the box's height follows the measured text.)" - changed
Input schema / properties / elements / items / properties / x / descriptionPrevious value: -"X position in canvas pixels. ORIGIN is alignment-dependent: TEXT only — left-aligned uses top-left, center-aligned uses CENTER POINT, right-aligned uses top-right. All other element types (callout, rectangle, arrow, blur, spotlight, image, animation) use top-left. For zoom, use type_data.center_x instead."New value: +"X position in canvas pixels. ORIGIN is alignment-dependent: TEXT only — left-aligned uses top-left, center-aligned uses CENTER POINT, right-aligned uses top-right. All other element types (callout, rectangle, arrow, blur, spotlight, image, animation) use top-left. For zoom, use type_data.centerX instead." - changed
Input schema / properties / elements / items / properties / y / descriptionPrevious value: -"Y position in canvas pixels. ORIGIN matches x: center-aligned text positions by its vertical center. All other types and alignments use the top edge."New value: +"Y position in canvas pixels. Which part of the element this refers to is set by type_data.y_anchor for text (top / center / bottom). To sit a label on a row, pill, chip, card or beside an icon, pass that container's centre line here with y_anchor:'center'." - removed
Input schema / properties / elements / items / requiredRemoved value: -[ - "clip_index" -] - added
Input schema / properties / returningAdded value: +{ + "description": "Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write.", + "items": { + "enum": [ + "ids", + "layout", + "qa", + "qa.codes" + ], + "type": "string" + }, + "type": "array" +}
- Changed
get_clip9 fields changed- changed
Input schema / properties / render / descriptionPrevious value: -"Render a PNG of the frame. Presence of this object IS the request to render — omit it and nothing is rendered. `{}` renders at t=0. Independent of `select`, which only shapes the JSON: pair `select: []` with `render: {}` for the PNG alone (smallest read). CHECKING YOUR WORK: pass a mid-clip `timestamp`, not the t=0 default — text and image elements have entry animations (a ~0.4s slide/fade by default), so at t=0 they have not arrived yet and a correct edit renders as an empty frame. Shapes have no entry animation and do show at t=0, which makes a t=0 render especially misleading: some elements appear and others don't."New value: +"Render the clip as an image. Presence of this object IS the request to render — omit it and nothing is rendered. `{}` renders at t=0. Independent of `select`, which only shapes the JSON: pair `select: []` with `render: {}` for the PNG alone (smallest read). CHECKING YOUR WORK: pass `timestamps` with SEVERAL mid-clip moments, not the t=0 default — text and image elements have entry animations (a ~0.4s slide/fade by default), so at t=0 they have not arrived yet and a correct edit renders as an empty frame, while shapes have no entry animation and do show at t=0. That mix is what makes a single t=0 render actively misleading: some elements appear and others don't. A list comes back as one grid for about a quarter of the tokens of the same frames separately, so checking several moments is the cheap option, not the expensive one. `animations: false` draws everything settled if you would rather not pick moments at all." - added
Input schema / properties / render / properties / animationsAdded value: +{ + "description": "Whether entry/exit animations play at this timestamp. Default true — the frame as the video will show it, which is what you want to judge motion. Pass false to draw every element settled at its final position and full opacity: use that to check COMPOSITION, because with staggered starts and short windows there may be no single timestamp at which nothing is mid-flight, and an element part-way through a slide reads as mis-positioned when it is fine.", + "type": "boolean" +} - added
Input schema / properties / render / properties / layoutAdded value: +{ + "description": "Only meaningful when `timestamps` holds several. 'sheet' (default) tiles them into one image; 'separate' returns them full-size, which costs ~4x more — use it only when a grid cell is too small to judge.", + "enum": [ + "sheet", + "separate" + ], + "type": "string" +} - added
Input schema / properties / render / properties / max_widthAdded value: +{ + "description": "Width in px of the IMAGE you get back — for a grid that is the whole grid, not each cell, so a cell is roughly a third of it. Default 960 for a single frame, 1280 for a grid. An image costs roughly (w×h)/750 tokens, so 1280 is ~1229 and 960 ~691; above 1568 nothing is gained because the model downscales to that anyway. The default is legible for this design system's type scale — a 40px canvas caption lands at ~20px. Raise it only to read genuinely small print, such as UI text inside a pasted screenshot.", + "maximum": 1568, + "minimum": 320, + "type": "integer" +} - changed
Input schema / properties / render / properties / save / descriptionPrevious value: -"Also upload the rendered PNG to S3 and return presigned_url, which you can pass as source_url to update_clueprint (files=[{path, source_url}])."New value: +"Also upload the rendered image to S3 and return presigned_url, which you can pass as source_url to update_clueprint (files=[{path, source_url}]). Uploads ONE image, so it works with a single frame or a grid but not with layout:'separate' — there is one URL and several frames." - removed
Input schema / properties / render / properties / timestampRemoved value: -{ - "description": "The moment within the clip to render, in seconds (default 0).", - "minimum": 0, - "type": "number" -} - added
Input schema / properties / render / properties / timestampsAdded value: +{ + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "items": { + "minimum": 0, + "type": "number" + }, + "maxItems": 15, + "minItems": 1, + "type": "array" + } + ], + "description": "Which moment(s) of the clip to render, in seconds (default 0). Pass several — [0.5, 2, 4] — and they come back as one labelled grid costing about a quarter of what those frames cost individually. Prefer several whenever you are checking rather than reading: entry animations mean no single moment shows everything, so one frame is usually the wrong question. A grid cell is a third of the width, so for small print pass a single number. Max 15; duplicates dropped, sorted into time order." +} - changed
Input schema / properties / select / descriptionPrevious value: -"Ask for exactly the JSON you want, GraphQL-style. Omit for everything; pass [] for none.\n Sections: 'elements' (whole element rows), 'words' (per-word VO timings). Rendering is `render`, not a value here.\n Per-key: 'elements.<key>' projects element rows to just those keys (id is always kept). Keys: name, geo, x, y, width, height, start_time, end_time, rotation, keyframes, textdata, shapedata, imagedata, videodata, zoomdata, codedata, parent_id.\n Examples: ['elements.x','elements.y','elements.width','elements.height'] to read geometry; ['elements.name','elements.start_time','elements.end_time'] for a timing pass; ['words'] to sync visuals to narration; [] with render:{} returns the PNG with no JSON (smallest read); ['elements.textdata','words'] to rewrite copy against the VO.\n Mixing 'elements' with 'elements.<key>' returns whole rows. Use element_ids to choose WHICH rows — that is independent of this."New value: +"Ask for exactly the JSON you want, GraphQL-style. Omit for everything; pass [] for none.\n Sections: 'elements' (whole element rows), 'voiceover_words' (per-word VO timings; returns the key of the same name, holding `{word, start, end, punctuated_word}` with start/end in SECONDS — null on a clip with no transcription), 'groups' (group rows: id, name, parent_id, bounds_px, anchor_px, keyframes). Each section returns the key it is named after. Rendering is `render`, not a value here.\n Per-key: 'elements.<key>' projects element rows to just those keys (id is always kept). Keys: name, element_type, x, y, width, height, start_time, end_time, rotation, keyframes, textdata, shapedata, imagedata, videodata, zoomdata, codedata, parent_id.\n Examples: ['elements.x','elements.y','elements.width','elements.height'] to read geometry; ['elements.name','elements.start_time','elements.end_time'] for a timing pass; ['voiceover_words'] to sync visuals to narration; ['groups'] to resolve a group id for update_groups; [] with render:{} returns the PNG with no JSON (smallest read); ['elements.textdata','voiceover_words'] to rewrite copy against the VO.\n Mixing 'elements' with 'elements.<key>' returns whole rows. Use element_ids to choose WHICH rows — that is independent of this." - changed
Input schema / properties / select / items / enumPrevious value: -[ - "elements", - "words", - "elements.name", - "elements.geo", - "elements.x", - "elements.y", - "elements.width", - "elements.height", - "elements.start_time", - "elements.end_time", - "elements.rotation", - "elements.keyframes", - "elements.textdata", - "elements.shapedata", - "elements.imagedata", - "elements.videodata", - "elements.zoomdata", - "elements.codedata", - "elements.parent_id" -]New value: +[ + "elements", + "voiceover_words", + "groups", + "elements.name", + "elements.element_type", + "elements.x", + "elements.y", + "elements.width", + "elements.height", + "elements.start_time", + "elements.end_time", + "elements.rotation", + "elements.keyframes", + "elements.textdata", + "elements.shapedata", + "elements.imagedata", + "elements.videodata", + "elements.zoomdata", + "elements.codedata", + "elements.parent_id" +]
- Changed
get_element_schema4 fields changed- changed
Input schema / properties / element_type / descriptionPrevious value: -"One of: text, callout, rectangle, arrow, blur, spotlight, zoom, image, video, animation"New value: +"One of: text, callout, rectangle, arrow, blur, spotlight, zoom, image, video, animation, group" - changed
Input schema / properties / element_type / enumPrevious value: -[ - "text", - "callout", - "rectangle", - "arrow", - "blur", - "spotlight", - "zoom", - "image", - "video", - "animation" -]New value: +[ + "text", + "callout", + "rectangle", + "arrow", + "blur", + "spotlight", + "zoom", + "image", + "video", + "animation", + "group" +] - added
Input schema / properties / fieldsAdded value: +{ + "description": "Return only these fields, with their prose — text is 15KB whole, ~300 bytes for two. Omit while learning the type: only the full schema carries the keyframable list and the keyframe rules.", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / formatAdded value: +{ + "description": "Defaults to 'declarations' — TypeScript-style, which is the better READ. Inside run_script it defaults to 'json' instead, because a script indexes into the structure and the declaration text would arrive newline-escaped. Set it explicitly to override either default.", + "enum": [ + "declarations", + "json" + ], + "type": "string" +}
- Added
get_script_job - Changed
remove_from_project4 fields changed- added
Input schema / properties / group_idAdded value: +{ + "description": "Group ID to remove (required for target='group')", + "type": "string" +} - added
Input schema / properties / keep_childrenAdded value: +{ + "description": "target='group' only. Omit/true ungroups: children rise to the removed group's own parent. false deletes the whole subtree.", + "type": "boolean" +} - changed
Input schema / properties / target / descriptionPrevious value: -"What to remove: 'element' or 'audio'"New value: +"What to remove: 'element', 'group' or 'audio'" - changed
Input schema / properties / target / enumPrevious value: -[ - "element", - "audio" -]New value: +[ + "element", + "group", + "audio" +]
- Added
run_script - Changed
update_elements10 fields changed- added
Input schema / properties / defaultsAdded value: +{ + "additionalProperties": false, + "description": "Values shared by every item, sent once rather than repeated. Items win per key; type_data merges one level. E.g. defaults:{clip_index:1, element_type:'text', type_data:{font_setting:{font:'Inter',weight:'600'}, alignment:'center'}} then items carry only what differs.", + "properties": { + "clip_id": { + "type": "string" + }, + "clip_index": { + "minimum": 0, + "type": "integer" + }, + "element_type": { + "enum": [ + "text", + "callout", + "rectangle", + "arrow", + "blur", + "spotlight", + "zoom", + "image", + "video", + "animation" + ], + "type": "string" + }, + "end_time": { + "minimum": 0, + "type": "number" + }, + "group": { + "minLength": 1, + "type": "string" + }, + "height": { + "minimum": 0, + "type": "number" + }, + "insert_at": { + "enum": [ + "front", + "back" + ], + "type": "string" + }, + "keyframes": { + "anyOf": [ + { + "items": { + "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items" + }, + "type": "array" + }, + { + "type": "null" + } + ] + }, + "rotation": { + "type": "number" + }, + "start_time": { + "minimum": 0, + "type": "number" + }, + "type_data": { + "additionalProperties": {}, + "type": "object" + }, + "width": { + "minimum": 0, + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "type": "object" +} - added
Input schema / properties / returningAdded value: +{ + "description": "Declare what comes back, the way get_clip's `select` shapes a read. Omit it and you get ids, the measured layout, and the clip audit in compact form — which names every problem but drops the explanatory prose. Values: 'ids' (element_id per result), 'layout' (the measured text fit — font_size_px, text_width_px, natural_width_px, line_count, fits_width/fits_height/fits — `fits` is the WIDTH check (the widest rendered line inside the box), `fits_height` is the separate height one — plus an `adjusted` entry whenever the measured line box replaced the height you sent; widen a box to natural_width_px, NOT text_width_px, which is the widest RENDERED line and so a lower bound on text that is already wrapping), 'qa.codes' (audit counts and summary plus severity/code/element_ids per finding), 'qa' (the same audit with the full message and suggested fix on every finding — ask for this when a code alone isn't enough to act on). ERROR-severity findings always come back with their full message whichever you choose — including `returning:[]` and `['ids']`, which suppress WARNINGS only. A failed item always returns complete. Pass [] for just {total, succeeded, failed} plus any errors, the leanest write.", + "items": { + "enum": [ + "ids", + "layout", + "qa", + "qa.codes" + ], + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / updates / items / properties / clip_index / descriptionPrevious value: -"Zero-based clip index"New value: +"Zero-based clip index. OPTIONAL — `element_id` is unique within the project, so the server finds the clip itself. Pass it only as a fast-path hint; a wrong one is corrected rather than rejected." - changed
Input schema / properties / updates / items / properties / height / descriptionPrevious value: -"New height, pixels (0 allowed)"New value: +"New height, pixels (0 allowed). For text, the space you are giving it — the box resizes to the measured text. See layout.fits_height in the response." - added
Input schema / properties / updates / items / properties / insert_atAdded value: +{ + "anyOf": [ + { + "enum": [ + "front", + "back" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "before": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "before" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "after": { + "minLength": 1, + "type": "string" + } + }, + "required": [ + "after" + ], + "type": "object" + } + ], + "description": "Move this element in z-order, without rebuilding it. `front`/`back` are the ends of the group it is already in (the clip itself for an ungrouped element), so they never change what it belongs to. `{before: element_id}` / `{after: element_id}` sit it next to that element or group and put it in THAT node's group — which is how you move something into or out of a group and position it in one call. Applied after `group` when both are passed." +} - changed
Input schema / properties / updates / items / properties / keyframes / anyOfPrevious value: -[ - { - "items": { - "additionalProperties": false, - "properties": { - "backgroundBlur": { - "description": "Backdrop blur behind the element", - "type": "number" - }, - "bezier": { - "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "bezier_overrides": { - "additionalProperties": { - "items": { - "type": "number" - }, - "maxItems": 4, - "minItems": 4, - "type": "array" - }, - "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ] - }, - "type": "object" - }, - "blur": { - "description": "Layer blur", - "type": "number" - }, - "borderRadiusBottomLeft": { - "description": "borderRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "borderRadiusBottomRight": { - "description": "borderRadiusBottomRight in canvas pixels", - "type": "number" - }, - "borderRadiusTopLeft": { - "description": "borderRadiusTopLeft in canvas pixels", - "type": "number" - }, - "borderRadiusTopRight": { - "description": "borderRadiusTopRight in canvas pixels", - "type": "number" - }, - "fontSize": { - "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", - "type": "number" - }, - "height": { - "description": "Height in canvas pixels (0 allowed)", - "minimum": 0, - "type": "number" - }, - "imageBorderColor": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/strokeColor", - "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "imageBorderWidth": { - "description": "imageBorderWidth in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomLeft": { - "description": "imageCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusBottomRight": { - "description": "imageCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopLeft": { - "description": "imageCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "imageCornerRadiusTopRight": { - "description": "imageCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "interpolation": { - "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", - "enum": [ - "linear", - "easeInOut", - "easeIn", - "easeOut", - "sigmoid", - "smootherstep", - "smoothstep", - "hold", - "easeInBack", - "easeOutBack", - "easeInOutBack", - "custom" - ], - "type": "string" - }, - "interpolation_overrides": { - "additionalProperties": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/interpolation" - }, - "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", - "propertyNames": { - "enum": [ - "positionX", - "positionY", - "width", - "height", - "rotation", - "scaleX", - "scaleY", - "rotateX", - "rotateY", - "opacity", - "blur", - "backgroundBlur", - "strokeWidth", - "strokeDash", - "strokeGap", - "strokeTrimStart", - "strokeTrimEnd", - "strokeTrimOffset", - "textStrokeWidth", - "textStrokeDash", - "textStrokeGap", - "imageBorderWidth", - "shadowOffsetX", - "shadowOffsetY", - "shadowBlur", - "shadowSpread", - "borderRadiusTopLeft", - "borderRadiusTopRight", - "borderRadiusBottomRight", - "borderRadiusBottomLeft", - "imageCornerRadiusTopLeft", - "imageCornerRadiusTopRight", - "imageCornerRadiusBottomRight", - "imageCornerRadiusBottomLeft", - "videoCornerRadiusTopLeft", - "videoCornerRadiusTopRight", - "videoCornerRadiusBottomRight", - "videoCornerRadiusBottomLeft", - "fontSize", - "lineHeight", - "letterSpacing", - "paddingTop", - "paddingRight", - "paddingBottom", - "paddingLeft", - "textBgRadiusTopLeft", - "textBgRadiusTopRight", - "textBgRadiusBottomRight", - "textBgRadiusBottomLeft", - "strokeColor", - "textStrokeColor", - "imageBorderColor", - "textColor", - "textBackgroundColor", - "shadowColor" - ] - }, - "type": "object" - }, - "letterSpacing": { - "description": "Letter spacing in canvas pixels.", - "type": "number" - }, - "lineHeight": { - "description": "lineHeight (native unit)", - "type": "number" - }, - "opacity": { - "description": "Opacity 0-100", - "maximum": 100, - "minimum": 0, - "type": "number" - }, - "paddingBottom": { - "description": "paddingBottom in canvas pixels", - "type": "number" - }, - "paddingLeft": { - "description": "paddingLeft in canvas pixels", - "type": "number" - }, - "paddingRight": { - "description": "paddingRight in canvas pixels", - "type": "number" - }, - "paddingTop": { - "description": "paddingTop in canvas pixels", - "type": "number" - }, - "positionX": { - "description": "X position in canvas pixels (NOT `x`). Uses the SAME alignment-aware origin as the element's top-level x — left-aligned text uses top-left, center-aligned uses CENTER POINT, right-aligned uses top-right; all other types use top-left.", - "type": "number" - }, - "positionY": { - "description": "Y position in canvas pixels (NOT `y`). Origin matches positionX — center-aligned text positions by vertical center.", - "type": "number" - }, - "rotateX": { - "description": "rotateX (native unit)", - "type": "number" - }, - "rotateY": { - "description": "rotateY (native unit)", - "type": "number" - }, - "rotation": { - "description": "Rotation in degrees", - "type": "number" - }, - "scaleX": { - "description": "Horizontal scale multiplier (1 = 100%)", - "type": "number" - }, - "scaleY": { - "description": "Vertical scale multiplier (1 = 100%)", - "type": "number" - }, - "shadowBlur": { - "description": "shadowBlur in canvas pixels", - "type": "number" - }, - "shadowColor": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/strokeColor", - "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "shadowOffsetX": { - "description": "shadowOffsetX in canvas pixels", - "type": "number" - }, - "shadowOffsetY": { - "description": "shadowOffsetY in canvas pixels", - "type": "number" - }, - "shadowSpread": { - "description": "shadowSpread in canvas pixels", - "type": "number" - }, - "strokeColor": { - "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)", - "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", - "type": "string" - }, - "strokeDash": { - "description": "strokeDash in canvas pixels", - "type": "number" - }, - "strokeGap": { - "description": "strokeGap in canvas pixels", - "type": "number" - }, - "strokeTrimEnd": { - "description": "strokeTrimEnd (native unit)", - "type": "number" - }, - "strokeTrimOffset": { - "description": "strokeTrimOffset (native unit)", - "type": "number" - }, - "strokeTrimStart": { - "description": "strokeTrimStart (native unit)", - "type": "number" - }, - "strokeWidth": { - "description": "strokeWidth in canvas pixels", - "type": "number" - }, - "textBackgroundColor": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/strokeColor", - "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textBgRadiusBottomLeft": { - "description": "textBgRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusBottomRight": { - "description": "textBgRadiusBottomRight in canvas pixels", - "type": "number" - }, - "textBgRadiusTopLeft": { - "description": "textBgRadiusTopLeft in canvas pixels", - "type": "number" - }, - "textBgRadiusTopRight": { - "description": "textBgRadiusTopRight in canvas pixels", - "type": "number" - }, - "textColor": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/strokeColor", - "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textStrokeColor": { - "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/strokeColor", - "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)" - }, - "textStrokeDash": { - "description": "textStrokeDash in canvas pixels", - "type": "number" - }, - "textStrokeGap": { - "description": "textStrokeGap in canvas pixels", - "type": "number" - }, - "textStrokeWidth": { - "description": "textStrokeWidth in canvas pixels", - "type": "number" - }, - "timestamp": { - "description": "Clip-relative time in seconds", - "minimum": 0, - "type": "number" - }, - "videoCornerRadiusBottomLeft": { - "description": "videoCornerRadiusBottomLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusBottomRight": { - "description": "videoCornerRadiusBottomRight in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopLeft": { - "description": "videoCornerRadiusTopLeft in canvas pixels", - "type": "number" - }, - "videoCornerRadiusTopRight": { - "description": "videoCornerRadiusTopRight in canvas pixels", - "type": "number" - }, - "width": { - "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", - "minimum": 0, - "type": "number" - } - }, - "required": [ - "timestamp" - ], - "type": "object" - }, - "type": "array" - }, - { - "type": "null" - } -]New value: +[ + { + "items": { + "additionalProperties": false, + "properties": { + "backgroundBlur": { + "description": "Backdrop blur behind the element", + "type": "number" + }, + "bezier": { + "description": "Cubic-bezier [x1,y1,x2,y2]; used when interpolation is 'custom'.", + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "bezier_overrides": { + "additionalProperties": { + "items": { + "type": "number" + }, + "maxItems": 4, + "minItems": 4, + "type": "array" + }, + "description": "Per-property cubic-bezier override, e.g. {\"opacity\":[.4,0,.6,1]}, when two `custom`-eased properties in this entry need DIFFERENT curves. Keys must be properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ] + }, + "type": "object" + }, + "blur": { + "description": "Layer blur", + "type": "number" + }, + "borderRadiusBottomLeft": { + "description": "borderRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "borderRadiusBottomRight": { + "description": "borderRadiusBottomRight in canvas pixels", + "type": "number" + }, + "borderRadiusTopLeft": { + "description": "borderRadiusTopLeft in canvas pixels", + "type": "number" + }, + "borderRadiusTopRight": { + "description": "borderRadiusTopRight in canvas pixels", + "type": "number" + }, + "cropHeight": { + "description": "cropHeight (native unit)", + "type": "number" + }, + "cropWidth": { + "description": "cropWidth (native unit)", + "type": "number" + }, + "cropX": { + "description": "cropX (native unit)", + "type": "number" + }, + "cropY": { + "description": "cropY (native unit)", + "type": "number" + }, + "fillColor": { + "description": "fillColor as #rrggbb or #rrggbbaa (alpha = opacity)", + "pattern": "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$", + "type": "string" + }, + "fontSize": { + "description": "Font size in CANVAS PIXELS (same unit as the top-level fontSize — NOT a fraction).", + "type": "number" + }, + "height": { + "description": "Height in canvas pixels (0 allowed)", + "minimum": 0, + "type": "number" + }, + "imageBorderColor": { + "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "imageBorderColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "imageBorderWidth": { + "description": "imageBorderWidth in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomLeft": { + "description": "imageCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusBottomRight": { + "description": "imageCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopLeft": { + "description": "imageCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "imageCornerRadiusTopRight": { + "description": "imageCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "interpolation": { + "description": "Easing for THIS entry, applied to every property in it (default easeInOut). NOT `easing`.", + "enum": [ + "linear", + "easeInOut", + "easeIn", + "easeOut", + "sigmoid", + "smootherstep", + "smoothstep", + "hold", + "easeInBack", + "easeOutBack", + "easeInOutBack", + "custom" + ], + "type": "string" + }, + "interpolation_overrides": { + "additionalProperties": { + "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/interpolation" + }, + "description": "Per-property easing override, e.g. {\"opacity\":\"linear\"} while the rest use `interpolation`. Keys must be keyframable properties present in this entry.", + "propertyNames": { + "enum": [ + "positionX", + "positionY", + "width", + "height", + "rotation", + "scaleX", + "scaleY", + "rotateX", + "rotateY", + "cropX", + "cropY", + "cropWidth", + "cropHeight", + "opacity", + "blur", + "backgroundBlur", + "strokeWidth", + "strokeDash", + "strokeGap", + "strokeTrimStart", + "strokeTrimEnd", + "strokeTrimOffset", + "textStrokeWidth", + "textStrokeDash", + "textStrokeGap", + "imageBorderWidth", + "shadowOffsetX", + "shadowOffsetY", + "shadowBlur", + "shadowSpread", + "borderRadiusTopLeft", + "borderRadiusTopRight", + "borderRadiusBottomRight", + "borderRadiusBottomLeft", + "imageCornerRadiusTopLeft", + "imageCornerRadiusTopRight", + "imageCornerRadiusBottomRight", + "imageCornerRadiusBottomLeft", + "videoCornerRadiusTopLeft", + "videoCornerRadiusTopRight", + "videoCornerRadiusBottomRight", + "videoCornerRadiusBottomLeft", + "fontSize", + "lineHeight", + "letterSpacing", + "paddingTop", + "paddingRight", + "paddingBottom", + "paddingLeft", + "textBgRadiusTopLeft", + "textBgRadiusTopRight", + "textBgRadiusBottomRight", + "textBgRadiusBottomLeft", + "fillColor", + "strokeColor", + "textStrokeColor", + "imageBorderColor", + "textColor", + "textBackgroundColor", + "shadowColor" + ] + }, + "type": "object" + }, + "letterSpacing": { + "description": "Letter spacing in canvas pixels.", + "type": "number" + }, + "lineHeight": { + "description": "lineHeight (native unit)", + "type": "number" + }, + "opacity": { + "description": "Opacity 0-100", + "maximum": 100, + "minimum": 0, + "type": "number" + }, + "paddingBottom": { + "description": "paddingBottom in canvas pixels", + "type": "number" + }, + "paddingLeft": { + "description": "paddingLeft in canvas pixels", + "type": "number" + }, + "paddingRight": { + "description": "paddingRight in canvas pixels", + "type": "number" + }, + "paddingTop": { + "description": "paddingTop in canvas pixels", + "type": "number" + }, + "positionX": { + "description": "X position in canvas pixels (NOT `x`). Uses the SAME alignment-aware origin as the element's top-level x — left-aligned text uses top-left, center-aligned uses CENTER POINT, right-aligned uses top-right; all other types use top-left.", + "type": "number" + }, + "positionY": { + "description": "Y position in canvas pixels (NOT `y`). Origin matches positionX — center-aligned text positions by vertical center. y_anchor applies to the element's own y, not to keyframe values — keyframes use the alignment origin, so read the element back and key off its stored y.", + "type": "number" + }, + "rotateX": { + "description": "rotateX (native unit)", + "type": "number" + }, + "rotateY": { + "description": "rotateY (native unit)", + "type": "number" + }, + "rotation": { + "description": "Rotation in degrees", + "type": "number" + }, + "scaleX": { + "description": "Horizontal scale multiplier (1 = 100%)", + "type": "number" + }, + "scaleY": { + "description": "Vertical scale multiplier (1 = 100%)", + "type": "number" + }, + "shadowBlur": { + "description": "shadowBlur in canvas pixels", + "type": "number" + }, + "shadowColor": { + "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "shadowColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "shadowOffsetX": { + "description": "shadowOffsetX in canvas pixels", + "type": "number" + }, + "shadowOffsetY": { + "description": "shadowOffsetY in canvas pixels", + "type": "number" + }, + "shadowSpread": { + "description": "shadowSpread in canvas pixels", + "type": "number" + }, + "strokeColor": { + "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "strokeColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "strokeDash": { + "description": "strokeDash in canvas pixels", + "type": "number" + }, + "strokeGap": { + "description": "strokeGap in canvas pixels", + "type": "number" + }, + "strokeTrimEnd": { + "description": "strokeTrimEnd (native unit)", + "type": "number" + }, + "strokeTrimOffset": { + "description": "strokeTrimOffset (native unit)", + "type": "number" + }, + "strokeTrimStart": { + "description": "strokeTrimStart (native unit)", + "type": "number" + }, + "strokeWidth": { + "description": "strokeWidth in canvas pixels", + "type": "number" + }, + "textBackgroundColor": { + "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "textBackgroundColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "textBgRadiusBottomLeft": { + "description": "textBgRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusBottomRight": { + "description": "textBgRadiusBottomRight in canvas pixels", + "type": "number" + }, + "textBgRadiusTopLeft": { + "description": "textBgRadiusTopLeft in canvas pixels", + "type": "number" + }, + "textBgRadiusTopRight": { + "description": "textBgRadiusTopRight in canvas pixels", + "type": "number" + }, + "textColor": { + "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "textColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "textStrokeColor": { + "$ref": "#/properties/updates/items/properties/keyframes/anyOf/0/items/properties/fillColor", + "description": "textStrokeColor as #rrggbb or #rrggbbaa (alpha = opacity)" + }, + "textStrokeDash": { + "description": "textStrokeDash in canvas pixels", + "type": "number" + }, + "textStrokeGap": { + "description": "textStrokeGap in canvas pixels", + "type": "number" + }, + "textStrokeWidth": { + "description": "textStrokeWidth in canvas pixels", + "type": "number" + }, + "timestamp": { + "description": "Clip-relative time in seconds", + "minimum": 0, + "type": "number" + }, + "videoCornerRadiusBottomLeft": { + "description": "videoCornerRadiusBottomLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusBottomRight": { + "description": "videoCornerRadiusBottomRight in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopLeft": { + "description": "videoCornerRadiusTopLeft in canvas pixels", + "type": "number" + }, + "videoCornerRadiusTopRight": { + "description": "videoCornerRadiusTopRight in canvas pixels", + "type": "number" + }, + "width": { + "description": "Width in canvas pixels (0 allowed — e.g. a bar that draws in from 0)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "timestamp" + ], + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } +] - added
Input schema / properties / updates / items / properties / keyframes_repeatAdded value: +{ + "additionalProperties": false, + "description": "Repeat `keyframes` as a cycle — { count, mode?, every? }. Requires `keyframes` in the same call.", + "properties": { + "count": { + "description": "TOTAL number of cycles, INCLUDING the one you wrote. 1 is a no-op. Expansion stops at the clip end rather than piling the overflow onto the last frame, and the generated total is capped at 600 keyframes (it errors rather than silently truncating).", + "minimum": 1, + "type": "integer" + }, + "every": { + "description": "Seconds between cycle STARTS. Defaults to the cycle's own span (back-to-back). A LARGER value holds the last value in the gap — that is how you get a pulse every 2s instead of a constant wobble. Shorter than the cycle is rejected, because the cycles would overlap and collide on the same frames.", + "exclusiveMinimum": 0, + "type": "number" + }, + "mode": { + "description": "'loop' (default) replays the cycle forwards every time — seamless only if your first and last values match. 'pingpong' alternates forwards/backwards, so the value always returns to where it started without a jump; use it for a breathe/pulse written as a one-way ramp.", + "enum": [ + "loop", + "pingpong" + ], + "type": "string" + } + }, + "required": [ + "count" + ], + "type": "object" +} - changed
Input schema / properties / updates / items / properties / width / descriptionPrevious value: -"New width, pixels (0 allowed — e.g. a bar that draws in from 0)"New value: +"New width, pixels (0 allowed — e.g. a bar that draws in from 0). For text this is the wrap width and re-wraps the text." - changed
Input schema / properties / updates / items / properties / y / descriptionPrevious value: -"New Y (canvas pixels). ORIGIN matches x — center-aligned text positions by vertical center."New value: +"New Y (canvas pixels). Takes type_data.y_anchor the same way add_elements does." - changed
Input schema / properties / updates / items / requiredPrevious value: -[ - "clip_index", - "element_id" -]New value: +[ + "element_id" +]
- Added
update_groups - Changed
voiceover_batch1 field changed- changed
Input schema / properties / entries / items / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "action": { - "const": "set_text", - "description": "Write the voiceover transcript onto the clip without generating audio.", - "type": "string" - }, - "clip_index": { - "description": "Zero-based clip index", - "minimum": 0, - "type": "integer" - }, - "text": { - "description": "Voiceover transcript", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "action", - "clip_index", - "text" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "action": { - "const": "generate_speech", - "description": "Generate speech audio from the transcript already set on the clip.", - "type": "string" - }, - "clip_id": { - "description": "Clip ID", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "action", - "clip_id" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "action": { - "const": "set_and_generate", - "description": "Write the transcript and generate its speech audio in one step.", - "type": "string" - }, - "clip_id": { - "description": "Clip ID", - "minLength": 1, - "type": "string" - }, - "clip_index": { - "description": "Zero-based clip index", - "minimum": 0, - "type": "integer" - }, - "text": { - "description": "Voiceover transcript", - "minLength": 1, - "type": "string" - } - }, - "required": [ - "action", - "clip_index", - "clip_id", - "text" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "action": { + "const": "set_text", + "description": "Write the voiceover transcript onto the clip without generating audio.", + "type": "string" + }, + "clip_index": { + "description": "Zero-based clip index", + "minimum": 0, + "type": "integer" + }, + "text": { + "description": "Voiceover transcript", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "action", + "clip_index", + "text" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "action": { + "const": "generate_speech", + "description": "Generate speech audio from the transcript already set on the clip.", + "type": "string" + }, + "clip_id": { + "description": "Clip ID. Give this or clip_index.", + "minLength": 1, + "type": "string" + }, + "clip_index": { + "description": "Zero-based clip index. Give this or clip_id.", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "action" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "action": { + "const": "set_and_generate", + "description": "Write the transcript and generate its speech audio in one step.", + "type": "string" + }, + "clip_id": { + "description": "Clip ID. Give this or clip_index.", + "minLength": 1, + "type": "string" + }, + "clip_index": { + "description": "Zero-based clip index. Give this or clip_id.", + "minimum": 0, + "type": "integer" + }, + "text": { + "description": "Voiceover transcript", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "action", + "text" + ], + "type": "object" + } +]
1 tool update
- Changed
record_screen2 fields changed- added
Input schema / properties / edit_scene_idsAdded value: +{ + "description": "The clip id(s) this edit replaces. Only used when recording_session_id is set; scenes you do not name are not re-filmed. Set preceding_clip_id to the clip you are replacing — an edit naming a clip that is not in the guide is refused rather than appended to the end.", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / recording_session_idAdded value: +{ + "description": "EDIT an existing recording instead of shooting a new one. Pass the recording_session_id from the record_screen that made it, or read it off get_clip. The recorder restores that take's code, notes and click script and changes only what you ask for, which is far faster and cheaper than re-recording. Omit for a fresh recording. Only code-wizard recordings are editable; get_clip omits the field for any clip that is not.", + "type": "string" +}
40 tool updates
- First observed
add_article_media - First observed
add_audio - First observed
add_clips - First observed
add_comment - First observed
add_elements - First observed
add_sync_point - First observed
analyze_audio - First observed
auto_sync - First observed
check_uploads - First observed
create_clueprint - First observed
create_project - First observed
duplicate_clip - First observed
duplicate_project - First observed
estimate_duration - First observed
export_project - First observed
find - First observed
generate_media - First observed
get_article - First observed
get_clip - First observed
get_clueprint - First observed
get_design_guide - First observed
get_element_schema - First observed
get_project - First observed
record_screen - First observed
remove_clip - First observed
remove_elements - First observed
remove_from_project - First observed
reorder_elements - First observed
set_voice - First observed
split_clip - First observed
switch_workspace - First observed
update_article - First observed
update_article_media - First observed
update_audio - First observed
update_clips - First observed
update_clueprint - First observed
update_elements - First observed
update_project - First observed
upload_file - First observed
voiceover_batch
Related MCP Connectors
Generate and edit images, video, voice, lip-sync and 3D models from your AI agent.
Give your AI agents a design superpower. Generate, edit, and publish publication-grade decks, reports, landing pages, resumes, and marketing visuals directly within your agent workflow. Delivering frontier-level design quality at 3× the speed and 53× lower cost -from conversational prompt to live link or vector PDF in minutes.
Turn URLs, recordings, docs, assets, or ideas into launch films, demo recordings, and decks.
On-brand creative studio for AI agents: images, video, audio, and 3D.
Related MCP Servers
AlicenseNot gradedqualityDmaintenanceA creative agent that plans and executes across image, video, and audio. Uses 30+ tools, orchestrates 20+ AI models, and does agentic timeline editing.MIT- AlicenseNot gradedqualityAmaintenanceEnables AI agents to generate narrated videos from topics or scripts, with stock footage, home videos, or local AI clips.2MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to autonomously edit raw video footage into publish-ready videos with millisecond-accurate cuts, Whisper transcription, karaoke captions, motion graphics, and high-CTR thumbnails.3 npm4MIT
- FlicenseNot gradedqualityBmaintenanceEnables AI agents to author presentations, reports, and one-pagers as visual documents that humans can edit in a WYSIWYG editor and export to a single HTML file.-
Glama MCP Gateway
Add one secure layer between your agents and this server.