← WebMCP Directory

Tool tree

deskmate-cc.vercel.app

Media & PersonalTools verified
Website
Deskmate
Explore capabilities
    get_desktop_stateAnswer

    Return which apps and folders exist on this desktop, which windows are open, and which one has focus, plus what this browser lets the page do. Call it first: what the user is looking at decides whether they are writing, filming or editing, and a note about the timeline is useless to someone standing in front of a camera.

    View tool JSON
    {
      "name": "get_desktop_state",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return which apps and folders exist on this desktop, which windows are open, and which one has focus, plus what this browser lets the page do. Call it first: what the user is looking at decides whether they are writing, filming or editing, and a note about the timeline is useless to someone standing in front of a camera.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    list_scriptsAnswer

    Return every script saved on this desktop with its title, how many lines it has and its estimated spoken runtime. A line is one spoken beat plus an optional shot direction, and it is the unit the teleprompter advances through. Returns titles and lengths, not the words; call get_script for those.

    View tool JSON
    {
      "name": "list_scripts",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return every script saved on this desktop with its title, how many lines it has and its estimated spoken runtime. A line is one spoken beat plus an optional shot direction, and it is the unit the teleprompter advances through. Returns titles and lengths, not the words; call get_script for those.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    get_scriptAnswer

    Return one saved script in full: every line with what is said out loud, its shot direction, and how long that line takes to say. Read it before suggesting anything about the take or the edit, because the shot directions say what the footage is meant to show.

    View tool JSON
    {
      "name": "get_script",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return one saved script in full: every line with what is said out loud, its shot direction, and how long that line takes to say. Read it before suggesting anything about the take or the edit, because the shot directions say what the footage is meant to show.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "script_id": {
            "type": "string",
            "description": "Id from list_scripts."
          }
        },
        "required": [
          "script_id"
        ],
        "additionalProperties": false
      }
    }
    get_open_scriptAnswer

    Return the script the writer has open in front of them right now, taken from the live fields rather than the saved record, so a line they are still typing is included. Says which line and which field their caret is in and what they have selected. Use this before answering anything phrased as 'this line', 'what I just wrote', or 'this bit'.

    View tool JSON
    {
      "name": "get_open_script",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the script the writer has open in front of them right now, taken from the live fields rather than the saved record, so a line they are still typing is included. Says which line and which field their caret is in and what they have selected. Use this before answering anything phrased as 'this line', 'what I just wrote', or 'this bit'.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    get_prompter_stateAnswer

    Return what the teleprompter is showing at this instant: the line the speaker is on, its shot direction, how far through the script they are, and whether it is scrolling or paused. Only meaningful while the prompter is up. If it is running, the person is mid-performance: keep any answer to one short sentence, or say nothing.

    View tool JSON
    {
      "name": "get_prompter_state",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return what the teleprompter is showing at this instant: the line the speaker is on, its shot direction, how far through the script they are, and whether it is scrolling or paused. Only meaningful while the prompter is up. If it is running, the person is mid-performance: keep any answer to one short sentence, or say nothing.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    get_recorder_stateAnswer

    Return what the Camera is doing right now: idle, armed with a live preview, or recording, how many seconds into the take it is, and the teleprompter script loaded into it with the exact line they are on. Check this before suggesting anything. Someone mid-take cannot read a paragraph of advice, and you cannot start or stop a recording yourself.

    View tool JSON
    {
      "name": "get_recorder_state",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return what the Camera is doing right now: idle, armed with a live preview, or recording, how many seconds into the take it is, and the teleprompter script loaded into it with the exact line they are on. Check this before suggesting anything. Someone mid-take cannot read a paragraph of advice, and you cannot start or stop a recording yourself.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    list_clipsAnswer

    Return the clip library: everything recorded or imported on this desktop, oldest first, including sound files, which have kind "audio". Each clip says which of the person's own library folders it is in, if any. Clips are held in this browser and have never been uploaded anywhere, so this is the only place they can be listed.

    View tool JSON
    {
      "name": "list_clips",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the clip library: everything recorded or imported on this desktop, oldest first, including sound files, which have kind \"audio\". Each clip says which of the person's own library folders it is in, if any. Clips are held in this browser and have never been uploaded anywhere, so this is the only place they can be listed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "recording",
              "import",
              "export",
              "screen",
              "audio"
            ],
            "description": "Optional. Restrict to one kind of clip. Sound files are \"audio\"."
          }
        },
        "additionalProperties": false
      }
    }
    get_timelineAnswer

    Return the cut as it stands: every segment in order with its in and out points, look, speed and where it starts in the finished piece. This is the working edit, not the clip library. Use list_clips for what is available to add.

    View tool JSON
    {
      "name": "get_timeline",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the cut as it stands: every segment in order with its in and out points, look, speed and where it starts in the finished piece. This is the working edit, not the clip library. Use list_clips for what is available to add.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    get_selectionAnswer

    Return the segment the user currently has selected in the Editor. Use this before answering anything phrased as 'this clip', 'this bit', or 'tighten this'. Nothing outside this tab knows what is selected.

    View tool JSON
    {
      "name": "get_selection",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the segment the user currently has selected in the Editor. Use this before answering anything phrased as 'this clip', 'this bit', or 'tighten this'. Nothing outside this tab knows what is selected.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    get_playheadAnswer

    Return where the playhead is in the Editor preview and which segment sits under it. Use it to talk about the moment the user is actually looking at.

    View tool JSON
    {
      "name": "get_playhead",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return where the playhead is in the Editor preview and which segment sits under it. Use it to talk about the moment the user is actually looking at.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    get_graphicsAnswer

    Return the motion graphics on this cut, both the ones you have proposed and the ones the editor has accepted, with their timings and settings. Call it before proposing, so you build on what is there instead of stacking a second title card on top of the first.

    View tool JSON
    {
      "name": "get_graphics",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the motion graphics on this cut, both the ones you have proposed and the ones the editor has accepted, with their timings and settings. Call it before proposing, so you build on what is there instead of stacking a second title card on top of the first.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    propose_graphicAction

    Propose a motion graphic over the cut. It appears immediately on the timeline as a dashed, unconfirmed overlay the editor can watch and then accept or reject; it is not in the video until they accept it. Choose a type from: lower_third: A name and a role sliding in at the lower left. For introducing a person or a place. title_card: A full-frame headline over a wash. For a chapter break or the opening line. caption_pop: Words appearing one at a time along the bottom, in time with speech. For a line worth landing. callout_arrow: An arrow and a label pointing at a spot in the frame. For a screen recording, or anything you need someone to look at. stat_badge: A number that counts up, with a label under it. For a figure you say out loud. progress_bar: A bar filling across the bottom over its own duration. For a walkthrough with steps. Call get_timeline first so the timing lands on the right moment, and get_selection if they asked for it over "this bit".

    View tool JSON
    {
      "name": "propose_graphic",
      "kind": "act",
      "impl": "imperative",
      "description": "Propose a motion graphic over the cut. It appears immediately on the timeline as a dashed, unconfirmed overlay the editor can watch and then accept or reject; it is not in the video until they accept it. Choose a type from: lower_third: A name and a role sliding in at the lower left. For introducing a person or a place. title_card: A full-frame headline over a wash. For a chapter break or the opening line. caption_pop: Words appearing one at a time along the bottom, in time with speech. For a line worth landing. callout_arrow: An arrow and a label pointing at a spot in the frame. For a screen recording, or anything you need someone to look at. stat_badge: A number that counts up, with a label under it. For a figure you say out loud. progress_bar: A bar filling across the bottom over its own duration. For a walkthrough with steps. Call get_timeline first so the timing lands on the right moment, and get_selection if they asked for it over \"this bit\".",
      "inputSchema": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "lower_third",
              "title_card",
              "caption_pop",
              "callout_arrow",
              "stat_badge",
              "progress_bar"
            ]
          },
          "text": {
            "type": "string",
            "maxLength": 90,
            "description": "The words that appear on screen. Not a description of them. Short: this is a graphic, not a paragraph."
          },
          "subtext": {
            "type": "string",
            "maxLength": 90,
            "description": "Optional second line: a role, a source, a label under a number."
          },
          "start": {
            "type": "number",
            "minimum": 0,
            "description": "Seconds from the start of the finished cut, from get_timeline."
          },
          "duration": {
            "type": "number",
            "minimum": 0.2,
            "maximum": 30,
            "description": "Seconds on screen. Default 4."
          },
          "position": {
            "type": "string",
            "enum": [
              "lower_left",
              "lower_right",
              "upper_left",
              "upper_right",
              "center",
              "bottom_bar"
            ]
          },
          "palette_role": {
            "type": "string",
            "enum": [
              "accent",
              "warm",
              "cool",
              "positive",
              "plain"
            ],
            "description": "A role, not a colour. The theme decides what it looks like, so this works in light and dark."
          },
          "easing": {
            "type": "string",
            "enum": [
              "out",
              "in_out",
              "linear"
            ]
          },
          "point": {
            "type": "object",
            "description": "callout_arrow only. Where to aim, as fractions of the frame: {x: 0.5, y: 0.5} is the middle.",
            "properties": {
              "x": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "y": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              }
            },
            "required": [
              "x",
              "y"
            ],
            "additionalProperties": false
          },
          "reason": {
            "type": "string",
            "maxLength": 200,
            "description": "One sentence, shown to the editor on the card. Why this, here."
          }
        },
        "required": [
          "type",
          "start"
        ],
        "additionalProperties": false
      }
    }
    propose_graphic_changeAction

    Propose a change to a graphic that is already on the cut: retime it, move it, reword it, recolour it. The original stays exactly as it is until the editor accepts the change, so rejecting costs them nothing. Send only the fields you are changing.

    View tool JSON
    {
      "name": "propose_graphic_change",
      "kind": "act",
      "impl": "imperative",
      "description": "Propose a change to a graphic that is already on the cut: retime it, move it, reword it, recolour it. The original stays exactly as it is until the editor accepts the change, so rejecting costs them nothing. Send only the fields you are changing.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "graphic_id": {
            "type": "string",
            "description": "Id from get_graphics."
          },
          "text": {
            "type": "string",
            "maxLength": 90
          },
          "subtext": {
            "type": "string",
            "maxLength": 90
          },
          "start": {
            "type": "number",
            "minimum": 0
          },
          "duration": {
            "type": "number",
            "minimum": 0.2,
            "maximum": 30
          },
          "position": {
            "type": "string",
            "enum": [
              "lower_left",
              "lower_right",
              "upper_left",
              "upper_right",
              "center",
              "bottom_bar"
            ]
          },
          "palette_role": {
            "type": "string",
            "enum": [
              "accent",
              "warm",
              "cool",
              "positive",
              "plain"
            ]
          },
          "easing": {
            "type": "string",
            "enum": [
              "out",
              "in_out",
              "linear"
            ]
          },
          "reason": {
            "type": "string",
            "maxLength": 200
          }
        },
        "required": [
          "graphic_id"
        ],
        "additionalProperties": false
      }
    }
    propose_script_lineAction

    Write a line into the draft the person has open: a new beat, or a rewrite of one that is already there. It appears in their Draft view, at the line you aimed it at, as a dashed suggestion they accept or discard; it is not in their script until they do. This is where writing and researching happen, so it is where suggestions belong. Call get_open_script first, so you write from their research and their current draft rather than from memory, and so you do not repeat a line already waiting for them. One line per call: a beat is one thing said to camera, not a paragraph. Several lines is several calls, in order.

    View tool JSON
    {
      "name": "propose_script_line",
      "kind": "act",
      "impl": "imperative",
      "description": "Write a line into the draft the person has open: a new beat, or a rewrite of one that is already there. It appears in their Draft view, at the line you aimed it at, as a dashed suggestion they accept or discard; it is not in their script until they do. This is where writing and researching happen, so it is where suggestions belong. Call get_open_script first, so you write from their research and their current draft rather than from memory, and so you do not repeat a line already waiting for them. One line per call: a beat is one thing said to camera, not a paragraph. Several lines is several calls, in order.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 320,
            "description": "The words they say out loud. Their voice, not yours, and short enough to say in one breath."
          },
          "note": {
            "type": "string",
            "maxLength": 160,
            "description": "Optional shot direction for this beat: camera, b-roll, tone, what is on screen."
          },
          "index": {
            "type": "integer",
            "minimum": 0,
            "description": "Which line this concerns, from get_open_script. With mode 'insert' the line lands before this one, so 0 is a new opening and the line count appends at the end."
          },
          "mode": {
            "type": "string",
            "enum": [
              "insert",
              "replace"
            ],
            "description": "'insert' adds a beat, 'replace' offers a rewrite of the line at index. Default insert."
          },
          "reason": {
            "type": "string",
            "maxLength": 200,
            "description": "One sentence shown under the suggestion. Why this line, here."
          }
        },
        "required": [
          "text",
          "index"
        ],
        "additionalProperties": false
      }
    }
    offer_folderAction

    Tell this page about a folder you have access to, so it can offer to import it. Send the folder's name and a list of what is in it; the page draws it on the desktop as a ghost folder the person can accept or ignore. For text files (.txt, .md, .srt, .vtt) you may include the contents and they land immediately as scripts. Do not try to send video: it will not fit, and the page asks the person to point the browser at the folder instead. This does not read anything from their machine and does not import anything by itself.

    View tool JSON
    {
      "name": "offer_folder",
      "kind": "act",
      "impl": "imperative",
      "description": "Tell this page about a folder you have access to, so it can offer to import it. Send the folder's name and a list of what is in it; the page draws it on the desktop as a ghost folder the person can accept or ignore. For text files (.txt, .md, .srt, .vtt) you may include the contents and they land immediately as scripts. Do not try to send video: it will not fit, and the page asks the person to point the browser at the folder instead. This does not read anything from their machine and does not import anything by itself.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 60,
            "description": "The folder's name as they would recognise it."
          },
          "files": {
            "type": "array",
            "minItems": 1,
            "maxItems": 60,
            "description": "What is in the folder. Names only, unless it is a text file you can include.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200,
                  "description": "File name including its extension."
                },
                "size": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "Bytes, if you know. Shown to them, never used to decide anything."
                },
                "text": {
                  "type": "string",
                  "maxLength": 20000,
                  "description": "Text files only. The contents, which become a script with one line per paragraph. Omit for video."
                }
              },
              "required": [
                "name"
              ],
              "additionalProperties": false
            }
          },
          "reason": {
            "type": "string",
            "maxLength": 200,
            "description": "One sentence, shown when they hover it. Why this folder is worth importing."
          }
        },
        "required": [
          "name",
          "files"
        ],
        "additionalProperties": false
      }
    }
    get_offered_foldersAnswer

    Return the folders you have offered this page and whether the person accepted them. Check it before offering again, so you do not offer the same folder twice, and to find out whether the files you expected are actually in their library now.

    View tool JSON
    {
      "name": "get_offered_folders",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the folders you have offered this page and whether the person accepted them. Check it before offering again, so you do not offer the same folder twice, and to find out whether the files you expected are actually in their library now.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    list_ai_skillsAnswer

    Return the skills this workstation offers you: name, when to use it, and how long it is. These are instructions the person put here for you, about how they want this kind of work done. Call this early, once, and remember what is on the list. It returns descriptions only, so it is cheap; when one of them matches what you have been asked to do, call load_ai_skill to get it.

    View tool JSON
    {
      "name": "list_ai_skills",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the skills this workstation offers you: name, when to use it, and how long it is. These are instructions the person put here for you, about how they want this kind of work done. Call this early, once, and remember what is on the list. It returns descriptions only, so it is cheap; when one of them matches what you have been asked to do, call load_ai_skill to get it.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    load_ai_skillAction

    Return the full text of one skill from list_ai_skills, so you can follow it. Load a skill when its 'use_when' matches the task in front of you, not speculatively. Once loaded, treat it as the person's instruction for this kind of work and apply it for the rest of the session; they can see which skills you have taken.

    View tool JSON
    {
      "name": "load_ai_skill",
      "kind": "act",
      "impl": "imperative",
      "description": "Return the full text of one skill from list_ai_skills, so you can follow it. Load a skill when its 'use_when' matches the task in front of you, not speculatively. Once loaded, treat it as the person's instruction for this kind of work and apply it for the rest of the session; they can see which skills you have taken.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "skill_id": {
            "type": "string",
            "description": "Id from list_ai_skills."
          }
        },
        "required": [
          "skill_id"
        ],
        "additionalProperties": false
      }
    }
    get_compositionAnswer

    Return the motion graphics, sound and format layered over the cut, with every timing in both seconds and frames. Call it before proposing anything so you build on what is there instead of stacking a second title card on the first, and so you know the format: a graphic laid out for 16:9 reads differently once the same composition is reframed to 9:16.

    View tool JSON
    {
      "name": "get_composition",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the motion graphics, sound and format layered over the cut, with every timing in both seconds and frames. Call it before proposing anything so you build on what is there instead of stacking a second title card on the first, and so you know the format: a graphic laid out for 16:9 reads differently once the same composition is reframed to 9:16.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    get_transcriptAnswer

    Return what is said in the cut, word by word, with the second each word lands on. The timing comes from the teleprompter: the Camera recorded which script line was on screen at which second of the take, so this is derived from what they actually performed, not guessed from the page. Times are positions in the finished edit, already adjusted for every trim, reorder and speed change, so a time from here can be handed straight to propose_layer or propose_cut. Pass `quote` to locate a specific phrase.

    View tool JSON
    {
      "name": "get_transcript",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return what is said in the cut, word by word, with the second each word lands on. The timing comes from the teleprompter: the Camera recorded which script line was on screen at which second of the take, so this is derived from what they actually performed, not guessed from the page. Times are positions in the finished edit, already adjusted for every trim, reorder and speed change, so a time from here can be handed straight to propose_layer or propose_cut. Pass `quote` to locate a specific phrase.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "quote": {
            "type": "string",
            "maxLength": 200,
            "description": "Optional. Words to find, as they were said. Case and punctuation are ignored. Returns every occurrence with exact start and end seconds, which is how you turn 'the bit where I talk about the stack' into a range."
          },
          "include_words": {
            "type": "boolean",
            "description": "Optional. Include the full word-by-word array. Default false, which returns the text and the beats and is usually enough; ask for words when you need to time a caption to individual words."
          }
        },
        "additionalProperties": false
      }
    }
    get_composition_codeAnswer

    Return the composition as the TSX file it compiles to: one Sequence per graphic, with the exact frame it starts on and how many frames it runs for. Read it when you need to reason about the composition as a whole rather than one layer at a time, or to quote a specific line back to the person you are helping.

    View tool JSON
    {
      "name": "get_composition_code",
      "kind": "answer",
      "impl": "imperative",
      "description": "Return the composition as the TSX file it compiles to: one Sequence per graphic, with the exact frame it starts on and how many frames it runs for. Read it when you need to reason about the composition as a whole rather than one layer at a time, or to quote a specific line back to the person you are helping.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      }
    }
    propose_layerAction

    Propose a motion graphic over the cut. It appears at once on the timeline as a dashed, unconfirmed layer that previews live, and it is not in the video until the editor accepts it. Choose from: title_card: A full-frame headline over a dimmed wash, with an optional line under it. For an opening or a chapter break. lower_third: A name and a role on a panel at the lower left. For introducing a person, a place or a tool. caption_pop: Words appearing one at a time along the bottom, in time with speech. Pass word timings from the transcript and each word lands on the frame it is said. bullet_list: A titled list whose rows arrive one at a time. For anything you say as 'three things' or 'first, second, third'. comparison_cards: Two or three bordered cards side by side, each with a heading and a line. For 'before and after', 'this versus that', or a set of options. process_flow: Numbered steps joined by a line, revealed one at a time. For a process, a pipeline, or anything you narrate as a sequence. stat_badge: A number that counts up from zero, with a label under it. For a figure you say out loud and want to land. callout_arrow: A label with an arrow pointing at a spot in the frame. For a screen recording, or anything you need someone to look at. progress_bar: A bar filling across the bottom over its own duration, with an optional label. For a walkthrough with steps, or a chapter you want a sense of the length of. code_card: Monospaced lines on a dark panel, arriving one at a time. For a command, a snippet, a file tree, or a stack you are listing out. quote_card: An oversized quote mark, the line, and who said it. For something worth attributing, or your own sentence worth repeating on screen. text: Free text you control completely: typeface, size, colour, alignment, tracking, a plate behind it, an outline, and how it enters and leaves. Use this when none of the preset graphics fit, or when the styling is the point. shape: A rectangle, ellipse, pill, triangle, line, arrow, ring or star, in any colour, anywhere in the frame, at any size and rotation. The building block for anything the preset graphics do not cover. effect: A full-frame look over the picture: a dip to a colour (the transition to put over a cut), a flash, vignette, grain, scanlines, glitch, letterbox bars or a colour wash. Drawn over the frame, so the preview and the exported file are identical. For anything the preset graphics do not cover, use 'text' (full control of typeface, size, colour, alignment and animation), 'shape' (rectangles, ellipses, pills, triangles, lines, arrows, rings and stars in any colour and rotation) or 'effect' (flash, vignette, grain, scanlines, glitch, letterbox, wash). Colour is a palette role or a hex. Call get_composition first for the format and what is already there, and get_transcript if they asked for it over something they said.

    View tool JSON
    {
      "name": "propose_layer",
      "kind": "act",
      "impl": "imperative",
      "description": "Propose a motion graphic over the cut. It appears at once on the timeline as a dashed, unconfirmed layer that previews live, and it is not in the video until the editor accepts it. Choose from: title_card: A full-frame headline over a dimmed wash, with an optional line under it. For an opening or a chapter break. lower_third: A name and a role on a panel at the lower left. For introducing a person, a place or a tool. caption_pop: Words appearing one at a time along the bottom, in time with speech. Pass word timings from the transcript and each word lands on the frame it is said. bullet_list: A titled list whose rows arrive one at a time. For anything you say as 'three things' or 'first, second, third'. comparison_cards: Two or three bordered cards side by side, each with a heading and a line. For 'before and after', 'this versus that', or a set of options. process_flow: Numbered steps joined by a line, revealed one at a time. For a process, a pipeline, or anything you narrate as a sequence. stat_badge: A number that counts up from zero, with a label under it. For a figure you say out loud and want to land. callout_arrow: A label with an arrow pointing at a spot in the frame. For a screen recording, or anything you need someone to look at. progress_bar: A bar filling across the bottom over its own duration, with an optional label. For a walkthrough with steps, or a chapter you want a sense of the length of. code_card: Monospaced lines on a dark panel, arriving one at a time. For a command, a snippet, a file tree, or a stack you are listing out. quote_card: An oversized quote mark, the line, and who said it. For something worth attributing, or your own sentence worth repeating on screen. text: Free text you control completely: typeface, size, colour, alignment, tracking, a plate behind it, an outline, and how it enters and leaves. Use this when none of the preset graphics fit, or when the styling is the point. shape: A rectangle, ellipse, pill, triangle, line, arrow, ring or star, in any colour, anywhere in the frame, at any size and rotation. The building block for anything the preset graphics do not cover. effect: A full-frame look over the picture: a dip to a colour (the transition to put over a cut), a flash, vignette, grain, scanlines, glitch, letterbox bars or a colour wash. Drawn over the frame, so the preview and the exported file are identical. For anything the preset graphics do not cover, use 'text' (full control of typeface, size, colour, alignment and animation), 'shape' (rectangles, ellipses, pills, triangles, lines, arrows, rings and stars in any colour and rotation) or 'effect' (flash, vignette, grain, scanlines, glitch, letterbox, wash). Colour is a palette role or a hex. Call get_composition first for the format and what is already there, and get_transcript if they asked for it over something they said.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "component": {
            "type": "string",
            "enum": [
              "title_card",
              "lower_third",
              "caption_pop",
              "bullet_list",
              "comparison_cards",
              "process_flow",
              "stat_badge",
              "callout_arrow",
              "progress_bar",
              "code_card",
              "quote_card",
              "text",
              "shape",
              "effect"
            ]
          },
          "text": {
            "type": "string",
            "description": "title_card, lower_third, caption_pop, bullet_list, comparison_cards, process_flow, stat_badge, callout_arrow, progress_bar, code_card, quote_card, text only. The figure, with its furniture: '40%', '$1.2M', '3×'. The number inside is what counts up.",
            "maxLength": 24
          },
          "subtext": {
            "type": "string",
            "description": "title_card, lower_third, stat_badge, quote_card only. The role, the title, the one-line description.",
            "maxLength": 80
          },
          "eyebrow": {
            "type": "string",
            "description": "title_card only. A small tracked label above it: a chapter number, a section name.",
            "maxLength": 32
          },
          "font": {
            "type": "string",
            "description": "title_card, lower_third, caption_pop, bullet_list, stat_badge, quote_card, text only. The headline's typeface. One of: display, displayHeavy, body, bodyBold, mono. Defaults to displayHeavy; the eyebrow and subtext keep their own weight."
          },
          "timings": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 0
            },
            "maxItems": 40,
            "description": "caption_pop only. Optional. One frame number per word, from get_transcript, relative to this layer's start. Without it the words are spread evenly, which is close but never exact."
          },
          "items": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 3
            },
            "maxItems": 6,
            "description": "bullet_list, comparison_cards, process_flow, code_card only. One entry per card. Write each as 'Heading: the line under it'; a colon, en dash, or pipe splits them."
          },
          "point": {
            "type": "object",
            "description": "callout_arrow, text, shape only. Free placement as fractions of the frame: {x: 0.5, y: 0.5} is the middle. Leave it out to use `position` instead.",
            "properties": {
              "x": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "y": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              }
            },
            "required": [
              "x",
              "y"
            ],
            "additionalProperties": false
          },
          "size": {
            "type": "number",
            "description": "text only. Type size in points of a 1080-tall frame, 12 to 220. It scales with the format, so one number is right in every aspect ratio."
          },
          "align": {
            "type": "string",
            "description": "text only. left, center or right. Also decides which way the block grows from its anchor."
          },
          "tracking": {
            "type": "number",
            "description": "text only. Letter spacing as a fraction of the size, -0.05 to 0.4. Small caps labels want about 0.07."
          },
          "line_height": {
            "type": "number",
            "description": "text only. Multiple of the size, 0.8 to 2.4. Defaults to 1.18."
          },
          "backdrop": {
            "type": "string",
            "description": "text only. none, box, or scrim. A box is a plate behind the words; a scrim dims the whole frame so text over busy footage stays readable."
          },
          "outline": {
            "type": "number",
            "description": "text only. Outline thickness in points of a 1080 frame, 0 to 12. Reads on any background, which a plate does not."
          },
          "rotation": {
            "type": "number",
            "description": "text, shape only. Degrees, -180 to 180."
          },
          "opacity": {
            "type": "number",
            "description": "text, shape only. 0 to 1. Below 1 the words are see-through, for a watermark or a caption you do not want to fight the picture."
          },
          "animation": {
            "type": "string",
            "description": "text, shape, effect only. How it enters and leaves: fade, rise, drop, slide_left, slide_right, pop, grow, none."
          },
          "shape": {
            "type": "string",
            "description": "shape only. rect, ellipse, pill, triangle, line, arrow, ring or star."
          },
          "width": {
            "type": "number",
            "description": "shape only. As a fraction of the frame width, 0.01 to 1.5."
          },
          "height": {
            "type": "number",
            "description": "shape only. As a fraction of the frame height, 0.01 to 1.5."
          },
          "fill": {
            "type": "string",
            "description": "shape only. A hex like \"#F54E00\", a palette role, or \"none\" for an outline only."
          },
          "stroke": {
            "type": "string",
            "description": "shape only. Outline colour: a hex, a palette role, or \"none\"."
          },
          "stroke_width": {
            "type": "number",
            "description": "shape only. Outline thickness in points of a 1080 frame, 0 to 40."
          },
          "radius": {
            "type": "number",
            "description": "shape only. Corner rounding for a rect, in points of a 1080 frame."
          },
          "effect": {
            "type": "string",
            "description": "effect only. dip, flash, vignette, grain, scanlines, glitch, letterbox or wash. `dip` fades to the colour and back out, which is the transition you put over a cut."
          },
          "strength": {
            "type": "number",
            "description": "effect only. 0 to 1. Half is usually plenty; grain above 0.4 is a stylistic choice rather than an accident."
          },
          "tag": {
            "type": "string",
            "description": "effect only. An internal label. The editor uses it to find the transition it put on a clip; leave it out.",
            "maxLength": 60
          },
          "at_seconds": {
            "type": "number",
            "minimum": 0,
            "description": "Seconds from the start of the finished cut. From get_timeline or get_transcript."
          },
          "duration_seconds": {
            "type": "number",
            "minimum": 0.2,
            "maximum": 30,
            "description": "Seconds on screen. Leave it out for the component's own sensible default."
          },
          "position": {
            "type": "string",
            "enum": [
              "lower_left",
              "lower_right",
              "upper_left",
              "upper_right",
              "center",
              "bottom_bar",
              "top_bar"
            ],
            "description": "A named anchor. For `text` and `shape` you can send `point` instead and place it anywhere."
          },
          "palette_role": {
            "type": "string",
            "description": "A palette role, or a hex like \"#F54E00\". Roles resolve against the live theme, so one spec is legible in light and dark; send a hex when the exact colour is the point. Roles: accent, warm, cool, positive, plain, invert."
          },
          "easing": {
            "type": "string",
            "enum": [
              "linear",
              "out",
              "in_out",
              "spring_out"
            ]
          },
          "reason": {
            "type": "string",
            "maxLength": 200,
            "description": "One sentence, shown to the editor on the card. Why this, here."
          }
        },
        "required": [
          "component",
          "at_seconds"
        ],
        "additionalProperties": false
      }
    }
    propose_blank_clipAction

    Propose a blank clip on the timeline: a solid colour that takes up time, for building motion graphics on when there is no footage to put them over. Stage this first when they ask for a title sequence, an animated card or a graphics-only piece, then propose layers over it with propose_layer. It appears as a dashed block on the base track and is not part of the cut until the editor accepts it.

    View tool JSON
    {
      "name": "propose_blank_clip",
      "kind": "act",
      "impl": "imperative",
      "description": "Propose a blank clip on the timeline: a solid colour that takes up time, for building motion graphics on when there is no footage to put them over. Stage this first when they ask for a title sequence, an animated card or a graphics-only piece, then propose layers over it with propose_layer. It appears as a dashed block on the base track and is not part of the cut until the editor accepts it.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "seconds": {
            "type": "number",
            "minimum": 0.5,
            "maximum": 60,
            "description": "How long it lasts. Five is a sensible title card."
          },
          "colour": {
            "type": "string",
            "description": "The ground, as a hex like \"#101018\". Leave it out for the theme's own dark ground, which is the safe choice."
          },
          "reason": {
            "type": "string",
            "maxLength": 200,
            "description": "One sentence, shown to the editor. Why this, here."
          }
        },
        "required": [
          "seconds"
        ],
        "additionalProperties": false
      }
    }
    propose_layer_changeAction

    Propose a change to a layer that is already on the cut: retime it, move it, reword it, recolour it. The original stays exactly as it is until the editor accepts the change, so rejecting costs them nothing. Send only the fields you are changing; everything else is kept.

    View tool JSON
    {
      "name": "propose_layer_change",
      "kind": "act",
      "impl": "imperative",
      "description": "Propose a change to a layer that is already on the cut: retime it, move it, reword it, recolour it. The original stays exactly as it is until the editor accepts the change, so rejecting costs them nothing. Send only the fields you are changing; everything else is kept.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "layer_id": {
            "type": "string",
            "description": "Id from get_composition."
          },
          "component": {
            "type": "string",
            "enum": [
              "title_card",
              "lower_third",
              "caption_pop",
              "bullet_list",
              "comparison_cards",
              "process_flow",
              "stat_badge",
              "callout_arrow",
              "progress_bar",
              "code_card",
              "quote_card",
              "text",
              "shape",
              "effect"
            ],
            "description": "Change what kind of graphic it is. The fields it takes change with it."
          },
          "text": {
            "type": "string",
            "description": "title_card, lower_third, caption_pop, bullet_list, comparison_cards, process_flow, stat_badge, callout_arrow, progress_bar, code_card, quote_card, text only. The figure, with its furniture: '40%', '$1.2M', '3×'. The number inside is what counts up.",
            "maxLength": 24
          },
          "subtext": {
            "type": "string",
            "description": "title_card, lower_third, stat_badge, quote_card only. The role, the title, the one-line description.",
            "maxLength": 80
          },
          "eyebrow": {
            "type": "string",
            "description": "title_card only. A small tracked label above it: a chapter number, a section name.",
            "maxLength": 32
          },
          "font": {
            "type": "string",
            "description": "title_card, lower_third, caption_pop, bullet_list, stat_badge, quote_card, text only. The headline's typeface. One of: display, displayHeavy, body, bodyBold, mono. Defaults to displayHeavy; the eyebrow and subtext keep their own weight."
          },
          "timings": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 0
            },
            "maxItems": 40,
            "description": "caption_pop only. Optional. One frame number per word, from get_transcript, relative to this layer's start. Without it the words are spread evenly, which is close but never exact."
          },
          "items": {
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 3
            },
            "maxItems": 6,
            "description": "bullet_list, comparison_cards, process_flow, code_card only. One entry per card. Write each as 'Heading: the line under it'; a colon, en dash, or pipe splits them."
          },
          "point": {
            "type": "object",
            "description": "callout_arrow, text, shape only. Free placement as fractions of the frame: {x: 0.5, y: 0.5} is the middle. Leave it out to use `position` instead.",
            "properties": {
              "x": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "y": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              }
            },
            "required": [
              "x",
              "y"
            ],
            "additionalProperties": false
          },
          "size": {
            "type": "number",
            "description": "text only. Type size in points of a 1080-tall frame, 12 to 220. It scales with the format, so one number is right in every aspect ratio."
          },
          "align": {
            "type": "string",
            "description": "text only. left, center or right. Also decides which way the block grows from its anchor."
          },
          "tracking": {
            "type": "number",
            "description": "text only. Letter spacing as a fraction of the size, -0.05 to 0.4. Small caps labels want about 0.07."
          },
          "line_height": {
            "type": "number",
            "description": "text only. Multiple of the size, 0.8 to 2.4. Defaults to 1.18."
          },
          "backdrop": {
            "type": "string",
            "description": "text only. none, box, or scrim. A box is a plate behind the words; a scrim dims the whole frame so text over busy footage stays readable."
          },
          "outline": {
            "type": "number",
            "description": "text only. Outline thickness in points of a 1080 frame, 0 to 12. Reads on any background, which a plate does not."
          },
          "rotation": {
            "type": "number",
            "description": "text, shape only. Degrees, -180 to 180."
          },
          "opacity": {
            "type": "number",
            "description": "text, shape only. 0 to 1. Below 1 the words are see-through, for a watermark or a caption you do not want to fight the picture."
          },
          "animation": {
            "type": "string",
            "description": "text, shape, effect only. How it enters and leaves: fade, rise, drop, slide_left, slide_right, pop, grow, none."
          },
          "shape": {
            "type": "string",
            "description": "shape only. rect, ellipse, pill, triangle, line, arrow, ring or star."
          },
          "width": {
            "type": "number",
            "description": "shape only. As a fraction of the frame width, 0.01 to 1.5."
          },
          "height": {
            "type": "number",
            "description": "shape only. As a fraction of the frame height, 0.01 to 1.5."
          },
          "fill": {
            "type": "string",
            "description": "shape only. A hex like \"#F54E00\", a palette role, or \"none\" for an outline only."
          },
          "stroke": {
            "type": "string",
            "description": "shape only. Outline colour: a hex, a palette role, or \"none\"."
          },
          "stroke_width": {
            "type": "number",
            "description": "shape only. Outline thickness in points of a 1080 frame, 0 to 40."
          },
          "radius": {
            "type": "number",
            "description": "shape only. Corner rounding for a rect, in points of a 1080 frame."
          },
          "effect": {
            "type": "string",
            "description": "effect only. dip, flash, vignette, grain, scanlines, glitch, letterbox or wash. `dip` fades to the colour and back out, which is the transition you put over a cut."
          },
          "strength": {
            "type": "number",
            "description": "effect only. 0 to 1. Half is usually plenty; grain above 0.4 is a stylistic choice rather than an accident."
          },
          "tag": {
            "type": "string",
            "description": "effect only. An internal label. The editor uses it to find the transition it put on a clip; leave it out.",
            "maxLength": 60
          },
          "at_seconds": {
            "type": "number",
            "minimum": 0
          },
          "duration_seconds": {
            "type": "number",
            "minimum": 0.2,
            "maximum": 30
          },
          "position": {
            "type": "string",
            "enum": [
              "lower_left",
              "lower_right",
              "upper_left",
              "upper_right",
              "center",
              "bottom_bar",
              "top_bar"
            ]
          },
          "palette_role": {
            "type": "string",
            "description": "A palette role, or a hex like \"#F54E00\". Roles resolve against the live theme, so one spec is legible in light and dark; send a hex when the exact colour is the point. Roles: accent, warm, cool, positive, plain, invert."
          },
          "easing": {
            "type": "string",
            "enum": [
              "linear",
              "out",
              "in_out",
              "spring_out"
            ]
          },
          "reason": {
            "type": "string",
            "maxLength": 200
          }
        },
        "required": [
          "layer_id"
        ],
        "additionalProperties": false
      }
    }
    propose_soundAction

    Propose sound: a one-shot effect on a moment, or a music bed under a stretch of the cut. Effects are synthesised in the browser, so there is nothing to load and nothing to license; pick one of: hit (A short, low, percussive thump. For a title card landing.) pop (A bright click. For a list row or a caption word arriving.) whoosh (Filtered noise sweeping up. For anything sliding in from an edge.) riser (A pitch climbing to a stop. For building into a reveal.) tick (A dry tick. For a step in a process, or a counter.) chime (Two soft tones. For a result, a total, or a positive stat.) A music bed takes an existing clip from the library and ducks itself under speech automatically, using the transcript's word boundaries, so you do not need to shape the volume yourself.

    View tool JSON
    {
      "name": "propose_sound",
      "kind": "act",
      "impl": "imperative",
      "description": "Propose sound: a one-shot effect on a moment, or a music bed under a stretch of the cut. Effects are synthesised in the browser, so there is nothing to load and nothing to license; pick one of: hit (A short, low, percussive thump. For a title card landing.) pop (A bright click. For a list row or a caption word arriving.) whoosh (Filtered noise sweeping up. For anything sliding in from an edge.) riser (A pitch climbing to a stop. For building into a reveal.) tick (A dry tick. For a step in a process, or a counter.) chime (Two soft tones. For a result, a total, or a positive stat.) A music bed takes an existing clip from the library and ducks itself under speech automatically, using the transcript's word boundaries, so you do not need to shape the volume yourself.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "sfx",
              "music"
            ],
            "description": "'sfx' for a one-shot on a moment, 'music' for a bed under a stretch."
          },
          "preset": {
            "type": "string",
            "enum": [
              "hit",
              "pop",
              "whoosh",
              "riser",
              "tick",
              "chime"
            ],
            "description": "sfx only. Which effect."
          },
          "clip_id": {
            "type": "string",
            "description": "music only. The clip to take the bed from, from list_clips."
          },
          "at_seconds": {
            "type": "number",
            "minimum": 0,
            "description": "Seconds from the start of the cut. For an effect under a graphic, use that graphic's at_seconds so they land together."
          },
          "duration_seconds": {
            "type": "number",
            "minimum": 0.2,
            "description": "music only. Leave it out to run to the end of the cut."
          },
          "gain": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "0 to 1. A bed under speech wants 0.1 to 0.25; above 0.4 it competes with the voice. An effect wants 0.4 to 0.8."
          },
          "duck": {
            "type": "boolean",
            "description": "music only. Duck under speech. Default true, and leaving it true is almost always right."
          },
          "reason": {
            "type": "string",
            "maxLength": 200
          }
        },
        "required": [
          "kind",
          "at_seconds"
        ],
        "additionalProperties": false
      }
    }
    propose_formatAction

    Propose reframing the whole composition to a different aspect ratio. Every graphic is laid out as fractions of the frame, so this moves nothing and rewrites nothing: the same composition simply becomes 16:9, 9:16 or 1:1, with the safe margins that format needs. Use it when they mention shorts, reels, vertical or a square post.

    View tool JSON
    {
      "name": "propose_format",
      "kind": "act",
      "impl": "imperative",
      "description": "Propose reframing the whole composition to a different aspect ratio. Every graphic is laid out as fractions of the frame, so this moves nothing and rewrites nothing: the same composition simply becomes 16:9, 9:16 or 1:1, with the safe margins that format needs. Use it when they mention shorts, reels, vertical or a square post.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "format": {
            "type": "string",
            "enum": [
              "landscape",
              "vertical",
              "square"
            ],
            "description": "landscape is 16:9, vertical is 9:16, square is 1:1"
          },
          "reason": {
            "type": "string",
            "maxLength": 200
          }
        },
        "required": [
          "format"
        ],
        "additionalProperties": false
      }
    }
    propose_cutAction

    Propose removing a stretch of the cut. Give it a quote and it finds the words in the transcript and stages a cut over exactly them, which is how 'take out the bit where I stumble over the second point' becomes a precise range. It appears as a marked region on the timeline and nothing is removed until the editor accepts it. Removing footage is the most destructive thing in this app, so it is also the one most firmly behind a click.

    View tool JSON
    {
      "name": "propose_cut",
      "kind": "act",
      "impl": "imperative",
      "description": "Propose removing a stretch of the cut. Give it a quote and it finds the words in the transcript and stages a cut over exactly them, which is how 'take out the bit where I stumble over the second point' becomes a precise range. It appears as a marked region on the timeline and nothing is removed until the editor accepts it. Removing footage is the most destructive thing in this app, so it is also the one most firmly behind a click.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "quote": {
            "type": "string",
            "maxLength": 200,
            "description": "The words to cut, as they were said. Preferred over raw seconds: it is checked against the transcript, so it cannot land in the wrong place."
          },
          "start_seconds": {
            "type": "number",
            "minimum": 0,
            "description": "Use only when there is no transcript. Seconds into the finished cut."
          },
          "end_seconds": {
            "type": "number",
            "minimum": 0,
            "description": "Use only when there is no transcript."
          },
          "reason": {
            "type": "string",
            "maxLength": 200,
            "description": "One sentence shown on the marker. Why this should go."
          }
        },
        "additionalProperties": false
      }
    }
    propose_tidyAction

    Find every hesitation and every silence in the cut and stage a cut over each one, in a single call. Only mechanical things: 'um' and 'uh' and holes in the audio longer than about a second. It never proposes cutting a sentence for being weak, because that is a judgement and this is a list. Each one is marked separately on the timeline so they can be taken or left one at a time.

    View tool JSON
    {
      "name": "propose_tidy",
      "kind": "act",
      "impl": "imperative",
      "description": "Find every hesitation and every silence in the cut and stage a cut over each one, in a single call. Only mechanical things: 'um' and 'uh' and holes in the audio longer than about a second. It never proposes cutting a sentence for being weak, because that is a judgement and this is a list. Each one is marked separately on the timeline so they can be taken or left one at a time.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "min_silence_seconds": {
            "type": "number",
            "minimum": 0.4,
            "maximum": 5,
            "description": "How long a gap has to be before it counts as dead air. Default 1.1. Below about 0.8 you start cutting breaths, which makes the edit sound rushed."
          }
        },
        "additionalProperties": false
      }
    }