Comments and agents
Review comments and other agents working on the same project. 13 tools.
On the main list
The tools a client sees when it connects.
comments
Review comments
Review comments. op: list (open ones), add, resolve (one you addressed). Free.
| Input | Type | Description |
|---|---|---|
op required | "list" | "add" | "resolve" | |
project_id required | string | Project. |
scene_id | string | Scene. |
status | "open" | "resolved" | "all" | |
body | string | add: the comment. |
t_start | number | add: scene seconds. |
t_end | number | add: end. |
anchors | array | |
comment_id | string | resolve: which. |
note | string | resolve: what was done. |
Callable by name
Not listed on connect, to keep the list short. Call them directly by name, or find them with tools.
add_comment
Leave a review comment
Leave a comment on a project, anchored as narrowly as it deserves: scene_id for a scene, t_start (and t_end for a range; seconds from the scene start) for a moment, element_id for one element, composition_path for a node of the composition tree. To point at several places at once ("1 and 3 should hit together"), pass anchors instead. parent_id replies to an existing thread: the way to answer a comment you are not resolving, or to say what you changed. kind marks it a question or a blocker; to says who it is for (another agent, the director, or one run). Free.
| Input | Type | Description |
|---|---|---|
project_id required | string | Project id. |
body required | string | The comment (≤5000 chars). |
kind | "note" | "question" | "blocker" | Default note. |
to | string | Who it is for: anyone (default), agent, director, or run:<agent run id>. |
scene_id | string | Anchor to this scene. |
t_start | number | Seconds from the scene start (project timeline when no scene_id). |
t_end | number | End of a time range, ≥ t_start. |
element_id | string | Anchor to this element of the scene (needs scene_id). |
composition_path | string | Anchor to this node of the scene's composition tree (needs scene_id). |
anchors | array | Several places at once, numbered in order (instead of scene_id / t_start / element_id). Each item has a kind: {kind:"time", t_start, t_end?, scene_id?} a moment or range (scene seconds with scene_id, else project time); {kind:"scene", scene_id}; {kind:"element", scene_id, element_id | composition_path, t?}; {kind:"lane", lane:"hit.snare"|"note.violin"|"section.B"|"waveform"|word id, track_id?, t_start? (t_end? for a stretch of the waveform) | bar?, beat?, scene_id?} a timeline lane; {kind:"region", scene_id, t, shape:{type:"rect",x,y,w,h} | {type:"path",points:[[x,y],…]}} a shape on the frame, coordinates as fractions (0..1) of the composition. |
parent_id | string | Reply to this comment. |
check_comments
Anything new from a person?
A cheap, instant check for feedback: has a person left or answered a comment for an agent since your cursor? Returns {new, count, blockers, questions, first_id, cursor, retry_after_seconds}. It does not wait and returns no rows: when new is true, call list_comments {awaiting:"agent"} for them. The first call (no since) only returns a cursor; pass the cursor back as since each time. Call it between passes, not faster than retry_after_seconds (30): it is rate-limited, and the get_project_status / get_storyboard / apply_changes calls you already make carry the same hint for free. Free.
| Input | Type | Description |
|---|---|---|
project_id required | string | Project id. |
since | string | The cursor from the previous check_comments. Omit on the first call. |
claim_comment
Say you are working on a review comment
Take an ADVISORY, time-limited claim on a review comment before you work it: the editor shows "<you> is on it" and other agents skip it in their list_comments {awaiting:"agent"} inbox, so two agents do not do the same note. Call again to renew; it lapses by itself after ttl_seconds (default 600). result "held" means another agent already has it: pick another. release:true lets go. assign_to:"run:<agent run id>" hands the note to a sub-agent (your claim drops, the note is addressed to that run, which claims it when it starts). Resolving the comment clears the claim. Never blocks a reply or resolve_comment. Free.
| Input | Type | Description |
|---|---|---|
project_id required | string | Project id. |
comment_id required | string | From list_comments (the first comment of the thread). |
ttl_seconds | integer | Seconds the claim lasts unless renewed. Default 600. |
label | string | What the editor shows, e.g. "Claude · scene 4". Defaults to your session name. |
release | boolean | Let go instead of taking. |
assign_to | string | Hand the note to "run:<agent run id>" (a sub-agent) or "agent". |
fork_agent_run
Fork an agent run from a step
A new run that starts from another run's conversation as it stood at step from_seq, optionally with a different model, skill or a first steer — replay a decision point, or A/B two models from the same place. Fork from before the parent's create_project and the fork makes its own project (a comparable arm); after it, both work on the same project. Like start_agent_run, the fork spends only through the tools it calls.
| Input | Type | Description |
|---|---|---|
run_id required | string | The run to fork. |
from_seq required | number | The step to fork after (a seq from get_agent_run). 0 = from the brief. |
model | string | Model: "gemini-flash" (google/gemini-3.8-flash via OpenRouter, default), "deepseek-flash" (deepseek/deepseek-v4.1-flash), or any gateway ref ("nitrorouter:<id>" or an OpenRouter id). |
skill | string | A skill slug from list_skills ("history-map", "history-map@1"): its SKILL.md goes in the run's prompt. |
skill_md | string | Inline SKILL.md instead of a registry skill (a draft being tried before put_skill). |
message | string | A steer the fork reads first. |
brief | string | A different brief for the fork. Replaces the opening brief when forking from 0, else is read as an operator message. |
label | string | A name for the fork (default: the parent's label ⑂ from_seq). |
reasoning | "off" | "low" | "medium" | "high" | Reasoning effort. |
max_steps | number | Model steps for the whole run (default 300). |
max_minutes | number | Wall clock for the whole run (default 90). |
credit_cap | number | Most credits the run may spend (default 300). A spending call past it is refused. |
get_agent_run
Read an agent run
An agent run and its steps after a cursor: status, model, $ and credits spent, wall clock, project, share link and MP4 once they exist; each step is a model call (text, tokens, $, latency), a tool call (input, result — truncated; full:true for all of it, and frames it saw), a steer or an error. Poll with after_seq = the returned cursor. Without run_id: the account's recent runs. Free.
| Input | Type | Description |
|---|---|---|
run_id | string | The run. Omit to list recent runs. |
after_seq | number | Only steps after this seq (the previous cursor). Default 0. |
limit | number | Steps per page (default 100, max 500). |
full | boolean | Include full tool outputs and model reasoning. |
prompt | boolean | Include the system prompt as sent. |
status | string | Listing only: queued | running | paused | done | stopped | failed. |
get_director_thread
Read the project's Director thread
The project's Director (in-editor agent) conversation as a DECISION TRACE: every message, and for each assistant turn its ordered steps — tool name, input, and the real outcome. Read this when the question is WHY the project looks the way it does (what was created, in what order, what failed, what a resolve actually started) rather than what it looks like now. Read-only; automated "[Background job update]" rows and editor ledger events are marked by kind.
| Input | Type | Description |
|---|---|---|
project_id required | string | Project id. |
limit | number | Most recent N messages to return, oldest first (default 200, max 500). |
list_comments
Review comments
The review comments people left on a project, the way notes are left on a cut: each is anchored to the project, a scene, a time range (t_start/t_end, seconds from the scene start when scene_id is set), an element id, or a composition node path. A grouped comment lists every place in anchors (numbered in order; a region is a shape drawn on the frame at t, a lane is a timeline lane such as hit.snare): the body refers to them together, so fix them together, often in one apply_changes. A spoken note carries voice: its transcript is what was said (and the body, when nothing was typed). Default: OPEN threads with their replies, in the order they were left: your work queue. To work one: read the anchor (get_scene; get_scene_context at t_start), make the change (edit_elements, edit_composition_unit, apply_changes, update_scene), then resolve_comment with the changeset_id or revision_id that answered it. A comment you cannot or should not act on: reply with add_comment parent_id instead of resolving it. Each comment has a kind (note | question | blocker: answer a question, do blockers first) and may be addressed_to someone (null = anyone, agent, director, run:<id>); comments sent together in one review pass share a pass_id. A comment from a person also steers any live agent run on the project, so you may already have been told about it. A scene comment carries routed_to (the agent that last wrote that scene, mine when it is you): your awaiting inbox lists yours first; one routed to another agent is theirs to take, so prefer to leave it unless it is blocking. Free.
| Input | Type | Description |
|---|---|---|
project_id required | string | Project id. |
status | "open" | "resolved" | "all" | Default open. |
scene_id | string | Only comments on this scene. |
kind | "note" | "question" | "blocker" | Only this kind. |
awaiting | "agent" | Your inbox: open threads whose last word is a person's (a new comment, or a reply to something you said). Call this when you start or resume work on a project: nothing is pushed to a chat session, so this is how you learn you were answered. |
limit | number | Max rows (default 100, max 500). |
resolve_comment
Resolve a review comment
Mark a comment resolved and LINK the change that answered it: changeset_id (from apply_changes / list_changes) and/or revision_id (from get_revisions, for element and composition edits). The link is what lets the person see which fix answered which note, so pass it whenever a change was made. note says what you did in a line. reopen:true reopens a resolved comment. Free.
| Input | Type | Description |
|---|---|---|
project_id required | string | Project id. |
comment_id required | string | From list_comments. |
changeset_id | string | The changeset that answered it. |
revision_id | string | The revision that answered it (get_revisions). |
note | string | One line on what was done (≤2000 chars). |
reopen | boolean | Reopen instead of resolving. |
start_agent_run
Start a cheap-model agent run
Start an unattended agent run: a gateway model makes a video from brief through the same Typecut tools you have (create_project, speak, generate_image, put_scene_composition, preview_composition, render_project …), server-side — it survives this conversation. Every model call and tool call is traced. Returns the run; watch it with get_agent_run, steer it with steer_agent_run, branch it with fork_agent_run. Without project_id or workspace_id it works in the account's "Development" workspace and creates its own project. Starting is free; the run spends credits through the tools it calls (each priced as usual), up to credit_cap. Called by an agent that is itself running (the editor chat, a seat, a run), it starts a HELPER: same project, your model unless you name one, a cap within yours; at most 3 at once and 6 in all, and a helper cannot start its own. Its final answer comes back to you as a message when it ends. Staff / authoring pilot.
| Input | Type | Description |
|---|---|---|
brief required | string | What to make: topic, length, aspect, anything the model must honour. |
model | string | Model: "gemini-flash" (google/gemini-3.8-flash via OpenRouter, default), "deepseek-flash" (deepseek/deepseek-v4.1-flash), or any gateway ref ("nitrorouter:<id>" or an OpenRouter id). |
surface | "house" | "studio" | Tool profile the run works on: "house" (default, the full catalog) or "studio" (the slim profile you drive over /mcp/studio: put_scenes with patch edits, get_scene_context, preview_scenes, textView results). |
skill | string | A skill slug from list_skills ("history-map", "history-map@1"): its SKILL.md goes in the run's prompt. |
skill_md | string | Inline SKILL.md instead of a registry skill (a draft being tried before put_skill). |
project_id | string | Work in this existing project instead of creating one. |
workspace_id | string | Workspace to create the project in (default: the one named "Development"). |
label | string | A name for the run ("alaska-gemini-1"). |
reasoning | "off" | "low" | "medium" | "high" | Reasoning effort, where the model supports it. |
max_steps | number | Model steps for the whole run (default 300). |
max_minutes | number | Wall clock for the whole run (default 90). |
credit_cap | number | Most credits the run may spend (default 300). A spending call past it is refused. |
dry_run | boolean | Validate and show what would start (model, preset, tools, workspace, budgets) without creating or running anything. |
steer_agent_run
Steer an agent run
Change a run while it runs, applied between steps: message is read by the model next as "[Operator] …" (on a finished run it reopens it); action pause / resume / stop; model or skill swaps for the rest of the run; force_tool_result replaces a tool result the model has seen (its tool_call_id, else the latest). Free.
| Input | Type | Description |
|---|---|---|
run_id required | string | The run. |
message | string | What the model should read next. |
action | "pause" | "resume" | "stop" | Pause, resume or stop the run. |
model | string | Model: "gemini-flash" (google/gemini-3.8-flash via OpenRouter, default), "deepseek-flash" (deepseek/deepseek-v4.1-flash), or any gateway ref ("nitrorouter:<id>" or an OpenRouter id). |
skill | string | A skill slug from list_skills ("history-map", "history-map@1"): its SKILL.md goes in the run's prompt. |
skill_md | string | Inline SKILL.md instead of a registry skill (a draft being tried before put_skill). |
force_tool_result | object | Replace a tool result: {tool_call_id?, result}. |
talk_to_director
Talk to the project's Director
Send the project's Director (the in-editor agent) a message and get its whole turn back: the reply, the steps it took (tool, input, outcome) and its trace (how the turn was routed, what went into its window). It is the SAME turn the editor chat runs, and it lands in the same thread — whoever opens the project in the editor sees it, tool rows included. Attach library media by id (upload or import_asset first) exactly like dropping files on the composer. If the reply comes back with ask, the Director stopped on a question: answer it by calling this again with the same thread_id (an option label, or your own words). Background jobs it starts keep running after the turn: poll get_project_status, then tell it what happened. SPENDS CREDITS: each message is charged the editor chat's flat per-turn price (answering its question is free; a turn that fails is refunded), plus whatever the tools it runs spend — the same spend guard as the chat applies. Out of credits answers 402 insufficient_credits.
| Input | Type | Description |
|---|---|---|
project_id required | string | Project id. |
message | string | What you would type in the chat. May be empty when attachments carry the message. |
thread_id | string | Thread to continue (returned by the previous call). Omit to use the project thread. |
attachments | array | media_assets ids to send with the message, as files dropped on the composer. |
talking_head
Make a face speak
Lip-sync a FACE to a VOICE: a photo or a silent clip of a person (face_asset_id or face_url) plus a voice track (audio_asset_id — e.g. a speak result — or audio_url with audio_seconds) becomes a clip of that face saying those words. At most 60 s of voice per clip; cut longer speech into parts. SPENDS CREDITS, per second of voice (dry_run:true quotes). Not a scene element: the MP4 comes back as result {assetId, url, posterUrl, width, height…} to place in your own HyperFrames as a <video>. Takes a minute or more: this waits ~50 s, then answers status "generating" — poll get_generation (or get_status) with the generation_id.
| Input | Type | Description |
|---|---|---|
project_id required | string | Project whose library receives the clip. |
face_asset_id | string | The face: a library image or video id. Or face_url. |
face_url | string | The face: a public https image or video url. |
audio_asset_id | string | The voice: a library audio id (a speak result). Or audio_url. |
audio_url | string | The voice: a public https audio url; then audio_seconds is required. |
audio_seconds | number | Length of the voice, 0–60 s. Required with audio_url; prices the clip. |
model | string | A talking-head model id from the allow-list (replicate:…). Omit for the default. |
seed | number | Provider seed for a repeatable take. |
dry_run | boolean | Quote only: returns {credits, available} and charges nothing. |