reelsaw
Reelsaw's MCP server exposes its whole long-form→short-form clipping pipeline to an agent over HTTP: start projects from video URLs, drive them to completion, read transcripts, and curate clips and intros/outros.
Projects: list them paginated (
list_projects), inspect one with its clips and settings (get_project), create one from any yt-dlp-fetchable URL with full settings (focus, clip length, captions, framing, language, vocabulary, instructions, intros/outros), block until done/failed (wait_for_project, ≤120 s polls), resume failures (retry_project), re-pick clips from the existing transcript with new settings (reanalyze_project), delete (delete_project).Transcript & activity: read the transcript as timed sentences clipped to a time range or char budget (
get_transcript), and see stage starts/completions, renders, retries and failure reasons (get_project_events).Clips: typo-tolerant search across clip/project titles, hooks and captions (
search_clips); full detail per clip including bounds, scores, framing decisions and download links (get_clip); add a clip from a source range, either exact or AI-selected within it (create_clip); edit title, hook, caption, hashtags, emphasis words, bounds, framing override/sections and style, re-rendering burned-in changes by default (update_clip); re-render one clip or many at once (rerender_clip,rerender_clips); export a zip of rendered clips with YouTube/TikTok metadata, optionally a subset (export_project).Intro/outro library: list items with defaults, usage counts and thumbnails, add videos (≤10 s/50 MB) or images (≤20 MB) by URL or upload id, set the default for new projects, remove (restorable 30 days) and restore, check where an item is used, and set intro/outro per project or per clip with optional immediate re-render (
list_bumpers,add_bumper,set_default_bumper,remove_bumper,restore_bumper,bumper_usage,set_project_bumpers,set_clip_bumpers).Behaviour notes: read-only tools are annotated as such and removals/deletes as destructive; long-running work is asynchronous (create/retry/reanalyze/rerender return immediately, so poll with
wait_for_projector the event feed), and no tool supports MCP task execution.
Allows storing source videos, rendered clips, and other assets in Backblaze B2 cloud storage via the S3-compatible API.
Allows storing source videos, rendered clips, and other assets in Cloudflare R2 object storage via the S3-compatible API.
Allows using Deepgram's transcription models to transcribe source videos as part of the video clipping pipeline.
Allows using Google's AI models as the language model or transcription provider for analyzing and clipping videos.
Allows storing source videos, rendered clips, and other assets in a self-hosted MinIO S3-compatible object storage.
Allows using locally hosted Ollama models for language model and transcription tasks, enabling a fully local video clipping pipeline without external API keys.
Allows using OpenAI models as the language model, transcription, or caption-alignment provider for analyzing and clipping videos.
Allows generating platform-ready metadata for TikTok's Content Posting API, including post info for rendered vertical clips.
Allows using Vercel AI Gateway as an AI provider for language model, transcription, and caption-alignment tasks in the video clipping pipeline.
Allows creating video clipping projects from YouTube links and generating platform-ready metadata for YouTube Data API v3 uploads.
Reelsaw
Self-hosted, AI-powered long-form → short-form video clipper. Paste a YouTube link or upload a video; Reelsaw transcribes it, asks an LLM for the most clippable moments, then renders vertical 9:16 clips with word-highlight captions and a hook overlay.
Pure TypeScript. Any AI vendor via the AI SDK. One-step deploy with Docker Compose.
Features
Pipeline
Any AI vendor – language model, transcription model and caption-alignment model are each a
provider:modelstring: OpenAI, Anthropic, Google, Groq, Deepgram, AssemblyAI, Vercel AI Gateway, or any OpenAI-compatible server (Ollama, vLLM, LM Studio, local Whisper servers). Fully local with no API keys is supported.Research-backed clip selection – map → pool → rank: the transcript is chunked at long pauses with 20% overlap (no "lost in the middle" on long videos), every standalone moment is collected per chunk in parallel, candidates are snapped/deduped, then scored on a rubric (hook / value / flow / shareability, plus relevance with a focus) as the median of k samples, and the top 10 get K sliding pairwise head-to-head passes (PRP-Sliding-K;
ANALYZE_PAIRWISE_PASSES, default 3 so the top 3 you see first are placed reliably) with positions swapped to cancel judge bias. Cost: at most Σ(n−1−p) pairs × 2 calls, i.e. 48 calls for the top 10 with 3 passes (18 with 1); pairs met twice are judged once. No target count: in auto mode weak picks are dropped by a gate relative to the run, not a fixed number, because pointwise scores do not transfer between judge models: a clip is dropped below max(ANALYZE_MIN_SCORE_FLOOR= 25, median −ANALYZE_SCORE_MAD_K= 1 × MAD) of the pooled rubric totals, and the best clip is always kept (ANALYZE_SCORE_RULE=absoluterestores the old fixed 45). The threshold and its median/MAD are in the project'scandidatesartifact. Candidates whose scoring failed are never compared with rubric totals; they only fill in when fewer than 3 scored clips survive. Optional "at most N" cap, and "Find clips about …" keeps only on-topic moments. Click a clip's score for the breakdown.ANALYZE_JUDGE_MODELlets a different model score and compare (less self-preference than judging its own hooks).ANALYZE_CONCURRENCY,ANALYZE_SCORE_SAMPLES,ANALYZE_PAIRWISEtune cost (auto: 1 call at a time, 1 sample, no pairwise for a self-hosted judge; 4 / 3 / on for cloud).Clean transcripts – names are fixed from vocabulary hints and a constrained LLM correction, and fillers, repetitions and false starts are cut with jump cuts. Every cut is located by forced alignment and checked by listening to the seam, so karaoke highlights land on the syllable. Each fix shows inline in the transcript with accept/reject, and long pauses can be shortened (details below).
Smart 9:16 reframing – UltraFace (1.2 MB ONNX, CPU, ~7 ms/frame via
onnxruntime-node) samples each clip at 4 fps and picks a layout per segment (clips are split at scene cuts and face-presence changes, so a picture-in-picture intro can be "fit" and the talking head after it "face"): face (crop follows the speaker with "heavy tripod" smoothing: dead zone, capped pan speed, instant snap at scene cuts), split (two speakers stacked), stack (slides/screen on top, zoomed webcam below), or fit (whole frame over a blurred background when there is no face, e.g. graphics and b-roll). With two people in a wide shot the crop follows whoever is talking (mouth motion correlated with the audio envelope, minimum 2.5 s per shot), falling back to a split when detection isn't confident. Override per project or per clip. Reference for every layout, its triggers, caveats and fixtures: docs/LAYOUTS.md.Captions – AI-picked key words per clip coloured and enlarged (editable in the editor), readability limits (≈2 short lines, comma/sentence breaks, a line stays up long enough to read: at least 0.7 s, 0.3 s per word and 20 characters per second), ASS karaoke word highlight (any colour), boxed, or outlined; size, words on screen (1 = one word at a time), uppercase; hook overlay with its own duration. Caption and hook positions are free x/y set by dragging on a live 9:16 preview that uses the renderer's crop math and font metrics, with a platform safe-zone overlay. Project-wide defaults, per-clip overrides. Burned in with ffmpeg + libass.
Editing
Workspace and clip editor – source player and clickable transcript on the left, clips streaming in on the right as they render, with score, layout badge, post caption + hashtags copy and download. The editor has a live preview of the source with the clip's framing and captions and a multi-lane timeline (ruler, transcript words, clip range, layout track) with zoom, snapping to words/scene cuts/playhead, nudge buttons, typed timestamps and I/O keys for frame-accurate trims. Split the layout track (⌘/Ctrl+B, the Split button, a double-click or the right-click menu) into sections that are Auto or forced to face/split/stack/fit/centre; drag the picture to re-centre a section; add, drag and remove transitions; ⌘/Ctrl+Z / ⇧⌘Z undo and redo every edit.
Deletes can be undone – deleting a project stops its work and hides it, with an Undo in the toast; it stays restorable for
DELETED_RETENTION_DAYS(7) before its files are removed. Re-picking moments keeps every clip you made or edited (text, bounds, framing, style, intro/outro) and only replaces untouched AI picks, which can be restored too. Single clips can be deleted and restored the same way. The same through MCP (delete_clip,restore_project,restore_clip) and the CLI (reelsaw deleted,restore,delete-clip,restore-clip,purge).Command palette and bulk export – ⌘K searches projects and clips with status, length and age, opens a row's actions (open, export, resume, retry failed clips, re-run refine, re-render, download, delete), takes pasted links (one project each, or opens the existing one) and offers retry-all shortcuts. "Export all" zips every rendered clip with platform-ready metadata: a paste-ready
.txt(title, description, tags, caption), a.youtube.json(YouTube Data API v3videos.insertbody, private by default) and a.tiktok.json(Content Posting APIpost_info,SELF_ONLY) per clip, plusmanifest.json,clips.csv(with rendered duration) and a README. Descriptions carry a timestamped link to the exact moment in the parent video.
Intros and outros
Intro and outro library – the Library page keeps several videos or images (PNG or JPG, shown 1 to 10 s); drop many files at once (duplicates are detected), view them enlarged, see which projects and clips use each one, remove with Undo, and choose the default new projects start with. Each clip is rendered as intro + clip + outro in a single encode, fitted to vertical over a blurred background.
Per project and per clip – a project follows the default, uses none or a specific item; each clip can follow the project, use none or pick its own, set in the editor, from a clip card or for several selected clips at once. The editor shows what a clip adds around its source range, changes re-render only when confirmed, and an unusable asset is skipped with a plain-language event instead of failing the clip.
Agents and automation
MCP server –
/api/mcp(Streamable HTTP) lets Claude Code, Claude Desktop, Cursor or a script create projects, wait for them, read timed transcripts, edit, create and re-render clips, manage the intro/outro library and download the results. Authenticate with an API key from Settings, or withMCP_OAUTH=trueso claude.ai and Claude Desktop connectors sign in through the browser.Operator CLI –
docker compose exec app reelsaw …inspects and fixes a running instance:status,events,clip,rerender,stuck,recover,logs,cuts,align,hear,flags,storage,retention,deleted,restore,purge,users,approve,make-admin,bumpers,import-reportand more (every command is in Operator CLI).
Hosting and accounts
Accounts, approval and quotas – the first account is the admin;
SIGNUP_MODE=open|approval|closeddecides who gets in, and admins approve, suspend, promote and remove people on the Users page, with usage per account (projects, source minutes, clips, model calls and tokens, stored bytes). Optional per-user quotas, retention of old files, captcha on sign-in, email (approval notices, password reset, verification) and terms/privacy links. Everyone has their own Project defaults (vocabulary, instructions, language, clip length, pauses, caption style, intro and outro) and API keys.Models and providers at runtime – admins switch the language, transcription and alignment models under Settings → System → Models without a restart: pick a provider, enter its key or server URL there (stored encrypted, never shown again), and choose from live model lists; local Ollama and Speaches models download with a progress bar. Keys and models are tested when saved.
Operations
Reliable, resumable, scalable – every stage is a pg-boss job in Postgres that checkpoints its output, so a crashed or restarted worker picks up where it left off; a worker that stops heartbeating (every 15 s) has its job re-queued by pg-boss within about a minute or two, and a reconciler re-enqueues anything orphaned. Run extra
workercontainers to scale. Every run (first pass, retry, re-render, re-analyze) is recorded with its own timings, and the UI shows elapsed against expected time per stage, learned from your finished projects. The browser gets live updates over a tRPC SSE subscription with automatic reconnect.Storage and install – local volume or
s3(AWS S3, MinIO, Cloudflare R2, Backblaze B2…); superseded renders, expired sources and orphaned files are swept hourly (reelsaw storagereports,reelsaw storage sweepruns it). One-line installers for macOS/Linux (bash) and Windows (PowerShell), and Report an issue saves a zip of a project's data, decisions and logs, with secrets left out.Observable and fail-fast – every service is built in
mainand self-checks, so the process exits with a readable reason if a model id is wrong, a key is missing, a binary is absent, the bucket is unreachable or the DB is down.LLM_TRACE=logsorlangfusecaptures every prompt/response (tokens, latency, project/clip/stage), andOTEL_ENABLED=trueturns on OTLP traces and metrics for HTTP, Postgres, pg-boss jobs, AI SDK calls, ffmpeg/yt-dlp and each stage.
Related MCP server: Smart Clip MCP
Contributing
See CONTRIBUTING.md (principles, tests, sign-off). Roadmap for learning from user decisions: docs/SELF-IMPROVEMENT.md.
Read docs/PRINCIPLES.md first: the consistency, concurrency and UI rules every change follows. Agent instructions live in AGENTS.md / CLAUDE.md.
Install (no source needed)
Fully local, with Ollama for the language model and Speaches for speech-to-text. Needs Docker; on macOS install Ollama first:
curl -fsSL https://raw.githubusercontent.com/osbytes/reelsaw/main/deploy/install.sh | bashOn Windows (Docker Desktop), in PowerShell:
irm https://raw.githubusercontent.com/osbytes/reelsaw/main/deploy/install.ps1 | iexWSL2 users can run the bash one-liner as is (with Docker Desktop's WSL integration on).
It writes ~/reelsaw (compose file + .env with generated secrets), pulls the published image and
the model (chosen by RAM: qwen2.5:14b, ~9 GB, on 24 GB or more; qwen2.5:7b from 12 GB; gemma3:4b below that; the script prints its choice and REELSAW_LLM=<model> overrides it), starts everything and waits
until http://localhost:3000 answers. Hosted providers and manual setup: deploy/README.md.
The scripts are deploy/install.sh and deploy/install.ps1;
they are served from main (see docs/RELEASING.md).
Quick start (from source)
git clone <this repo> reelsaw && cd reelsaw
cp .env.example .env
# edit .env: set BETTER_AUTH_SECRET, APP_URL, and at least one AI provider key
docker compose up -d --buildOpen http://localhost:3000, create an account (it becomes the admin), start a project. Set SIGNUP_MODE=closed or approval afterwards if the instance is public.
Scale workers:
docker compose --profile workers up -d --scale worker=2Use MinIO for local S3 testing:
docker compose --profile minio up -d
# then in .env: STORAGE_DRIVER=s3 S3_ENDPOINT=http://minio:9000 S3_FORCE_PATH_STYLE=true S3_BUCKET=reelsaw S3_ACCESS_KEY_ID=reelsaw S3_SECRET_ACCESS_KEY=reelsaw123(Create the bucket once via the MinIO console at http://localhost:9001.)
Model configuration
The language model and the transcription model are independent; mix vendors freely (Anthropic has no speech-to-text, so pair it with Deepgram/OpenAI/AssemblyAI/Groq). Each needs only its own key.
Env | Example values |
|
|
|
|
The transcription model must return word timestamps (captions and cuts need them), so openai:gpt-4o-transcribe, which returns none, is not supported.
Fully local (no API keys)
Ollama only serves language models; it has no speech-to-text. So the local stack is Ollama for AI_MODEL plus Speaches (faster-whisper behind an OpenAI-compatible API, word timestamps supported) for TRANSCRIPTION_MODEL. Both ship as a compose profile:
docker compose --profile local-ai up -d # Speaches; use your native Ollama (macOS: Metal GPU)
docker compose --profile local-ai --profile ollama up -d # Linux: also run Ollama in a container
ollama pull qwen2.5:14b # or: docker compose exec ollama ollama pull qwen2.5:14b.env:
AI_MODEL=compat:qwen2.5:14b # qwen2.5:7b or gemma3:4b on less RAM
OPENAI_COMPATIBLE_BASE_URL=http://host.docker.internal:11434/v1 # native Ollama; http://ollama:11434/v1 for the container
OPENAI_COMPATIBLE_API_KEY=ollama
TRANSCRIPTION_MODEL=openai:Systran/faster-whisper-small
OPENAI_BASE_URL=http://speaches:8000/v1
OPENAI_API_KEY=localNotes: the app requests response_format: json_schema from the compat server (OPENAI_COMPATIBLE_STRUCTURED_OUTPUTS=false to disable) and falls back to lenient parsing when a model ignores it, but small models still pick weak moments and write bland hooks. gemma3 4b works; qwen2.5 14b (the installer's default on 24 GB or more), llama3.1 8b or gemma3 12b are noticeably better. On first boot the app auto-downloads the whisper model into Speaches and verifies the Ollama model is pulled (it exits with ollama pull <model> otherwise). Speaches CPU with faster-whisper-small runs roughly real-time; use the latest-cuda image and faster-whisper-large-v3 on a GPU. The OPENAI_* variables are reused for Speaches because it speaks the OpenAI audio API, which is why the LLM goes through the compat provider instead.
What to expect: processing time
Every stage scales with the length of the video. Expected seconds for a stage ≈ video seconds × factor, where the factor depends on the models (local vs vendor) and your machine:
stage | what sets the factor | local CPU (measured¹) | vendor (measured²) |
download | your bandwidth and the site | 0.015 | 0.015 |
transcribe | whisper size on CPU/GPU, or the STT vendor | 0.25 | 0.065 |
refine (fillers, names) | LLM latency × number of candidate windows | 0.5 | 0.03 |
find moments | LLM latency × (video minutes ÷ 5 + 1) calls | 0.2 | 0.02–0.07 |
render | ffmpeg + face tracking per clip, ÷ render concurrency | 0.04 (3 clips) | 0.05 (3 clips) |
Rule of thumb: a vendor stack finishes a video in about a fifth of its length; a local CPU stack takes about as long as the video. Refine runs alongside finding moments, so the stages don't add up exactly.
¹ Apple-silicon laptop, qwen2.5:14b on Ollama + faster-whisper-small on Speaches (CPU), 20-minute podcast: download 15 s, transcribe 4.9 min, refine 10 min, find moments 4 min, render 47 s; 20 min in all. On a local 14B model the disfluency verifier (one call per candidate, ~40 s each) is the bottleneck, not transcription; a smaller model or DISFLUENCY_LLM=false cuts refine to a fraction. ² Same video through the Vercel AI Gateway, whisper-1 + claude-haiku-4.5: download 13 s, transcribe 77 s, refine 31 s, find moments 24 s, render 56 s; 3.4 min in all. Gemini 2.5 Flash took 5 min (long "thinking" outputs), Sonnet 4.5 about 4. Mixing a vendor LLM with a local TRANSCRIPT_ALIGN_MODEL makes render the slowest stage (5–9 min: every cut is re-aligned on the CPU); keep alignment on the same vendor as transcription. Full numbers in eval/bench/results/.
These factors are only the starting point. The app learns from its own finished projects: each stage's expected time is the median over your recent projects that ran with the same models, shown next to the elapsed time on the project page while it runs, in the activity feed when a stage finishes (Transcribe finished in 4:50 (expected ~4:00)), and as a per-stage expected vs actual table under Settings → System → Machine. There is no calibration step; the runs are the calibration.
Switching models without a restart
.env names the default models and keys; an admin can change both at any time under Settings →
System → Models. Each of the three pickers (language, transcription, alignment) opens provider
first: pick a provider and, if it has no key or server URL yet, enter it right there; its models
then appear. Cloud vendors are asked live, a self-hosted Ollama or Speaches shows what is installed
and downloads anything else with a progress bar, and the search box filters every provider at once.
Saving a key tries it first (the provider's models are listed with it) and a wrong one is refused;
saving a model checks it too (key present, server reachable and model installed, transcription
returns word timestamps). Keys are stored encrypted in the database with a key derived from
BETTER_AUTH_SECRET and never shown again (the UI sees the last four characters); rotating that
secret makes stored keys unreadable, and the UI asks for them again. Changes survive restarts and
reach worker processes within seconds; a stage already running finishes with the model it started
with. "Back to .env" / "Remove" drop an override. Over the API: admin.models.*, admin.providers.*.
Accounts and roles
The first account created on an instance is the admin; everyone else is a user. Admins see
the system settings (models, storage, resource meters) and the Users page; users see their own
projects and settings only. SIGNUP_MODE decides who gets in:
| Behaviour |
| Anyone can sign up and use the app at once. Right for a single-user box. |
| New accounts wait on a "Waiting for approval" page until an admin approves them (Users page, or |
| No sign-ups. (The older |
Every user has Settings → Project defaults (vocabulary, instructions, language, clip length,
pauses, caption style…) applied to each new project they or their agents start; the new-project
form starts from them and can save its current values back. Admins also see the System section
(models, storage, resource meters) and /api/health includes machine numbers only for them (or
with HEALTH_DETAILS=true).
Suspending an account (Users page) ends its sessions and refuses its API keys at the next request;
removing one deletes its projects, clips and files. Locked out? docker compose exec app reelsaw make-admin you@example.com promotes an account from the shell.
Email (EMAIL_DRIVER=smtp|resend, EMAIL_FROM, SMTP_URL or RESEND_API_KEY) turns on approval
notices, password reset and, with REQUIRE_EMAIL_VERIFICATION=true, verification before the
first sign-in. Without it everything else works; approvals are handled on the Users page.
Hosting for many people
Everything below is off by default and switched on by environment (deploy/.env.example lists
them), so a single-user box stays as it is:
Quotas:
MAX_PROJECTS_PER_USER,MAX_SOURCE_MINUTES_PER_DAY,MAX_NEW_PROJECTS_PER_HOUR(0 = unlimited), with per-user overrides on the Users page. A refusal is a sentence that says what to do ("Daily limit of 120 minutes reached; resets at 00:00 UTC"). Length is checked once the video is probed, so an over-long download fails the project with that reason.Usage (Users → Usage): projects, minutes of source, clips rendered, model calls and tokens (every model call writes a
llm_usagerow attributed to the project's owner), stored bytes.Retention:
SOURCE_RETENTION_DAYS/CLIP_RETENTION_DAYSdelete stored files from finished projects; rows and history stay, the project page offers "fetch again" and clips re-render.reelsaw retentionruns a sweep by hand.History pruning:
EVENT_RETENTION_DAYS(90),LLM_USAGE_RETENTION_DAYS(180) andADMIN_EVENT_RETENTION_DAYS(365) delete old rows in batches once a day (0 keeps everything); a project's run skeleton (created, run started, done) is always kept.Bot protection:
CAPTCHA_PROVIDER(Cloudflare Turnstile, reCAPTCHA, hCaptcha) with site and secret keys puts a widget on sign-up and sign-in.yt-dlp from a datacentre: YouTube refuses many cloud IPs.
YTDLP_PROXYandYTDLP_COOKIES_FILEhelp; a blocked download fails with "upload the file instead".Legal:
TERMS_URL/PRIVACY_URLappear on the sign-up form.MCP over OAuth (
MCP_OAUTH=true): Reelsaw becomes an OAuth 2.1 authorization server for MCP connectors (claude.ai, Claude Desktop): dynamic client registration, sign-in and a consent page in the browser, discovery at/.well-known/oauth-protected-resource/api/mcp(which names the issuer,<APP_URL>/api/auth, whose metadata is at/.well-known/oauth-authorization-server/api/auth). API keys keep working for CLIs.
MCP: drive Reelsaw from an agent
Reelsaw is an MCP server (Model Context Protocol, Streamable HTTP) at /api/mcp. Create an API key
in Settings → API keys and MCP (shown once) and point a client at it:
claude mcp add --transport http reelsaw https://your-host/api/mcp --header "Authorization: Bearer rs_…"{ "mcpServers": { "reelsaw": { "type": "http", "url": "https://your-host/api/mcp", "headers": { "Authorization": "Bearer rs_…" } } } }Clients that launch a command instead of calling a URL with a header (Claude Desktop without
MCP_OAUTH, Cursor's stdio entries) use reelsaw mcp: the same tools over stdio, forwarded to a
running instance. It needs no database or models, only REELSAW_URL (default: the app in the same
container) and REELSAW_API_KEY:
{ "mcpServers": { "reelsaw": { "command": "docker", "args": ["exec", "-i", "-e", "REELSAW_API_KEY=rs_…", "reelsaw-app-1", "reelsaw", "mcp"] } } }The tools (generated from apps/server/src/mcp-tools.ts; each tool's full description and input
schema say what it returns, whether it runs in the background and which neighbour to use instead):
Tool | What it does |
| Your projects, most recently updated first. |
| One of your projects: status, settings, effective intro/outro, transcript summary, and every clip (id, title, hook, bounds, score, status, download links); replacedClips lists deleted or replaced clips for restore_clip. |
| Start clipping a video from a URL (YouTube, Vimeo, a direct link; anything yt-dlp fetches). |
| Rename a project and/or change its saved settings (focus, instructions, clip length, maxClips, caption style, framing, pauses); only the fields you pass change. |
| Block until the project is done or failed, or timeoutSeconds pass. |
| The project's transcript as timed lines "[m:ss] text", optionally only a time range. |
| Find your clips and projects by words in their title, hook or caption (every word must match; case-insensitive, typo-tolerant; best first). |
| The project's pipeline history, newest first: stage starts and completions, clip renders, retries, failures with reasons. |
| Everything about one clip: text, bounds, scores, framing, style, emphasis, own and effective intro/outro, render diagnostics, video/thumbnail/editor links. |
| Edit one clip: only the fields you pass change; style and layoutSections replace the clip's whole value (null = back to the project's). |
| Add a clip from a time range of the source (needs a transcript). |
| Delete one clip of your project; a render in progress stops. |
| Queue one clip for rendering again (after rerender: false edits, a failure, or an intro/outro change). |
| Queue several clips of one project for rendering again in one step (after edits or failures). |
| A download link for a zip of the project's rendered clips with YouTube/TikTok metadata. |
| Resume a failed or stuck project from its furthest completed stage: re-render unfinished clips if there are clips, else pick clips, refine or transcribe again. |
| Pick clips again from the existing transcript (needs one), optionally with new settings. |
| Your intro/outro library. |
| Add a video (MP4/MOV/WebM, ≤10 s, ≤50 MB) or image (PNG/JPG, ≤20 MB) to your library from a public url or an uploadId. |
| Rename one of your library items (removed ones too). |
| Make a library item your default intro or outro for projects you create from now on (assetId null clears it). |
| Remove an item from your library and from your defaults. |
| Bring one of your removed library items back (list_bumpers shows them under removed); restoring an item that is not removed changes nothing. |
| The projects and clips that use a library item. |
| Set one project's intro and/or outro: "default" (your current default), "none", or a library asset id; a slot left out is untouched, and introSec/outroSec are saved with the project. |
| Override the intro and/or outro of up to 200 clips of one project: "inherit" (follow the project), "none", or a library asset id; a slot left out is untouched. |
| Delete one of your projects and all its clips; work in progress stops. |
| Bring back a deleted project with its clips and files (find it with list_projects deleted: true); restoring a project that is not deleted changes nothing. |
| Bring back a deleted clip or one a re-analyze replaced (get_project lists them as replacedClips); it goes to the end of the project's clips. |
get_project / get_clip show each clip's effective intro/outro and where it comes from.
They call the same tRPC procedures as the web app, so ownership checks and
validation are identical (apps/server/src/mcp.ts; the catalogue both transports advertise is
apps/server/src/mcp-tools.ts). The same key also authenticates tRPC
(/api/trpc/*), uploads and media downloads, so an agent can fetch the rendered clips. Keys are
hashed at rest (@better-auth/api-key); revoke them from Settings.
Operator CLI
docker compose exec app reelsaw <command> (see TROUBLESHOOTING for when to reach for which). Generated from the header of apps/server/src/cli.ts.
Run as docker compose exec app reelsaw <command> (from source: pnpm --filter @reelsaw/server cli <command>).
Command | What it does |
| list accounts: role, status, sign-up date |
| approve a waiting account (when email is off or the admin is locked out) |
| promote an account to admin (approves it first if needed) |
| run the retention sweep now (SOURCE_RETENTION_DAYS / CLIP_RETENTION_DAYS) |
| deleted projects that can still be restored, with their purge date |
| undo a project delete (same as projects.restore and the restore_project tool) |
| bring back a deleted clip or one a re-analyze replaced |
| delete one clip, restorable like a project (same as clips.delete and delete_clip) |
| rename a project or change its settings without re-running anything (same as projects.update and update_project); values are JSON or text |
| [--dry-run] remove deleted projects and replaced clips past DELETED_RETENTION_DAYS now |
| project, refine steps, clips, live jobs, last error |
| recent pipeline events |
| everything about one clip incl. render diagnostics |
| [a-b] [--json] face boxes per sampled frame + split speaker tracks |
| queue a re-render of one or several clips (same as the UI buttons) |
| rehydrate an issue report as a new project (dev only; the zip's contents are untrusted data, see its README) |
| [--save ] [--fixture ] dry-run the disfluency cut search for a clip and print every candidate verdict; --save writes removed/context audio; --fixture exports each flagged span as an offline regression case for |
| word timestamps from the align model for a source window |
| [start] [dur] transcribe a range of the RENDERED clip (what viewers hear) |
| [from] [to] transcript flags (entities / disfluencies) with status |
| disk use: unique, scratch-only, duplicate-source, expired-but-present bytes; |
| every unfinished project/clip: age, last event, live jobs, problems |
| clip: re-run the right step (prepare or render); project: reconcile |
| [n=60] [--since 2h] [--level debug] [--module render] [--raw] log lines mentioning a project/clip/job/request id from LOG_FILE (survives redeploys) |
| show the log levels in force, or set them for a while (e.g. render=debug); all processes follow within ~5 s |
| re-detect shot cuts (adaptive); --store saves them for layout/snapping/overlays |
| the intro/outro library. The user is --user, else the only account on this install; otherwise pass --user |
| a project's intro/outro: the library default, none or a specific item |
| a clip's own choice (inherit the project's, none or an item); both act as the project's owner; --rerender re-renders only the affected clips |
| scan the source for burned-in captions / watermarks; --store saves them (renders then hide them) |
| [--days 30] per account: projects, source minutes, clips, model calls / tokens / reported cost, minutes transcribed, stored bytes (same numbers as Users → Usage) |
| an account's quotas: instance value, override, in force, in use now |
| the MCP server over stdio for clients that launch a command: same tools as /api/mcp, forwarded to REELSAW_URL with REELSAW_API_KEY (needs no database; see src/mcp-stdio.ts) |
Settings and precedence
Where a value comes from, from the weakest source to the strongest (a later link overrides an earlier one):
What | Chain |
Models (language, transcription, alignment) |
|
Provider keys and URLs |
|
Stage knobs ( |
|
A project's settings | built-in defaults, then the user's Project defaults, then what the create form or agent sent. The result is frozen into |
A clip's style | the project's style, then the clip's own override ( |
Framing |
|
Quotas |
|
Two things to know:
An env gate wins silently.
TRANSCRIPT_BIAS=falseignores the project's vocabulary hints andDISFLUENCY_REMOVAL=falseskips the disfluency settings; neither tells the user. If a project setting seems to do nothing, check the gate first (TROUBLESHOOTING, "A project or clip setting has no effect").Existing projects keep their frozen settings. Changing your Project defaults affects new projects only.
Code: apps/server/src/pipeline/settings.ts (project), resolveStyle in packages/shared/src/index.ts (style), apps/server/src/pipeline/render.ts (framing), apps/server/src/ai/models.ts (models), apps/server/src/quota.ts (quotas).
Architecture
apps/web React 19 + Vite + Tailwind + TanStack Query + tRPC client + Better Auth client
apps/server Hono + tRPC + Better Auth + Drizzle (Postgres) + pg-boss workers + ffmpeg/yt-dlp
packages/shared zod schemas and types shared by bothServer composition (apps/server/src/services.ts): createServices() builds config → media tools → ai → storage → database (+migrations) → events → queue → auth, checking each one. The resulting Services object is injected into the tRPC context, the HTTP app and every pipeline stage (StageContext), so nothing reaches for a global. Boot logs one boot step ok line per step (JSON, or pretty on a terminal) with the step name and its duration in ms: config, data dir, resources, media tools, LLM call capture, AI models, the on-device detectors, storage, database, model settings, event bus, job queue, email, auth. Steps whose feature is switched off say so in their name (face detector (disabled)). A failing step stops the process with exit code 78 and a message that names the step and the fix, for example a transcription model that returns no word timestamps or a model server that is unreachable. The AI-models step checks the environment's models; once the database is up the effective models (after an admin's runtime override) are checked too.
Pipeline (each box is a pg-boss queue; each stage emits events and enqueues the next):
project.ingest ─▶ project.transcribe ─┬▶ refine.entities ─┐
yt-dlp / upload audio → chunks ├▶ refine.disfluency ─┼▶ project.analyze ─▶ clip.render (×N)
ffprobe parallel transcribe └▶ refine.scenes ─┘ LLM picks moments layout + captions
store source checkpoint per chunk (fan-out, fan-in snap to sentences cuts + crossfades
on the transcript row) finalize projectThe three refine jobs are independent: each writes its result under a row lock on the transcript (entity flags win over overlapping disfluency flags), and the last one to finish enqueues analyze. A refine step that exhausts its retries is marked failed and skipped; it never blocks the project. "Re-run refine" re-queues any subset on the existing transcript, e.g. after editing the vocabulary. Chunk transcription runs TRANSCRIBE_CONCURRENCY calls in parallel (auto: 1 for a self-hosted whisper, 3 for cloud vendors).
Durability model:
pgboss.jobis the source of truth for "what should run".projects.status/clips.statusis the source of truth for "what happened".Each stage checks for existing output first (source file in storage, transcript chunk rows, clip rows, rendered clip in storage) and skips work that is done.
Queues use
policy: exclusive+singletonKeyso a stage can never run twice concurrently for the same project/clip.heartbeatSeconds(15 s) on every queue: if a worker dies, pg-boss notices the missed heartbeat on its next supervisor pass (every 60 s), fails the job and retries it elsewhere after a 15 s delay that doubles per retry. Budget a minute or two, not seconds; each interruption uses one retry.On boot and every 5 minutes a reconciler re-enqueues any in-progress project or clip that has no live job.
Manual Retry resumes from the furthest completed stage; Re-analyze keeps the transcript and picks new clips.
Development
Live-reload loop in Docker (source mounted, no image rebuilds; rebuild the dev image only when dependencies change):
docker compose -f docker-compose.yml -f docker-compose.dev.yml --profile local-ai up -d app
open http://localhost:5173 # Vite + HMR; /api and /media proxied to the server (tsx watch)
docker compose exec app reelsaw stuckModels for running outside Docker: pnpm models:download (face, on-screen text, voice activity, forced alignment; ~105 MB).
pnpm install
docker compose up -d db
cp .env.example .env # set DATABASE_URL=postgres://reelsaw:reelsaw@localhost:5432/reelsaw
pnpm dev # server on :3000 (tsx watch), web on :5173 (vite, proxies /api and /media)Requires ffmpeg, ffprobe and yt-dlp on your PATH for local dev. Schema changes: edit apps/server/src/db/schema.ts, then pnpm db:generate; migrations run automatically on boot.
Most tests run against the local stack (they create and delete their own users and data); CI runs only the ones that need no stack, so run the ones you touched against yours:
pnpm --filter @reelsaw/server testReleases and distribution
Users install from a published image. The runtime image contains only
the minified server bundle (apps/server/scripts/bundle.mjs), the web build and production
dependencies, which scripts/check-image.sh <image> verifies.
Tag
vX.Y.Z→.github/workflows/release.ymlbuilds amd64 + arm64, checks the image, pushes to GHCR (and Docker Hub whenvars.DOCKERHUB_IMAGE+DOCKERHUB_USERNAME/DOCKERHUB_TOKENare set) and attachesreelsaw-X.Y.Z.zip(thedeploy/folder, image pinned) to the release.Before tagging: build locally, run
scripts/check-image.sh reelsaw:latest, and bootdeploy/in a scratch directory with only a.env(see the spec's verification section).Versions and changelogs come from changesets: every PR adds one (
pnpm changeset), a "Release" PR bumps the version, merging it pushes the tag. Full flow, versioning policy, pre-releases and hotfixes: docs/RELEASING.md.
Issue reports
Report an issue (project ⋯ menu, a failed clip, the account menu) downloads a zip with the
project's data, pipeline decisions (stage_artifacts), logs, system info and recent errors, and the
user's description. Secrets never go in. To reproduce one locally:
docker compose cp ~/Downloads/reelsaw-report-….zip app:/data/tmp/report.zip
docker compose exec app reelsaw import-report /data/tmp/report.zip [--user you@example.com]Everything in a report except its README and manifest is untrusted data; see TROUBLESHOOTING before letting an agent work on one. Spec: docs/specs/distribution-and-issue-reports.md.
Environment reference
Every variable, with its default and meaning, is in docs/CONFIG.md (generated from apps/server/src/config.ts; pnpm docs:gen refreshes it). .env.example and deploy/.env.example are generated from the same source.
Observability
OTEL_ENABLED=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 # OTLP/HTTP; traces + metrics
OTEL_SERVICE_NAME=reelsawSpans: inbound HTTP (/api/health excluded), Postgres queries, outbound fetch to AI vendors, pipeline.<stage> per job with reelsaw.project_id / reelsaw.clip_id / reelsaw.attempt, exec ffmpeg|ffprobe|yt-dlp, and the AI SDK's own ai.generateText / ai.transcribe spans (inputs/outputs not recorded). pg-boss propagates trace context from send() into the worker span, so one trace follows a project from the create mutation through every stage.
Entity-aware transcription
Whisper mishears names ("Copia" → "Copious"). Three layers fix that, all optional:
Vocabulary hints (
TRANSCRIPT_BIAS=true): proper nouns pulled from the channel name, title, description, tags and chapters, plus anything typed into "Names & terms" on the project form, are passed to the transcriber (promptfor OpenAI/Groq/Speaches,keytermfor Deepgram,wordBoostfor AssemblyAI). Biggest win: in our eval it halves WER and lifts entity recall from 64% to 95% at zero cost.Constrained LLM correction (
TRANSCRIPT_CORRECTION=true): transcript spans that sound like a known entity become candidates; the language model confirms each one in context with a confidence score. Only candidates can change, so the model cannot rewrite the transcript, and word timestamps are kept.Review in the UI: corrections at or above
TRANSCRIPT_AUTO_FIX_CONFIDENCE(0.85) are applied automatically and shown as "auto-fixed"; the rest appear under the transcript line with the confidence and accept/reject buttons. Applying decisions re-renders only the clips whose captions overlap the change.
Language: the filler/repeat rules, the sound-alike name search and the CTC cut aligner are English-only. For a transcript detected as any other language those steps are skipped with a plain-language event ("not available for de") instead of running blind; the language-model checks and the whisper-based cut search still work.
Disfluencies
Fillers ("um"), repetitions ("the the") and false starts ("your pay actual pay dates") are detected after transcription (DISFLUENCY_REMOVAL=true): a rule pass with near-certain confidence, then a model pass (DISFLUENCY_LLM=true) that rewrites each window cleanly and is diffed against the original so it can only ever delete. A model deletion is kept only when every removed word is a filler or is restated within the next few words; repairs land as pending flags for review. Flags appear inline in the transcript (struck through once applied) with the same accept/reject popover. Captions drop accepted disfluencies, and they are always cut from the audio/video with jump cuts. Long pauses are shortened too (project setting Pauses: natural 0.6 s, tight 0.35 s, or keep), detected with Silero VAD on the clip audio. Cut boundaries are not taken from the chunk-level ASR timestamps (they drift by up to a word): every cut is first located by CTC forced alignment (wav2vec2, exact word boundaries at 20 ms from the audio plus the known words, ~0.2 s on CPU) and verified with one transcription of the seam; only if that fails is it re-aligned by transcribing windows around it (TRANSCRIPT_ALIGN_MODEL) twice with different offsets (word timings shift with the window), boundaries snap to the quietest 5 ms frame beside the neighbouring words, and a candidate search keeps the first seam that passes verification: both neighbours heard back to back, nothing left between them, and the deleted words gone (or, when the recogniser fills them back in from context, the removed audio on its own is heard as those words). Unverifiable cuts are skipped and listed on the clip. Seams get a 20 ms equal-power crossfade (acrossfade) with length-compensated trims so audio and video stay in sync. Substitution repairs between function words ("into between", "a the") are caught by a rule; legitimate compounds ("out of", "up to") are excluded.
Eval
Regression evals live in one runner with pluggable suites (selection, framing, scenes, pauses, alignment, speakers, overlays, cuts, transcription, disfluency, selection-model); fixtures are small and in git, large media is fetched into a gitignored cache, baselines are versioned and a run fails on regressions. See docs/EVALS.md, including how to turn a new bug into a case.
pnpm eval # all suites
pnpm eval cuts framing # some suites
pnpm eval --offline # skip suites that need models
pnpm eval --update # accept new numbers as the baselineThe transcription suite synthesizes its cases with macOS text-to-speech so the ground truth is exact (eval/generate-audio.sh), and reports WER, entity recall and false entity insertions per model × vocabulary bias × LLM correction.
Results on the bundled cases (43 entity mentions, Speaches on CPU, qwen2.5:14b as judge):
model | vocab bias | LLM correction | WER | entity recall | false insertions |
faster-whisper-small | no | no | 9.0% | 63% | 0 |
faster-whisper-small | no | yes | 6.6% | 79% | 0 |
faster-whisper-small | yes | no | 4.3% | 95% | 0 |
faster-whisper-small | yes | yes | 4.3% | 95% | 0 |
faster-whisper-medium | yes | no | 3.7% | 95% | 0 |
Takeaway: vocabulary bias is the lever; the model size buys a little WER; the correction pass is the safety net for names the hints did not cover (and the review UI catches the rest).
Testing without AI keys
scripts/mock-ai.mjs is a tiny OpenAI-compatible server (chat completions + transcription with word timestamps). Point the app at it to exercise the whole pipeline offline:
OPENAI_BASE_URL=http://localhost:4545/v1 OPENAI_API_KEY=mock AI_MODEL=openai:mock TRANSCRIPTION_MODEL=openai:whisper-1Troubleshooting
Start with docker compose exec app reelsaw status <projectId>; see docs/TROUBLESHOOTING.md for the CLI, structured logs, diagnostics and evals, including a "setting has no effect" checklist.
Roadmap
See docs/RESEARCH.md for the competitor audit and research review behind these priorities. Top items:
Punch-in zooms on the emphasis words.
Active speaker: more labelled two-way conversation cases; a learned audio-visual model (Light-ASD ONNX) if the synchrony heuristic plateaus. Saliency fallback when no face is visible.
SRT/VTT export.
Direct publishing to YouTube Shorts / TikTok / Instagram.
Hosted edition: billing and plans on top of the shipped accounts, quotas and usage (docs/specs/hosted.md).
License
Reelsaw is free software under the GNU Affero General Public License v3.0. You can run
it, change it and host it; if you offer a modified version as a network service you must make
your modifications available under the same licence. Hosted-only additions (billing, for example)
will live under ee/ with their own licence; nothing in the repository is there yet. Contributions
need a DCO sign-off (git commit -s), see CONTRIBUTING.md.
Copyright (C) 2026 osbytes
Available Tools
29 toolsadd_bumperAdd intro/outroA
Add a video (MP4/MOV/WebM, ≤10 s, ≤50 MB) or image (PNG/JPG, ≤20 MB) to your library from a public url or an uploadId. Returns { id, name, kind, durationSec, duplicate, restored } (the same file twice returns the existing item). setDefault makes it your default for NEW projects only; existing ones change with set_project_bumpers.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | http(s) link to an MP4/MOV/WebM (max 10 s) or PNG/JPG; the server downloads it (max 50 MB, 60 s) | |
| name | No | Library name (url only; default: the file name). rename_bumper changes it later | |
| uploadId | No | An existing upload id (from POST /api/upload) instead of a url | |
| setDefault | No | Also make it your default intro or outro for new projects | |
| imageSeconds | No | How long an image shows (1-10 s) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does it well: accepted formats and size/duration limits, duplicate semantics ('the same file twice returns the existing item'), and the returned object shape { id, name, kind, durationSec, duplicate, restored }. It also scopes setDefault to new projects. This is unusually rich behavioral disclosure for a mutation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with no filler, front-loaded with the core action and its constraints before the routing note about set_project_bumpers. Every clause carries 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?
No output schema exists, so the description's inline return shape is a genuine asset, and with no annotations it adequately covers limits, idempotency, and defaults. It stops short of stating permission/auth requirements or what happens if both url and uploadId are omitted (all 5 params are optional).
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 real meaning beyond the schema: the url-vs-uploadId mutual alternative and the new-projects-only scope of setDefault. It does not explain imageSeconds, which is left entirely to 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?
States a concrete verb (add) plus the resource (video/image bumper) and the two accepted input sources (public url or uploadId). An agent can distinguish this from rename_bumper, list_bumpers, or set_project_bumpers without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly routes the 'make this the default' case: setDefault affects NEW projects only, and existing ones require set_project_bumpers. That names an alternative and the condition selecting it. It does not, however, spell out when to use add_bumper versus list_bumpers/restore_bumper, though those are largely self-evident from the name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
bumper_usageWhere an intro/outro is usedARead-only
The projects and clips that use a library item. Returns { projects: [{ id, title, slots, clips: [{ id, index, title, slots, via }] }] }, via saying whether through the project or the clip's own choice. Check before removing one.
| Name | Required | Description | Default |
|---|---|---|---|
| assetId | Yes | Library asset id (from list_bumpers) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, lowering the burden, and the description goes further by describing the exact return shape (nested projects/clips with slots and via) and explaining what 'via' means. That is real added context beyond the annotations, though it says nothing about permissions or result limits.
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?
Front-loads the purpose, then the return shape, then the actionable cue. Mostly tight, though the inline JSON-ish return shape and the 'via saying whether through the project or the clip's own choice' clause are a little dense.
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, the description compensates by spelling out the return structure and the meaning of 'via', and it covers the sole parameter and usage context. It is complete enough to invoke correctly, with only minor gaps around result scale.
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 single parameter is documented there (asset id, from list_bumpers), so the schema carries the burden. The description adds no parameter-level detail, making the baseline 3 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?
States a specific purpose: it returns 'the projects and clips that use a library item,' which is a clear verb+resource and distinctive from siblings like list_bumpers or remove_bumper. It does not explicitly name a sibling to contrast with, but the impact-analysis intent is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The closing phrase 'Check before removing one' gives a concrete when-to-use tied to the removal workflow (remove_bumper). It conveys the context clearly but does not name the alternative tool or state exclusions explicitly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_clipCreate clipA
Add a clip from a time range of the source (needs a transcript). mode exact keeps your bounds (3 s-10 min); mode ai lets the model pick the best moment inside them (≥8 s). Returns the new clip { id, status: "preparing" }; it gets a title and renders in the background (about a minute), so poll get_clip until done. To change an existing clip use update_clip instead.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | exact = these bounds (default); ai = best moment inside them | exact |
| endSec | Yes | Range end, seconds | |
| startSec | Yes | Range start, seconds from the start of the source video | |
| projectId | Yes | Project id (from list_projects, search_clips or create_project) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so: it discloses the transcript prerequisite, the async lifecycle (returns status "preparing", renders in background ~1 minute), the required polling via get_clip, and the distinct duration constraints per mode (3 s–10 min for exact, ≥8 s for ai). This is context an agent cannot get from the 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?
Four tight sentences, each earning its place, with the core purpose front-loaded and the routing advice, lifecycle, and constraints following in priority order. No filler or restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by describing the return shape and the polling flow. Slight gaps remain around failure modes (e.g. missing transcript, out-of-range bounds) and permissions, but for a 4-param create tool it is nearly 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%, so the baseline is 3, but the description adds real meaning beyond it: numeric bounds for mode=exact (3 s–10 min) and mode=ai (≥8 s) are not present in the schema's enum description. It adds constraints, though it doesn't restate projectId/startSec/endSec 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?
States a specific verb+resource ("Add a clip from a time range of the source") and immediately names the sibling it is not (update_clip for existing clips). An agent can distinguish it from update_clip/rerender_clip without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes to the alternative: "To change an existing clip use update_clip instead," and states the prerequisite (needs a transcript) plus the follow-up flow (poll get_clip until done). When-to-use and when-not-to-use are both covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_projectCreate projectA
Start clipping a video from a URL (YouTube, Vimeo, a direct link; anything yt-dlp fetches). Returns { id, title, status: "queued", next } at once; the pipeline (download, transcribe, pick, render) runs in the background for minutes, so follow with wait_for_project(id). Intro/outro default to your library defaults unless introAssetId/outroAssetId say otherwise.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Project title (default: the video's own title) | |
| introSec | No | Seconds an intro image shows (1-10) | |
| outroSec | No | Seconds an outro image shows (1-10) | |
| settings | No | Project settings; omit for the defaults (automatic clip count, 20–60 s clips, natural pauses). | |
| sourceUrl | Yes | http(s) URL of the video | |
| introAssetId | No | Library asset id (list_bumpers) for the intro of every clip; null = no intro; omitted = your default intro | |
| outroAssetId | No | Same for the outro |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, and it delivers the key behavioral trait: the call is asynchronous, returns immediately with status 'queued', and the download/transcribe/pick/render pipeline runs for minutes. It also documents the return shape and the intro/outro defaulting behavior. It omits permission/auth requirements and rate limits, so not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with the purpose, then the return value, then the async lifecycle and the next-tool handoff, then defaults. No filler; every clause carries actionable 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?
With no output schema and no annotations, the description compensates well: it explains the immediate return object, the background pipeline duration, and the follow-up call. Combined with a 100%-covered input schema, an agent has everything needed to invoke it 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 schema already documents all 7 parameters in detail, establishing a baseline of 3. The description adds only the intro/outro defaulting rule, which the schema's own parameter descriptions largely already state ('omitted = your default intro'), so the marginal value is small.
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 ('Start clipping a video from a URL') with the accepted source kinds enumerated (YouTube, Vimeo, direct link, anything yt-dlp fetches). This clearly distinguishes it from create_clip, which operates on already-analyzed 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?
Explicitly routes the agent to the follow-up tool: 'the pipeline runs in the background for minutes, so follow with wait_for_project(id).' That is a clear when-to-use-next instruction. It does not state when NOT to use it (e.g. re-analyzing an existing project via reanalyze_project), so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_clipDelete clipADestructiveIdempotent
Delete one clip of your project; a render in progress stops. Reversible: restore_clip brings it back for DELETED_RETENTION_DAYS (7 days by default). Returns { changed, restorable }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Clip id (from get_project or search_clips) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond destructiveHint/idempotentHint: it discloses the side effect ('a render in progress stops'), that the deletion is soft and restorable for DELETED_RETENTION_DAYS (7 by default), and the exact return shape { changed, restorable } despite there being no output schema. That is the full behavioral picture for a destructive mutation.
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 dense sentences, front-loaded with the action and its immediate side effect, then the undo contract and return value. No filler; every clause carries 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 single-parameter destructive tool with no output schema, the description supplies reversibility, retention duration, in-flight render behavior, and return fields. Nothing an agent needs before calling 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 single `id` parameter is already documented in-schema as coming 'from get_project or search_clips'. The description adds no format or provenance detail beyond that, so baseline 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?
States a specific verb and resource ('Delete one clip of your project'), with the scope ('one clip') making it clearly distinct from delete_project and restore_clip in the sibling list. An agent can pick it out 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?
Names the concrete alternative in 'Reversible: restore_clip brings it back' plus the retention window, which tells an agent both the undo path and its deadline. It doesn't spell out when to prefer update_clip or rerender_clip over deletion, so it stops short of full when/when-not coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_projectDelete projectADestructiveIdempotent
Delete one of your projects and all its clips; work in progress stops. Reversible: restore_project brings it back for DELETED_RETENTION_DAYS (7 days by default), then it and its files are removed for good. Returns { changed, restorable, message }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the destructiveHint/idempotentHint annotations by disclosing the cascade to clips, that in-progress work stops, the 7-day retention window before permanent file removal, and the exact return shape. This is the kind of consequence detail an agent needs before calling a destructive tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences: effect first, reversibility second, return contract last. No filler and the destructive consequence is 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?
Covers the cascade, the undo window, and the return payload even though no output schema exists, so an agent has everything needed to call it and interpret the result.
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 single 'id' parameter is already documented with its source tools, so the description adds nothing parameter-specific. Baseline 3 is appropriate when the schema does all the work.
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 ('Delete one of your projects and all its clips') plus the cascading scope. An agent can distinguish it from delete_clip and restore_project without inspecting schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the recovery path explicitly ('restore_project brings it back for DELETED_RETENTION_DAYS'), which tells the agent the alternative and the time window for undo. It doesn't spell out when this is preferable to other cleanup calls, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_projectExport clipsARead-only
A download link for a zip of the project's rendered clips with YouTube/TikTok metadata. Returns { url, clips, notRendered }; the link needs the same Authorization header as this server.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| clipIds | No | Only these clips (max 200; must be rendered clips of the project); omitted = every rendered clip |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover readOnlyHint=true, so the description carries most of the behavioral burden. It discloses an important non-obvious trait: the returned URL requires the same Authorization header as the server, plus the return shape ({ url, clips, notRendered }) in the absence of an output schema. It still omits whether the export is synchronous or how rendering gaps should be handled.
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 sentences with zero filler: the first gives the payload and its contents, the second gives the return shape and the auth caveat. Information is front-loaded and every clause 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 two-parameter read with no output schema, the description covers what the download contains, the response fields, and the auth requirement for the link. Minor gaps remain around failure/partial-render behavior, but nothing essential for invoking it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both id and clipIds are already fully documented (including the max 200 and 'must be rendered clips' constraints). The description adds no parameter-level meaning beyond the schema, making the baseline 3 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 resource and output: a zip download link of the project's rendered clips bundled with YouTube/TikTok metadata. No sibling tool does export/download, so an agent can distinguish it immediately from create_project, rerender_clips, or get_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?
There is no guidance on when to use this tool versus alternatives, no prerequisites (e.g., clips must be rendered first), and no mention of what happens when nothing is rendered. Usage is only weakly implied by the noun phrase 'rendered clips'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_clipGet clipARead-only
Everything about one clip: text, bounds, scores, framing, style, emphasis, own and effective intro/outro, render diagnostics, video/thumbnail/editor links. Returns the clip object. get_project lists all clips in brief; poll this after an edit to see the render finish (status done).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Clip id (from get_project or search_clips) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so safety is covered; the description adds real behavioral value by disclosing that render status transitions to 'done' and that render diagnostics are part of the response, implying eventual-consistency/polling semantics. It stops short of stating polling cadence, rate limits, or freshness guarantees.
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?
Front-loads the scope in one sentence, then the return behavior, then the sibling/polling guidance. The long field enumeration is dense but earns its place since there is no output schema; only minor trimming is possible.
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, the description compensates by listing the returned contents and confirming 'Returns the clip object', and it covers the read-only nature via annotations plus the render-polling lifecycle. An agent has everything needed to call it 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% and the single 'id' param is already documented in the schema (from get_project or search_clips). The description adds no syntax, format, or edge-case detail beyond what the schema provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Everything about one clip') and then enumerates the concrete payload (text, bounds, scores, framing, style, intro/outro, render diagnostics, links), so the agent knows exactly what comes back. It also explicitly distinguishes itself from the sibling 'get_project', which returns clips only in brief.
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?
Names the alternative (get_project for a brief list of all clips) and the condition that selects it, plus a concrete follow-up workflow: 'poll this after an edit to see the render finish (status done)'. The agent can route between list-view and single-clip-view without guessing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_projectGet projectARead-only
One of your projects: status, settings, effective intro/outro, transcript summary, and every clip (id, title, hook, bounds, score, status, download links); replacedClips lists deleted or replaced clips for restore_clip. Returns the project object. For one clip's full detail use get_clip, for the words get_transcript, for the pipeline history get_project_events.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries the burden of describing the return payload and does so richly, including the non-obvious replacedClips field and its link to restore_clip. It stops short of pagination, size limits, or error behavior, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with what the tool returns, followed by one routing sentence. It is dense but each clause (clip fields, replacedClips, sibling routing) earns its place; only the 'Returns the project object' sentence is slightly redundant with the opening enumeration.
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, the description must convey the response shape, and it does so field-by-field, including the otherwise undiscoverable replacedClips semantics. Combined with the sibling routing, an agent has everything needed to call and interpret 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?
There is a single parameter with 100% schema description coverage, and the schema already states the id and where to obtain it (list_projects, search_clips, create_project). The description adds nothing about the id beyond what the schema provides, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource and enumerates exactly what the project payload contains (status, settings, intro/outro, transcript summary, clips with their fields). It also names the sibling tools it is not (get_clip, get_transcript, get_project_events), so an agent can distinguish it without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent to alternatives: get_clip for one clip's detail, get_transcript for words, get_project_events for pipeline history. It also states the purpose of replacedClips (restore_clip), giving a clear when-to-use signal for a downstream tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_project_eventsProject activityARead-only
The project's pipeline history, newest first: stage starts and completions, clip renders, retries, failures with reasons. Returns [{ at, type, ...details }]. Use it to find out why something failed or is slow; get_project shows the current state.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| limit | No | Most events to return (1-200, default 50) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description adds real value beyond that: it discloses the ordering (newest first), the return shape ({ at, type, ...details }), and the kinds of diagnostic content (failures with reasons). It does not mention pagination behavior for the limit cutoff, but is otherwise well-disclosed for a read-only 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?
Two dense sentences, front-loaded with the resource and ordering, followed by the return shape and a routing hint. Every clause carries information; 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 read-only, two-parameter tool with no output schema, the description supplies the return shape, ordering, event taxonomy, and sibling routing. Nothing essential to 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 id and limit are already fully documented, giving a baseline of 3. The description adds only marginal meaning beyond the schema by implying chronological ordering; it does not elaborate on the limit's effect on older events.
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 ('The project's pipeline history') and enumerates the exact event types returned (stage starts/completions, clip renders, retries, failures with reasons). It explicitly distinguishes itself from get_project, so an agent can separate the history tool from the current-state tool without inspecting schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete use case ('find out why something failed or is slow') and names the alternative (get_project shows current state). This is a clear when-to-use plus alternative, though it never states when NOT to reach for this tool or any prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_transcriptGet transcriptARead-only
The project's transcript as timed lines "[m:ss] text", optionally only a time range. Returns text; output longer than maxChars is cut with a note saying which fromSec to continue from. Use it to pick your own moments for create_clip.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| toSec | No | End of the range, seconds | |
| fromSec | No | Start of the range, seconds from the start of the video | |
| maxChars | No | Cut the output at this many characters (1000-200000, default 60000) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so safe read is covered. The description adds valuable behavior: the truncation policy ('output longer than maxChars is cut with a note saying which fromSec to continue from') and the return format, which goes beyond the annotation's safety 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?
Three focused sentences with no waste, front-loading the output format and then covering the truncation behavior and the recommended use case. Slightly dense but well-structured.
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 transcript tool with no output schema, the description covers the return format, truncation behavior, and downstream use case. It is nearly complete, though it could mention whether the range is clamped to video length or how missing projects are handled.
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 fully documents all 4 parameters. The description mentions the time range and maxChars truncation, but adds no syntax or format details beyond what the schema provides. Baseline 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('transcript') and describes the exact output format ('[m:ss] text' timed lines). It also distinguishes it from siblings by naming create_clip as the downstream use case.
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 the agent 'Use it to pick your own moments for create_clip', giving a clear use case. However, it doesn't state when NOT to use it or name an alternative for retrieving transcript text in a different way.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_bumpersList intros and outrosARead-only
Your intro/outro library. Returns { assets: [{ id, name, kind, durationSec, isDefaultIntro, isDefaultOutro, usedBy, thumbnailUrl }], removed: [...] } (removed items stay restorable for 30 days). Use the ids with set_project_bumpers, set_clip_bumpers or set_default_bumper.
| 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, so safety is covered; the description adds genuine value beyond that by disclosing the return shape and the behavioral detail that removed items remain restorable for 30 days. This is more than restating the annotation.
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?
Front-loaded purpose, then return shape, then actionable usage note; no filler sentences. The embedded return-shape listing is dense but justified since there is no output schema to carry it.
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, the description usefully enumerates the returned asset fields and the removal/restore window, which an agent needs to act on the result. It is nearly complete; only the sibling-alternative routing is absent.
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 takes zero parameters, so there is nothing to document and the baseline is 4. The description appropriately spends instead on return-value structure rather than fabricating parameter detail.
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?
Name, title, and the opening phrase 'Your intro/outro library' make clear this lists the bumper (intro/outro) assets. The resource is specific and it is distinguishable from sibling setters, though the listing verb itself is only implied rather than stated outright.
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 tells the agent what the returned ids feed into: set_project_bumpers, set_clip_bumpers, or set_default_bumper, which contextualizes when to call it. It does not name a competing tool (e.g. bumper_usage) or state exclusions, so it falls short of the explicit alternative routing seen in the top-tier example.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_projectsList projectsARead-only
Your projects, most recently updated first. Returns { projects: [{ id, title, status, stage, clips: "n/m rendered", url }], total, nextCursor }; pass nextCursor as cursor for the next page. Use get_project for one project's clips, search_clips to find by words.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Projects per page (1-100, default 24) | |
| cursor | No | nextCursor from the previous page; omit for the first page | |
| deleted | No | true = only deleted projects that restore_project can still bring back |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint already covers the safety profile, so the description's added value is the sort order, the inline return shape (including the derived 'clips: n/m rendered' field), and the pagination contract. It does not mention rate limits or auth, but for a read-only list tool the disclosed behavior is substantive.
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 tight clauses: identity/ordering, return shape + pagination, then sibling routing. Front-loaded and every sentence carries information an agent needs; nothing is padding.
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?
No output schema exists, but the description documents the return payload and cursor field anyway, and it covers ordering and next-page mechanics. Combined with a fully described parameter schema, an agent has everything needed to call and page through 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 limit, cursor, and deleted are already fully documented, including the restore_project link for deleted. The description only restates the cursor handoff, adding no meaning beyond the schema. Baseline 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?
States a specific verb+resource ('Your projects'), plus the ordering ('most recently updated first'), which immediately separates it from the mutating project siblings. It also names the two relevant alternatives (get_project, search_clips), so an agent can route without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names alternatives with the condition that selects them: get_project for a single project's clips, search_clips for finding by words. Pagination guidance ('pass nextCursor as cursor for the next page') tells the agent exactly how to continue a multi-page call.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reanalyze_projectRe-analyze projectA
Pick clips again from the existing transcript (needs one), optionally with new settings. Clips you created or edited are kept; untouched AI picks are replaced and restorable with restore_clip for a while. Returns { kept, replaced } at once; the picking runs in the background, so follow with wait_for_project. To only save settings use update_project; to resume a failure use retry_project.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| settings | No | Project settings; omit for the defaults (automatic clip count, 20–60 s clips, natural pauses). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does it well: it discloses that edited clips are preserved, that untouched AI picks are replaced but restorable via restore_clip 'for a while', the immediate return shape { kept, replaced }, and that picking is asynchronous. The only shortfall is that 'for a while' is vague about the actual restore window and no permission/lock requirements are noted.
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 dense sentences, zero padding, front-loaded with the action and the prerequisite, then preservation semantics, then return/async behavior, then sibling routing. 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 tool with no output schema and no annotations, the description covers the prerequisite, destructive/restorative side effects, the return contract, and the async follow-up. An agent has everything needed to call it correctly and chain the next step.
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 nested settings object is thoroughly self-documented, so the baseline is 3. The description adds only 'optionally with new settings' and does not clarify any non-obvious behavior (e.g. whether partial settings merge with existing values) 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?
Specific verb ('pick clips again') plus resource ('existing transcript'), with the prerequisite stated inline ('needs one'). It explicitly separates itself from update_project and retry_project, so an agent can distinguish it from siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the when (re-pick from an existing transcript, optionally with new settings), the alternatives and their conditions ('To only save settings use update_project; to resume a failure use retry_project'), and the required follow-up ('follow with wait_for_project'). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_bumperRemove intro/outroADestructive
Remove an item from your library and from your defaults. Projects and clips already using it keep rendering with it. Undo with restore_bumper within 30 days; check bumper_usage first. Returns { ok }.
| Name | Required | Description | Default |
|---|---|---|---|
| assetId | Yes | Library asset id (from list_bumpers) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare destructiveHint=true; the description goes well beyond that by disclosing the blast radius ('Projects and clips already using it keep rendering with it'), the 30-day undo window, and the return shape { ok }. These are the non-obvious behaviors an agent needs before performing an irreversible-feeling delete.
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?
Four short sentences, front-loaded with the action and its scope, then recovery, then prerequisite, then return value. Every sentence carries distinct information with no repetition of the title or schema.
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 one-parameter destructive tool with no output schema, the description covers effect scope, reversibility window, prerequisite check, and response shape. An agent has everything needed to call it safely and to recover from a mistake.
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 a single required parameter with 100% schema description coverage ('Library asset id (from list_bumpers)'), so the schema already carries the meaning and the description adds nothing further about it. Baseline 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?
States a specific verb and resource ('Remove an item from your library and from your defaults') and immediately scopes what it does not touch. It names the sibling tools that matter (restore_bumper, bumper_usage), so an agent can place it against add_bumper/set_default_bumper without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete prerequisite ('check bumper_usage first') and the recovery path ('Undo with restore_bumper within 30 days'), which is real when-to-use guidance. It stops short of stating when not to use it (e.g., preferring set_default_bumper to merely swap a default), so it is clear but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rename_bumperRename intro/outroAIdempotent
Rename one of your library items (removed ones too). Only the label changes; nothing re-renders. Returns { id, name, previousName }.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | New name (1-120 chars) | |
| assetId | Yes | Library asset id (from list_bumpers) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare idempotentHint=true, so the description adds real value: 'Only the label changes; nothing re-renders' sets expectations about side effects, and the return shape is disclosed. It still omits permission/auth requirements and what happens if the asset doesn't exist.
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, front-loaded with the action and scope, with the side-effect caveat and return shape following. 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 simple two-parameter mutation with an idempotency annotation, the description covers purpose, side effects, and return shape. Output schema is absent but the return fields are given inline, leaving little of consequence 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%, with both assetId and name documented including length bounds. The description adds no parameter detail beyond the schema, so the baseline 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?
States a specific verb (rename) and resource (library item / bumper), and the title clarifies 'bumper' means intro/outro. It does not explicitly distinguish itself from siblings like add_bumper or remove_bumper, but the operation is 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 parenthetical '(removed ones too)' implies you may rename a removed item without restoring it first, which is a useful usage hint. However, there is no explicit when-to-use guidance and no named alternative (e.g., restore_bumper) is referenced.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rerender_clipRe-render clipAIdempotent
Queue one clip for rendering again (after rerender: false edits, a failure, or an intro/outro change). Async: the new video replaces the old when done (usually under a minute); poll get_clip. Returns { step: render | prepare } (prepare = it never got its AI title, which runs first). For several clips of a project use rerender_clips.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Clip id, not a project id (from get_project or search_clips) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only carry idempotentHint, so the description adds substantial behavior: it is async, the new video replaces the old on completion (usually under a minute), the agent should poll get_clip, and the return shape { step: render | prepare } with the meaning of 'prepare'. This is rich context beyond the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: the action, the trigger conditions, the async semantics, and the sibling alternative all land within a few sentences with no wasted phrasing.
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?
No output schema exists, so the description carries the return value and its variant ('prepare' vs 'render'), the async/polling model, and the replacement behavior. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema itself documents the id parameter in detail ('Clip id, not a project id (from get_project or search_clips)'). The description adds no further param syntax or format, so baseline 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?
States a specific verb and resource ('Queue one clip for rendering again') and explicitly scopes it to a single clip, naming the plural sibling rerender_clips for multi-clip use. An agent can distinguish it from rerender_clips without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete triggering conditions (rerender: false edits, a failure, or an intro/outro change) and names the alternative 'For several clips of a project use rerender_clips'. When-to-use and the sibling routing are both explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rerender_clipsRe-render clipsAIdempotent
Queue several clips of one project for rendering again in one step (after edits or failures). Finished and failed clips are queued, clips still rendering are skipped; each new video replaces the old when done. Returns { requested, rerendered, skipped }; poll get_project or wait_for_project. For a single clip rerender_clip is enough.
| Name | Required | Description | Default |
|---|---|---|---|
| clipIds | Yes | Clip ids of that project (get_project), 1-200 | |
| projectId | Yes | Project id (from list_projects, search_clips or create_project) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the lone idempotentHint annotation: it states which clips are queued versus skipped (finished/failed queued, still-rendering skipped), that each new video replaces the old on completion, and names the return payload. This is exactly the behavioral context an agent needs for a mutation-queue 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?
Four tight sentences: purpose, queue/skip semantics, return shape plus polling hint, and the sibling redirect, in that order. No filler and nothing redundant with the schema.
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-param batch mutation with no output schema, the description covers the trigger, the skip/replace semantics, the exact return shape, and the follow-up polling tools. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with clipIds documenting the 1-200 bound and projectId its source, so the schema already carries the parameter semantics. The description adds no syntax or format detail beyond referring to 'several clips of one project', so the baseline 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?
States a specific verb and resource ('Queue several clips of one project for rendering again') with scope ('in one step') and contrasts it against the single-clip sibling rerender_clip. An agent can distinguish it from rerender_clip and retry_project without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the trigger conditions ('after edits or failures') and explicitly names the alternative for a narrower use case ('For a single clip rerender_clip is enough'). When-to-use and when-to-use-something-else are both present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restore_bumperRestore intro/outroAIdempotent
Bring one of your removed library items back (list_bumpers shows them under removed); restoring an item that is not removed changes nothing. It does not become a default again. Returns { ok }.
| Name | Required | Description | Default |
|---|---|---|---|
| assetId | Yes | Library asset id (from list_bumpers → removed) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare idempotentHint=true; the description adds two real behavioral facts beyond that — the no-op outcome for non-removed items and that default status is not restored. It also discloses the return shape { ok }. It does not say what happens with an unknown or invalid assetId, which limits it to a 4.
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 clauses: the action, the no-op caveat, the non-default caveat, plus the return shape. The core action is front-loaded and every sentence carries information an agent could act on.
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, idempotent restore with no output schema, the description covers what the tool does, the state precondition, side effects, and the response shape, so an agent can call it confidently. The only omission is failure behavior for an invalid or already-deleted assetId.
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 assetId property description already says "Library asset id (from list_bumpers → removed)". The description paraphrases the same sourcing hint without adding format, validation, or error semantics, so the baseline 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?
"Bring one of your removed library items back" states a specific verb and resource, and naming list_bumpers anchors it to the bumper library rather than projects or clips. It never uses the word "bumper" explicitly, so the tie to the title (intro/outro) relies on the sibling reference.
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 tells the agent the precondition (item must be in the removed state, discoverable via list_bumpers) and what happens outside it ("restoring an item that is not removed changes nothing"). "It does not become a default again" implicitly routes the agent to set_default_bumper for that goal, but the alternative is never named outright.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restore_clipRestore clipAIdempotent
Bring back a deleted clip or one a re-analyze replaced (get_project lists them as replacedClips); it goes to the end of the project's clips. Returns { changed, status, needsRerender }; needsRerender means it never finished, so call rerender_clip.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Clip id (from get_project → replacedClips) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare idempotentHint=true, so the description carries most of the load and does it well: it discloses the positional side effect (the clip goes to the end of the project's clips) and the return shape { changed, status, needsRerender } with the meaning of needsRerender. It does not discuss permissions or whether restoring a replaced clip affects the replacing clip, leaving a small gap.
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 dense sentences with no filler: the capability and the affected set come first, then the return-value semantics and the required follow-up call. Every clause carries information an agent needs.
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, the description compensates by naming the returned fields and interpreting needsRerender, and it explains the placement side effect. For a one-parameter restore tool with only an idempotency annotation, nothing essential to 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 coverage is 100% for the single id parameter, so the schema already documents the type and its provenance. The description repeats the same hint ('from get_project → replacedClips') without adding format or syntax detail, so this is the baseline 3 rather than added value.
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 (bring back) and resource (a deleted clip or one a re-analyze replaced), and names the exact source of such clips (get_project lists them as replacedClips). This is clearly distinguishable from siblings like delete_clip, rerender_clip, and get_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?
Gives a clear trigger (restore a deleted or re-analyze-replaced clip) and explicitly routes the follow-up case: 'needsRerender means it never finished, so call rerender_clip.' No explicit when-not-to-use or alternative such as delete_clip is named, so it stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restore_projectRestore projectAIdempotent
Bring back a deleted project with its clips and files (find it with list_projects deleted: true); restoring a project that is not deleted changes nothing. A project that was processing comes back failed: retry_project resumes it. Returns { changed, status }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects with deleted: true) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare idempotentHint, so the description carries most of the burden and delivers: the no-op case for non-deleted projects, the state transition where a processing project returns as failed, and the return shape { changed, status } despite no output schema. It does not mention permission/auth requirements, which is the only real gap.
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?
One dense but well-ordered sentence: core purpose first, then discovery, then the no-op caveat, then the processing caveat, then the return shape. Every clause carries information an agent would otherwise have to guess.
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 one-parameter mutation with an idempotency annotation and no output schema, the description supplies exactly what is missing: precondition, no-op behavior, state edge case, and the return shape. Nothing needed to call it correctly is absent.
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?
Single parameter with 100% schema description coverage, and the schema already says the id comes from 'list_projects with deleted: true' — the description repeats that same hint rather than adding new meaning. Baseline 3 applies when the schema does the work.
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 (restore) and resource (deleted project), and explicitly scopes what is recovered: 'with its clips and files'. It also names sibling tools (list_projects for discovery, retry_project for the processing case), so an agent can distinguish it from delete_project/restore_clip without opening another schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states how to find the target ('find it with list_projects deleted: true'), what happens when the precondition fails ('restoring a project that is not deleted changes nothing'), and which alternative to use for the processing case ('retry_project resumes it'). Both the when and the when-not are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retry_projectRetry projectA
Resume a failed or stuck project from its furthest completed stage: re-render unfinished clips if there are clips, else pick clips, refine or transcribe again. Finished clips, the transcript and the source are kept. Returns { queue } (the stage restarted); then wait_for_project. To pick different clips use reanalyze_project instead.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses what is preserved (finished clips, transcript, source), what gets redone (re-render unfinished clips, else pick/refine/transcribe), and the return shape { queue }. It does not mention permissions, cost, or idempotency of repeated retries, which keeps it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and scope, then behavior, return value, and alternative. Dense but nearly every clause carries information; the branch enumeration ('re-render unfinished clips ... else pick clips, refine or transcribe again') is slightly heavy for a one-line description.
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 supplies the return value itself ({ queue }, the restarted stage) plus the follow-up tool. Combined with the stated preservation semantics, an agent has everything needed to call and chain 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?
Only one parameter (id) and schema coverage is 100%, so the schema already documents its origin. The description adds no param-level detail, but with a single fully described parameter the baseline is 4.
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 (resume/retry) and resource (a failed or stuck project), and pins the starting point precisely ('from its furthest completed stage'). It also names the sibling it is not (reanalyze_project), so an agent can distinguish it without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger condition ('failed or stuck project'), an explicit alternative with its condition ('To pick different clips use reanalyze_project instead'), and a follow-up step ('then wait_for_project'). Nothing about routing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_clipsSearch clipsARead-only
Find your clips and projects by words in their title, hook or caption (every word must match; case-insensitive, typo-tolerant; best first). Returns { projects (max 8), clips (max limit) with ids, bounds and links, truncated? }. Use list_projects to browse instead.
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | Words to find, e.g. "budget tips" | |
| limit | No | Most clips to return (1-50, default 15) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries matching and ranking behavior: every word must match, case-insensitive, typo-tolerant, best-first ordering. It also discloses the return envelope (projects max 8, clips max limit, ids/bounds/links, truncated flag) despite no output schema. It stops short of error or rate-limit behavior, keeping it out of top marks.
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 tight sentences with no filler: what it searches, what it returns, and the alternative tool, in that priority order. Every clause earns its place and the core purpose is 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?
No output schema exists, and the description compensates by outlining the result shape including the truncation flag and per-entity caps. Combined with full schema coverage on both parameters and the explicit sibling alternative, an agent has everything needed to call it 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, but the description adds genuine semantics for q: implicit AND across every word, case-insensitive, typo-tolerant matching, and it clarifies that limit caps only the clips portion of the result. That is meaning beyond the schema's terse 'Words to find' example.
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 (Find) applied to specific resources (clips and projects) and names the searched fields (title, hook, caption). An agent can immediately distinguish search_clips from list_projects, the browsing sibling, without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a concrete routing rule — 'Use list_projects to browse instead' — which contrasts searching by keyword versus browsing. It is clear context with an explicit alternative, though it doesn't cover edge cases like empty results or when to prefer get_clip over search for a known id.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_clip_bumpersSet clips' intro/outroA
Override the intro and/or outro of up to 200 clips of one project: "inherit" (follow the project), "none", or a library asset id; a slot left out is untouched. rerender: true re-renders only these clips. Returns { updated, rerendered }.
| Name | Required | Description | Default |
|---|---|---|---|
| intro | No | "inherit" (alias "default") = follow the project, "none" = no bumper on this clip, or a library asset id | |
| outro | No | "inherit" (alias "default") = follow the project, "none" = no bumper on this clip, or a library asset id | |
| clipIds | Yes | Clip ids of that project (get_project), 1-200 per call | |
| introSec | No | Seconds an intro image shows on these clips (1-10) | |
| outroSec | No | Seconds an outro image shows on these clips (1-10) | |
| rerender | Yes | true = re-render only these clips now; false = apply on their next render | |
| projectId | Yes | Project the clips belong to (list_projects) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the partial-update semantics (omitted slots untouched), the meaning of each value mode, the rerender side effect ('re-renders only these clips'), and the return shape ({ updated, rerendered }) despite having no output schema. It omits permission requirements and what happens to clips that keep an inherited bumper.
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 dense, front-loaded sentences with no filler: value modes and scope come first, then the rerender caveat, then the return shape. Every clause carries information an agent needs.
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 7-parameter mutation with no annotations and no output schema, the description covers the critical gaps: operation scope, partial-update behavior, side effects, and the return shape. It stops short of stating prerequisites (e.g. that clipIds must belong to projectId, or permission needs).
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 3 is the baseline, but the description adds value beyond it with the 200-clip cap, the slot-omission rule, and the scoping of 'rerender: true' to only the affected clips. The enum value semantics largely duplicate the schema's own parameter 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 gives a specific verb (override) and resource (intro/outro of clips) plus a hard scope bound ('up to 200 clips of one project'), which implicitly separates it from the project-level sibling set_project_bumpers. An agent can tell what this tool mutates and on which entities 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?
Usage is implied by the clip-level scope and the partial-update note ('a slot left out is untouched'), but no sibling is ever named and there is no explicit 'use set_project_bumpers instead when...' routing. The agent must infer the clip-vs-project split from the description alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_default_bumperSet default intro/outroAIdempotent
Make a library item your default intro or outro for projects you create from now on (assetId null clears it). Existing projects keep theirs; to change one use set_project_bumpers. Returns { ok }.
| Name | Required | Description | Default |
|---|---|---|---|
| slot | Yes | Which default to set | |
| assetId | Yes | Library asset id (list_bumpers), or null for no default |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only provide idempotentHint; the description adds valuable scope behavior (future-only effect) and the null-clears semantic. It also mentions the return shape, though it doesn't note auth requirements or what happens to already-defaulted rows.
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 clauses, front-loaded with the main action, then the scope caveat, then the return shape — zero waste.
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 2-param idempotent setter with no output schema, the description covers scope, clear semantics, alternative tool, and return value. Nothing essential 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 baseline is 3; the description adds the 'assetId null clears it' semantic that clarifies the anyOf-null branch beyond the schema's terse wording.
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 (make default) and resource (intro/outro bumper), and clearly scopes it to future projects versus existing ones, distinguishing it from set_project_bumpers.
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 says it affects projects created from now on, tells the agent existing projects are unchanged, and names the alternative (set_project_bumpers) for that case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_project_bumpersSet a project's intro/outroA
Set one project's intro and/or outro: "default" (your current default), "none", or a library asset id; a slot left out is untouched, and introSec/outroSec are saved with the project. Clips with their own choice (set_clip_bumpers) keep it. Applies on each clip's next render; rerender: true re-renders finished clips now. Returns { rerendered }. set_default_bumper changes future projects instead.
| Name | Required | Description | Default |
|---|---|---|---|
| intro | No | "default" = your current default intro/outro, "none" = no bumper, or a library asset id (see list_bumpers) | |
| outro | No | "default" = your current default intro/outro, "none" = no bumper, or a library asset id (see list_bumpers) | |
| introSec | No | Seconds an intro image shows in this project (1-10); videos keep their own length. Saved with the project | |
| outroSec | No | Seconds an outro image shows in this project (1-10). Saved with the project | |
| rerender | Yes | true = re-render the project's finished clips now; false = apply on their next render | |
| projectId | Yes | Project id (list_projects or create_project) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses override precedence (clip-level choices survive), timing semantics ('Applies on each clip's next render'), the effect of rerender:true (re-renders finished clips now), that a slot left out is untouched, and the return shape ({ rerendered }).
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?
Dense and front-loaded: the core action and value semantics come first, then precedence, then effect timing and the sibling routing. The colon/semicolon chain makes it slightly run-on, but every clause carries 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 six-parameter mutation tool with no annotations and no output schema, the description covers what is mutated, what is left alone, when changes take effect, override precedence, the return value, and the alternative tools. Nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real semantics beyond the schema by explaining that omitted slots are untouched and that introSec/outroSec are persisted with the project while clip-level choices override them. The enum-value meanings largely duplicate the schema text.
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 a specific verb and resource scope ('Set one project's intro and/or outro'), immediately distinguishing project-level bumper config from the clip-level and default-level siblings. An agent can tell this apart from set_clip_bumpers and set_default_bumper without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names both adjacent tools and their scopes: clip-specific choices win ('Clips with their own choice (set_clip_bumpers) keep it') and set_default_bumper 'changes future projects instead'. It gives clear context for selection, though it never states an explicit 'use this when' rule or exclusion beyond the scope contrast.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_clipUpdate clipA
Edit one clip: only the fields you pass change; style and layoutSections replace the clip's whole value (null = back to the project's). Text-only edits (title, caption, hashtags) apply at once; bounds, hook, framing, style and emphasis are burned into the video and re-render in the background (~1 min) unless rerender is false. Returns the clip summary with its new status; poll get_clip until done.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Clip id (from get_project or search_clips) | |
| hook | No | On-screen opening line (max 80 chars) | |
| style | No | Caption/hook style for this clip on top of the project's; replaces the clip's override; null = follow the project | |
| title | No | Clip title (1-120 chars) | |
| endSec | No | New end, seconds from the start of the source; clip must stay ≥3 s | |
| caption | No | Post caption, not burned in (max 300 chars) | |
| emphasis | No | Words the captions colour (max 30); replaces the list | |
| hashtags | No | Hashtags without # (max 20); replaces the list | |
| rerender | No | Re-render when a burned-in field changed (default true); false = keep the old video until rerender_clip | |
| startSec | No | New start, seconds from the start of the source video | |
| layoutOverride | No | Framing for the whole clip; null = automatic | |
| layoutSections | No | Framing per time range (max 50), source seconds; replaces all sections; null or [] = automatic |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does so well: it discloses partial-update semantics, that style/layoutSections REPLACE the whole value (with null reverting to project defaults), the split between instant text edits and background-burned edits, the ~1 min async re-render, the rerender:false escape hatch, and that the response is the clip summary with a new status.
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 dense sentences, front-loaded with the most consequential fact (only passed fields change) before the render/timing details and the follow-up call. No filler; every clause conveys a distinct behavioral fact.
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 12-parameter mutation tool with no annotations and no output schema, the description covers update semantics, async rendering, return shape and the polling loop. It omits error/conflict handling and any permission requirements, which are the remaining gaps for a tool of this complexity.
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 genuine meaning beyond it by grouping parameters into instant text fields (title, caption, hashtags) versus burned-in fields (bounds, hook, framing, style, emphasis) and by clarifying the replace-vs-merge contract per group.
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 ('Edit one clip') and immediately scopes it with the merge semantics ('only the fields you pass change'), which distinguishes it from update_project, set_clip_bumpers and rerender_clip. An agent knows this is the partial-metadata-and-render edit path without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It routes the agent to companion tools: poll get_clip until the re-render finishes, and it implies rerender_clip is the alternative when rerender is false. It doesn't state an explicit 'use this when X, use Y instead' exclusion, but the context for each edit class is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_projectUpdate projectAIdempotent
Rename a project and/or change its saved settings (focus, instructions, clip length, maxClips, caption style, framing, pauses); only the fields you pass change. Does not re-pick clips or re-render: reanalyze_project picks again with the new selection settings, rerender_clips applies style changes. Returns { changed, needsReanalyze, needsRerender, hint }.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from list_projects, search_clips or create_project) | |
| clear | No | Optional settings to reset to their default, e.g. maxClips (back to automatic) or focus | |
| title | No | New title | |
| settings | No | Settings to change; keys left out keep their value. Intro/outro go through set_project_bumpers |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations carry only idempotentHint, so the description does most of the work: it discloses partial-update semantics, the absence of reanalysis/rendering side effects, the follow-up tools needed to realise those effects, and the shape of the return object. It stops short of stating permission requirements, reversibility, or that a returned needsReanalyze flag implies a follow-up call is mandatory, so it is strong but not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, zero filler: capability and field list first, patch semantics and the not-does boundary second, sibling routing and return shape last. Each sentence carries distinct information an agent needs.
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 a 26-key nested settings object and no output schema, the description supplies the patch contract, the non-effects, the routing to reanalyze_project/rerender_clips, and the four return keys. Nothing required to invoke or interpret the call 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 description coverage is 100% and every parameter (including the nested settings keys, the clear enum and the deprecated captionPosition) is documented inline. The description's parenthetical field list only re-summarises a subset of what the schema already states, so it adds no meaning beyond it; baseline 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?
Names a specific verb (rename/change saved settings) and resource (project), then enumerates the affected settings groups (focus, instructions, clip length, maxClips, caption style, framing, pauses). It explicitly separates itself from reanalyze_project and rerender_clips, so an agent can route correctly without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the patch condition ('only the fields you pass change'), what this tool does NOT do ('Does not re-pick clips or re-render'), and which sibling to use for each of those cases with the trigger condition. Both alternatives are named explicitly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_projectWait for projectARead-only
Block until the project is done or failed, or timeoutSeconds pass. Returns { id, status, stage, stageProgress, error, clips: [{ id, title, status }] }; on timeout the same with hint "Still running": call it again. Use get_project instead for a non-blocking look with full clip details.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Project id (from create_project or list_projects) | |
| timeoutSeconds | No | Longest to wait, seconds (1-120, default 60) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=true, so the description carries the rest: it discloses that the call blocks, the timeout behavior, and the retry-on-timeout pattern. It adds the concrete return shape (status, stage, stageProgress, error, clips) without an output schema. Minor gap: no mention of auth or rate considerations, but the behavioral core is well covered.
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?
Front-loads the blocking behavior and termination conditions, then the return shape and alternative. Dense but every clause earns its place; the inline return object is compact rather than 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?
With no output schema, the description supplies the return structure and the timeout/retry hint, and it covers the blocking semantics and alternative tool. An agent has everything needed to invoke and interpret it 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 both id and timeoutSeconds are already documented in the schema. The description only alludes to timeoutSeconds in passing and adds no syntax or semantics beyond the structured field, 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?
States a specific verb (block/wait) and resource (project), and gives the exact termination conditions: done, failed, or timeoutSeconds elapsed. It also names the sibling it is not (get_project) for non-blocking reads, so an agent can distinguish it without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: use get_project instead for a non-blocking look, and call this again if the timeout hint 'Still running' is returned. Both the when and the alternative are stated directly.
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.
28 tool updates
v0.7.0- Changed
add_bumper1 field changed- added
Input schema / properties / name / descriptionAdded value: +"Library name (url only; default: the file name). rename_bumper changes it later"
- Changed
bumper_usage1 field changed- added
Input schema / properties / assetId / descriptionAdded value: +"Library asset id (from list_bumpers)"
- Changed
create_clip4 fields changed- added
Input schema / properties / endSec / descriptionAdded value: +"Range end, seconds" - added
Input schema / properties / mode / descriptionAdded value: +"exact = these bounds (default); ai = best moment inside them" - added
Input schema / properties / projectId / descriptionAdded value: +"Project id (from list_projects, search_clips or create_project)" - added
Input schema / properties / startSec / descriptionAdded value: +"Range start, seconds from the start of the source video"
- Changed
create_project33 fields changed- changed
Input schema / properties / introAssetId / descriptionPrevious value: -"Library asset id for the intro of every clip; null = no intro; omitted = your default intro"New value: +"Library asset id (list_bumpers) for the intro of every clip; null = no intro; omitted = your default intro" - changed
Input schema / properties / introSec / descriptionPrevious value: -"Seconds an intro image shows"New value: +"Seconds an intro image shows (1-10)" - added
Input schema / properties / outroSec / descriptionAdded value: +"Seconds an outro image shows (1-10)" - added
Input schema / properties / settings / properties / captionPosition / descriptionAdded value: +"Deprecated: use captionY" - added
Input schema / properties / settings / properties / captionSize / descriptionAdded value: +"Caption size multiplier (0.5-2, default 1)" - added
Input schema / properties / settings / properties / captionX / descriptionAdded value: +"Caption centre, horizontal, as a fraction of the 9:16 frame (0-1)" - added
Input schema / properties / settings / properties / captionY / descriptionAdded value: +"Caption centre, vertical (default 0.72), as a fraction of the 9:16 frame (0-1)" - added
Input schema / properties / settings / properties / captions / descriptionAdded value: +"Caption look: karaoke (active word highlighted), box, plain, or none (no captions)" - added
Input schema / properties / settings / properties / emphasis / descriptionAdded value: +"Colour the clip's key words (default true)" - added
Input schema / properties / settings / properties / emphasisColor / descriptionAdded value: +"Colour of emphasised words, #RRGGBB (default #39FF14)" - added
Input schema / properties / settings / properties / focus / descriptionAdded value: +"Only pick clips about this topic (max 300 chars)" - added
Input schema / properties / settings / properties / highlightColor / descriptionAdded value: +"Karaoke active-word colour, #RRGGBB (default #FFD700)" - added
Input schema / properties / settings / properties / hookSeconds / descriptionAdded value: +"How long the hook shows, seconds (0-15, default 3.5)" - added
Input schema / properties / settings / properties / hookX / descriptionAdded value: +"Hook centre, horizontal, as a fraction of the 9:16 frame (0-1)" - added
Input schema / properties / settings / properties / hookY / descriptionAdded value: +"Hook centre, vertical (default 0.16), as a fraction of the 9:16 frame (0-1)" - added
Input schema / properties / settings / properties / instructions / descriptionAdded value: +"Free-text guidance for picking and titling clips (max 2000 chars)" - added
Input schema / properties / settings / properties / introAssetId / descriptionAdded value: +"Library asset id of the intro (list_bumpers); null = none" - added
Input schema / properties / settings / properties / introSec / descriptionAdded value: +"Seconds an image intro/outro shows (1-10); videos keep their own length" - added
Input schema / properties / settings / properties / language / descriptionAdded value: +"Spoken language code (e.g. en); unset = detected" - added
Input schema / properties / settings / properties / maxClipSeconds / descriptionAdded value: +"Longest clip, seconds (10-300, default 60; must be above minClipSeconds)" - added
Input schema / properties / settings / properties / maxClips / descriptionAdded value: +"Most clips to pick (1-50); unset = every moment that stands on its own" - added
Input schema / properties / settings / properties / minClipSeconds / descriptionAdded value: +"Shortest clip, seconds (5-180, default 20)" - added
Input schema / properties / settings / properties / outroAssetId / descriptionAdded value: +"Library asset id of the outro (list_bumpers); null = none" - added
Input schema / properties / settings / properties / outroSec / descriptionAdded value: +"Seconds an image intro/outro shows (1-10); videos keep their own length" - added
Input schema / properties / settings / properties / pauses / descriptionAdded value: +"Long pauses inside clips: natural (cut to 0.6 s, default), tight (0.35 s) or off" - added
Input schema / properties / settings / properties / reframe / descriptionAdded value: +"Framing: auto (detect per section), face (follow the speaker), split (two speakers stacked), stack (full frame over a face crop), fit (whole frame on blur), center (static crop), none (original aspect)" - added
Input schema / properties / settings / properties / showHook / descriptionAdded value: +"Show the hook text at the start of the clip (default true)" - added
Input schema / properties / settings / properties / sourceText / descriptionAdded value: +"Text already in the video: hide (blur captions/logos except in slide decks, default), always (blur even then), keep" - added
Input schema / properties / settings / properties / uppercase / descriptionAdded value: +"Captions in capitals" - added
Input schema / properties / settings / properties / vocabulary / descriptionAdded value: +"Names, brands and jargon to spell correctly, comma separated (max 1000 chars)" - added
Input schema / properties / settings / properties / wordsPerLine / descriptionAdded value: +"Max caption words on screen at once (1-8, default 4)" - added
Input schema / properties / sourceUrl / descriptionAdded value: +"http(s) URL of the video" - added
Input schema / properties / title / descriptionAdded value: +"Project title (default: the video's own title)"
- Added
delete_clip - Changed
delete_project1 field changed- added
Input schema / properties / id / descriptionAdded value: +"Project id (from list_projects, search_clips or create_project)"
- Changed
export_project2 fields changed- added
Input schema / properties / clipIds / descriptionAdded value: +"Only these clips (max 200; must be rendered clips of the project); omitted = every rendered clip" - added
Input schema / properties / id / descriptionAdded value: +"Project id (from list_projects, search_clips or create_project)"
- Changed
get_clip1 field changed- added
Input schema / properties / id / descriptionAdded value: +"Clip id (from get_project or search_clips)"
- Changed
get_project1 field changed- added
Input schema / properties / id / descriptionAdded value: +"Project id (from list_projects, search_clips or create_project)"
- Changed
get_project_events2 fields changed- added
Input schema / properties / id / descriptionAdded value: +"Project id (from list_projects, search_clips or create_project)" - added
Input schema / properties / limit / descriptionAdded value: +"Most events to return (1-200, default 50)"
- Changed
get_transcript4 fields changed- added
Input schema / properties / fromSec / descriptionAdded value: +"Start of the range, seconds from the start of the video" - added
Input schema / properties / id / descriptionAdded value: +"Project id (from list_projects, search_clips or create_project)" - added
Input schema / properties / maxChars / descriptionAdded value: +"Cut the output at this many characters (1000-200000, default 60000)" - added
Input schema / properties / toSec / descriptionAdded value: +"End of the range, seconds"
- Changed
list_projects3 fields changed- added
Input schema / properties / cursor / descriptionAdded value: +"nextCursor from the previous page; omit for the first page" - added
Input schema / properties / deletedAdded value: +{ + "description": "true = only deleted projects that restore_project can still bring back", + "type": "boolean" +} - added
Input schema / properties / limit / descriptionAdded value: +"Projects per page (1-100, default 24)"
- Changed
reanalyze_project29 fields changed- added
Input schema / properties / id / descriptionAdded value: +"Project id (from list_projects, search_clips or create_project)" - added
Input schema / properties / settings / properties / captionPosition / descriptionAdded value: +"Deprecated: use captionY" - added
Input schema / properties / settings / properties / captionSize / descriptionAdded value: +"Caption size multiplier (0.5-2, default 1)" - added
Input schema / properties / settings / properties / captionX / descriptionAdded value: +"Caption centre, horizontal, as a fraction of the 9:16 frame (0-1)" - added
Input schema / properties / settings / properties / captionY / descriptionAdded value: +"Caption centre, vertical (default 0.72), as a fraction of the 9:16 frame (0-1)" - added
Input schema / properties / settings / properties / captions / descriptionAdded value: +"Caption look: karaoke (active word highlighted), box, plain, or none (no captions)" - added
Input schema / properties / settings / properties / emphasis / descriptionAdded value: +"Colour the clip's key words (default true)" - added
Input schema / properties / settings / properties / emphasisColor / descriptionAdded value: +"Colour of emphasised words, #RRGGBB (default #39FF14)" - added
Input schema / properties / settings / properties / focus / descriptionAdded value: +"Only pick clips about this topic (max 300 chars)" - added
Input schema / properties / settings / properties / highlightColor / descriptionAdded value: +"Karaoke active-word colour, #RRGGBB (default #FFD700)" - added
Input schema / properties / settings / properties / hookSeconds / descriptionAdded value: +"How long the hook shows, seconds (0-15, default 3.5)" - added
Input schema / properties / settings / properties / hookX / descriptionAdded value: +"Hook centre, horizontal, as a fraction of the 9:16 frame (0-1)" - added
Input schema / properties / settings / properties / hookY / descriptionAdded value: +"Hook centre, vertical (default 0.16), as a fraction of the 9:16 frame (0-1)" - added
Input schema / properties / settings / properties / instructions / descriptionAdded value: +"Free-text guidance for picking and titling clips (max 2000 chars)" - added
Input schema / properties / settings / properties / introAssetId / descriptionAdded value: +"Library asset id of the intro (list_bumpers); null = none" - added
Input schema / properties / settings / properties / introSec / descriptionAdded value: +"Seconds an image intro/outro shows (1-10); videos keep their own length" - added
Input schema / properties / settings / properties / language / descriptionAdded value: +"Spoken language code (e.g. en); unset = detected" - added
Input schema / properties / settings / properties / maxClipSeconds / descriptionAdded value: +"Longest clip, seconds (10-300, default 60; must be above minClipSeconds)" - added
Input schema / properties / settings / properties / maxClips / descriptionAdded value: +"Most clips to pick (1-50); unset = every moment that stands on its own" - added
Input schema / properties / settings / properties / minClipSeconds / descriptionAdded value: +"Shortest clip, seconds (5-180, default 20)" - added
Input schema / properties / settings / properties / outroAssetId / descriptionAdded value: +"Library asset id of the outro (list_bumpers); null = none" - added
Input schema / properties / settings / properties / outroSec / descriptionAdded value: +"Seconds an image intro/outro shows (1-10); videos keep their own length" - added
Input schema / properties / settings / properties / pauses / descriptionAdded value: +"Long pauses inside clips: natural (cut to 0.6 s, default), tight (0.35 s) or off" - added
Input schema / properties / settings / properties / reframe / descriptionAdded value: +"Framing: auto (detect per section), face (follow the speaker), split (two speakers stacked), stack (full frame over a face crop), fit (whole frame on blur), center (static crop), none (original aspect)" - added
Input schema / properties / settings / properties / showHook / descriptionAdded value: +"Show the hook text at the start of the clip (default true)" - added
Input schema / properties / settings / properties / sourceText / descriptionAdded value: +"Text already in the video: hide (blur captions/logos except in slide decks, default), always (blur even then), keep" - added
Input schema / properties / settings / properties / uppercase / descriptionAdded value: +"Captions in capitals" - added
Input schema / properties / settings / properties / vocabulary / descriptionAdded value: +"Names, brands and jargon to spell correctly, comma separated (max 1000 chars)" - added
Input schema / properties / settings / properties / wordsPerLine / descriptionAdded value: +"Max caption words on screen at once (1-8, default 4)"
- Changed
remove_bumper1 field changed- added
Input schema / properties / assetId / descriptionAdded value: +"Library asset id (from list_bumpers)"
- Added
rename_bumper - Changed
rerender_clip1 field changed- added
Input schema / properties / id / descriptionAdded value: +"Clip id, not a project id (from get_project or search_clips)"
- Changed
rerender_clips2 fields changed- added
Input schema / properties / clipIds / descriptionAdded value: +"Clip ids of that project (get_project), 1-200" - added
Input schema / properties / projectId / descriptionAdded value: +"Project id (from list_projects, search_clips or create_project)"
- Changed
restore_bumper1 field changed- added
Input schema / properties / assetId / descriptionAdded value: +"Library asset id (from list_bumpers → removed)"
- Added
restore_clip - Added
restore_project - Changed
retry_project1 field changed- added
Input schema / properties / id / descriptionAdded value: +"Project id (from list_projects, search_clips or create_project)"
- Changed
search_clips2 fields changed- added
Input schema / properties / limit / descriptionAdded value: +"Most clips to return (1-50, default 15)" - added
Input schema / properties / q / descriptionAdded value: +"Words to find, e.g. \"budget tips\""
- Changed
set_clip_bumpers5 fields changed- added
Input schema / properties / clipIds / descriptionAdded value: +"Clip ids of that project (get_project), 1-200 per call" - added
Input schema / properties / introSec / descriptionAdded value: +"Seconds an intro image shows on these clips (1-10)" - added
Input schema / properties / outroSec / descriptionAdded value: +"Seconds an outro image shows on these clips (1-10)" - added
Input schema / properties / projectId / descriptionAdded value: +"Project the clips belong to (list_projects)" - changed
Input schema / properties / rerender / descriptionPrevious value: -"true = re-render only these clips now"New value: +"true = re-render only these clips now; false = apply on their next render"
- Changed
set_default_bumper2 fields changed- added
Input schema / properties / assetId / descriptionAdded value: +"Library asset id (list_bumpers), or null for no default" - added
Input schema / properties / slot / descriptionAdded value: +"Which default to set"
- Changed
set_project_bumpers3 fields changed- changed
Input schema / properties / introSec / descriptionPrevious value: -"Seconds to show an intro image (1-10); videos keep their own length"New value: +"Seconds an intro image shows in this project (1-10); videos keep their own length. Saved with the project" - added
Input schema / properties / outroSec / descriptionAdded value: +"Seconds an outro image shows in this project (1-10). Saved with the project" - added
Input schema / properties / projectId / descriptionAdded value: +"Project id (list_projects or create_project)"
- Changed
update_clip14 fields changed- added
Input schema / properties / caption / descriptionAdded value: +"Post caption, not burned in (max 300 chars)" - changed
Input schema / properties / emphasis / descriptionPrevious value: -"Words the captions emphasise"New value: +"Words the captions colour (max 30); replaces the list" - added
Input schema / properties / endSec / descriptionAdded value: +"New end, seconds from the start of the source; clip must stay ≥3 s" - added
Input schema / properties / hashtags / descriptionAdded value: +"Hashtags without # (max 20); replaces the list" - added
Input schema / properties / hook / descriptionAdded value: +"On-screen opening line (max 80 chars)" - added
Input schema / properties / id / descriptionAdded value: +"Clip id (from get_project or search_clips)" - changed
Input schema / properties / layoutOverride / anyOfPrevious value: -[ - { - "enum": [ - "auto", - "face", - "split", - "stack", - "fit", - "center", - "none" - ], - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "description": "Framing: auto (detect per section), face (follow the speaker), split (two speakers stacked), stack (full frame over a face crop), fit (whole frame on blur), center (static crop), none (original aspect)", + "enum": [ + "auto", + "face", + "split", + "stack", + "fit", + "center", + "none" + ], + "type": "string" + }, + { + "type": "null" + } +] - changed
Input schema / properties / layoutSections / anyOfPrevious value: -[ - { - "items": { - "properties": { - "end": { - "minimum": 0, - "type": "number" - }, - "mode": { - "enum": [ - "auto", - "face", - "split", - "stack", - "fit", - "center" - ], - "type": "string" - }, - "offsetX": { - "maximum": 0.5, - "minimum": -0.5, - "type": "number" - }, - "start": { - "minimum": 0, - "type": "number" - } - }, - "required": [ - "start", - "end", - "mode" - ], - "type": "object" - }, - "maxItems": 50, - "type": "array" - }, - { - "type": "null" - } -]New value: +[ + { + "items": { + "properties": { + "end": { + "description": "Section end, seconds from the start of the source video", + "minimum": 0, + "type": "number" + }, + "mode": { + "description": "Framing for this section (same modes as the project's reframe, without none)", + "enum": [ + "auto", + "face", + "split", + "stack", + "fit", + "center" + ], + "type": "string" + }, + "offsetX": { + "description": "Shift the crop sideways by this fraction of the source width (-0.5 to 0.5)", + "maximum": 0.5, + "minimum": -0.5, + "type": "number" + }, + "start": { + "description": "Section start, seconds from the start of the source video", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "start", + "end", + "mode" + ], + "type": "object" + }, + "maxItems": 50, + "type": "array" + }, + { + "type": "null" + } +] - added
Input schema / properties / layoutSections / descriptionAdded value: +"Framing per time range (max 50), source seconds; replaces all sections; null or [] = automatic" - added
Input schema / properties / rerender / descriptionAdded value: +"Re-render when a burned-in field changed (default true); false = keep the old video until rerender_clip" - added
Input schema / properties / startSec / descriptionAdded value: +"New start, seconds from the start of the source video" - changed
Input schema / properties / style / anyOfPrevious value: -[ - { - "properties": { - "captionSize": { - "default": 1, - "maximum": 2, - "minimum": 0.5, - "type": "number" - }, - "captionX": { - "default": 0.5, - "maximum": 1, - "minimum": 0, - "type": "number" - }, - "captionY": { - "default": 0.72, - "maximum": 1, - "minimum": 0, - "type": "number" - }, - "captions": { - "default": "karaoke", - "enum": [ - "karaoke", - "box", - "plain", - "none" - ], - "type": "string" - }, - "emphasis": { - "default": true, - "type": "boolean" - }, - "emphasisColor": { - "default": "#39FF14", - "pattern": "^#[0-9a-fA-F]{6}$", - "type": "string" - }, - "highlightColor": { - "default": "#FFD700", - "pattern": "^#[0-9a-fA-F]{6}$", - "type": "string" - }, - "hookSeconds": { - "default": 3.5, - "maximum": 15, - "minimum": 0, - "type": "number" - }, - "hookX": { - "default": 0.5, - "maximum": 1, - "minimum": 0, - "type": "number" - }, - "hookY": { - "default": 0.16, - "maximum": 1, - "minimum": 0, - "type": "number" - }, - "showHook": { - "default": true, - "type": "boolean" - }, - "uppercase": { - "default": false, - "type": "boolean" - }, - "wordsPerLine": { - "default": 4, - "maximum": 8, - "minimum": 1, - "type": "integer" - } - }, - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "properties": { + "captionSize": { + "description": "Caption size multiplier (0.5-2, default 1)", + "maximum": 2, + "minimum": 0.5, + "type": "number" + }, + "captionX": { + "description": "Caption centre, horizontal, as a fraction of the 9:16 frame (0-1)", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "captionY": { + "description": "Caption centre, vertical (default 0.72), as a fraction of the 9:16 frame (0-1)", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "captions": { + "description": "Caption look: karaoke (active word highlighted), box, plain, or none (no captions)", + "enum": [ + "karaoke", + "box", + "plain", + "none" + ], + "type": "string" + }, + "emphasis": { + "description": "Colour the clip's key words (default true)", + "type": "boolean" + }, + "emphasisColor": { + "description": "Colour of emphasised words, #RRGGBB (default #39FF14)", + "pattern": "^#[0-9a-fA-F]{6}$", + "type": "string" + }, + "highlightColor": { + "description": "Karaoke active-word colour, #RRGGBB (default #FFD700)", + "pattern": "^#[0-9a-fA-F]{6}$", + "type": "string" + }, + "hookSeconds": { + "description": "How long the hook shows, seconds (0-15, default 3.5)", + "maximum": 15, + "minimum": 0, + "type": "number" + }, + "hookX": { + "description": "Hook centre, horizontal, as a fraction of the 9:16 frame (0-1)", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "hookY": { + "description": "Hook centre, vertical (default 0.16), as a fraction of the 9:16 frame (0-1)", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "showHook": { + "description": "Show the hook text at the start of the clip (default true)", + "type": "boolean" + }, + "uppercase": { + "description": "Captions in capitals", + "type": "boolean" + }, + "wordsPerLine": { + "description": "Max caption words on screen at once (1-8, default 4)", + "maximum": 8, + "minimum": 1, + "type": "integer" + } + }, + "type": "object" + }, + { + "type": "null" + } +] - added
Input schema / properties / style / descriptionAdded value: +"Caption/hook style for this clip on top of the project's; replaces the clip's override; null = follow the project" - added
Input schema / properties / title / descriptionAdded value: +"Clip title (1-120 chars)"
- Added
update_project - Changed
wait_for_project2 fields changed- added
Input schema / properties / id / descriptionAdded value: +"Project id (from create_project or list_projects)" - added
Input schema / properties / timeoutSeconds / descriptionAdded value: +"Longest to wait, seconds (1-120, default 60)"
24 tool updates
v0.1.0- First observed
add_bumper - First observed
bumper_usage - First observed
create_clip - First observed
create_project - First observed
delete_project - First observed
export_project - First observed
get_clip - First observed
get_project - First observed
get_project_events - First observed
get_transcript - First observed
list_bumpers - First observed
list_projects - First observed
reanalyze_project - First observed
remove_bumper - First observed
rerender_clip - First observed
rerender_clips - First observed
restore_bumper - First observed
retry_project - First observed
search_clips - First observed
set_clip_bumpers - First observed
set_default_bumper - First observed
set_project_bumpers - First observed
update_clip - First observed
wait_for_project
TDQS
Scored across 29 tools
Most tools target distinct resources and actions, and descriptions actively disambiguate near-neighbors (rerender_clip vs rerender_clips, get_project vs wait_for_project, retry_project vs reanalyze_project). A few pairs are close — set_project_bumpers vs set_default_bumper, restore_bumper vs add_bumper restoration behavior — but the descriptions explicitly cross-reference the alternatives, preventing most misselection.
Consistent verb_noun pattern throughout: create/list/get/update/delete/restore/rerender/_project/_clip/_bumpers. Plural forms (rerender_clips, set_project_bumpers) correctly denote batch operations. No camelCase mixing or vague standalone verbs.
29 tools is at the heavy end for a clipping service, spanning projects, clips, library assets, and pipeline control. The bumpers library alone accounts for eight tools (usage, list, add, rename, remove, restore, set_default, set_project, set_clip), which inflates the surface for what is essentially intro/outro management. Borderline for the stated scope.
Full lifecycle coverage: projects and clips both have create/read/update/delete/restore, plus re-render, reanalyze, retry, wait, transcript access, search, export, and a complete bumpers sub-lifecycle. No obvious dead ends; restore paths and deleted-item discovery are explicitly provided.
Maintenance
Related MCP Connectors
Turn long videos into short, subtitled, auto-reframed clips from Claude or ChatGPT.
Turn long videos into AI-curated short clips: caption, reframe, thumbnail, schedule, and publish.
Turns long videos into captioned vertical clips, cut at the moments that stand on their own.
AI video editing + publishing: turn clips into vertical shorts, post to TikTok/Instagram/YouTube.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceTurns long-form videos into short-form clips (TikTok/Reels) by reasoning over word-timestamped transcripts, with silence-aware rendering, STT-based validation, and optional reframing/captions.-
- AlicenseAqualityDmaintenanceAI-powered video clipping server that analyzes subtitles and audio to detect highlight moments, then generates platform-adapted short clips from long videos.5Apache 2.0
- AlicenseAqualityAmaintenanceOpenShorts turns long videos into vertical clips readys for Social Media posting86,727MIT
- FlicenseNot gradedqualityBmaintenanceEnables autonomous shortform video editing by tracking speakers and dynamically reframing 16:9 footage into 9:16, with smart bounding box coordination for CapCut and MCP-compatible agent workflows.8-